qhull 0.1.0.1 → 0.1.0.3
raw patch · 40 files changed
+23960/−23941 lines, 40 files
Files
- C/convexhull.c +0/−714
- C/delaunay.c +0/−577
- C/geom2_r.c +0/−2096
- C/geom_r.c +0/−1234
- C/global_r.c +0/−2100
- C/halfspaces.c +0/−68
- C/io_r.c +0/−4062
- C/libqhull_r.c +0/−1403
- C/mem_r.c +0/−562
- C/merge_r.c +0/−3627
- C/poly2_r.c +0/−3222
- C/poly_r.c +0/−1205
- C/qset_r.c +0/−1340
- C/random_r.c +0/−247
- C/stat_r.c +0/−682
- C/user_r.c +0/−527
- C/usermem_r.c +0/−94
- C/userprintf_r.c +0/−65
- C/utils.c +0/−91
- Cdir/convexhull.c +714/−0
- Cdir/delaunay.c +577/−0
- Cdir/geom2_r.c +2096/−0
- Cdir/geom_r.c +1234/−0
- Cdir/global_r.c +2100/−0
- Cdir/halfspaces.c +68/−0
- Cdir/io_r.c +4062/−0
- Cdir/libqhull_r.c +1403/−0
- Cdir/mem_r.c +562/−0
- Cdir/merge_r.c +3627/−0
- Cdir/poly2_r.c +3222/−0
- Cdir/poly_r.c +1205/−0
- Cdir/qset_r.c +1340/−0
- Cdir/random_r.c +247/−0
- Cdir/stat_r.c +682/−0
- Cdir/user_r.c +527/−0
- Cdir/usermem_r.c +94/−0
- Cdir/userprintf_r.c +65/−0
- Cdir/utils.c +91/−0
- ChangeLog.md +15/−0
- qhull.cabal +29/−25
− C/convexhull.c
@@ -1,714 +0,0 @@-#define qh_QHimport-#include "qhull_ra.h"-#include "convexhull.h"-#include "utils.h"--// to use the qsort function - sort vertices according to their ids-int cmpvertices (const void * a, const void * b) {- return ( (*((VertexT*)a)).id - (*((VertexT*)b)).id );-}-// - sort full vertices-int cmpfullvertices (const void * a, const void * b) {- return ( (*((FullVertexT*)a)).id - (*((FullVertexT*)b)).id );-}-// - sort edges-int cmpedges (const void * a, const void * b) {- if((*(unsigned**)a)[0] > (*(unsigned**)b)[0]){- return 1;- }else if((*(unsigned**)a)[0] == (*(unsigned**)b)[0]){- return (*(unsigned**)a)[1] - (*(unsigned**)b)[1];- }else{- return -1;- }-}--/* test equality of two _sorted_ arrays */-unsigned equalarraysu(unsigned* array1, unsigned* array2, unsigned length){- unsigned i;- for(i=0; i < length; i++){- if(array1[i] != array2[i]){- break;- }- }- return i == length;-}--/* return ids of a vector of VertexT */-unsigned* map_vertexid(VertexT* vertices, unsigned nvertices){- unsigned* ids = malloc(nvertices * sizeof(unsigned));- for(unsigned v=0; v < nvertices; v++){- ids[v] = vertices[v].id;- }- return ids;-}--/* return ids of a vector of RidgeT */-unsigned* map_ridgeid(RidgeT* ridges, unsigned nridges){- unsigned* ids = malloc(nridges * sizeof(unsigned));- for(unsigned r=0; r < nridges; r++){- ids[r] = ridges[r].id;- }- return ids;-}--// void deepCopyRidge(RidgeT* src, RidgeT* dest) { et dim !-// dest = malloc(sizeof(RidgeT));-// *dest = *src;-// dest->vertices = malloc(src->nvertices * sizeof(VertexT));-// for(unsigned v=0; v<src->nvertices; v++){-// dest->vertices[v].id = src.vertices[v].id;-// memcpy(dest->vertices[v].point, dest->vertices[v].point, dim * sizeof(double));-// }-// }--/* deep copy of a ridge */-RidgeT copyRidge(RidgeT ridge, unsigned dim){- RidgeT out;- out.ridgeOf1 = ridge.ridgeOf1;- out.ridgeOf2 = ridge.ridgeOf2;- out.nvertices = ridge.nvertices;- out.nedges = ridge.nedges;- out.vertices = malloc(out.nvertices * sizeof(VertexT));- for(unsigned v=0; v < out.nvertices; v++){- out.vertices[v].id = ridge.vertices[v].id;- out.vertices[v].point = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- out.vertices[v].point[i] = ridge.vertices[v].point[i];- }- }- // out.edges = malloc(out.nedges * sizeof(unsigned*));- // for(unsigned e=0; e < out.nedges; e++){- // out.edges[e] = malloc(2 * sizeof(unsigned));- // out.edges[e][0] = ridge.edges[e][0];- // out.edges[e][1] = ridge.edges[e][1];- // }- return out;-}--/* append to a vector of VertexT */-void appendv(VertexT x, VertexT** array, unsigned length, unsigned* flag){- *flag = 1;- for(unsigned i=0; i < length; i++){- if(x.id == (*(*array + i)).id){- *flag = 0;- break;- }- }- if(*flag == 1){- *array = realloc(*array, (length+1) * sizeof(VertexT));- if(*array == NULL){- printf("realloc failure - exiting\n");- exit(1);- }- *(*array + length) = x;- }-}--/* union of two vectors of VertexT */-void unionv(VertexT** vs1, VertexT* vs2, unsigned l1, unsigned l2, unsigned* l){- *l = l1;- for(unsigned v=0; v < l2; v++){- unsigned pushed;- appendv(vs2[v], vs1, *l, &pushed);- if(pushed){- (*l)++;- }- }- /* sort vertices according to their ids */- qsort(*vs1, *l, sizeof(VertexT), cmpvertices);-}--/* merge ridges with same ridgeOf's */-RidgeT* mergeRidges(RidgeT* ridges, unsigned nridges, unsigned* newlength){- // http://www.c4learn.com/c-programs/to-delete-duplicate-elements-in-array.html- *newlength = nridges;- unsigned i,j,k;- for(i = 0; i < nridges; i++){- for(j = i+1; j < nridges; ){- if(ridges[i].ridgeOf1 == ridges[j].ridgeOf1 &&- ridges[i].ridgeOf2 == ridges[j].ridgeOf2)- {- unsigned l;- unionv(&(ridges[i].vertices), ridges[j].vertices,- ridges[i].nvertices, ridges[j].nvertices, &l);- ridges[i].nvertices = l;- (*newlength)--;- for(k = j; k+1 < nridges; k++){- ridges[k] = ridges[k+1];- }- nridges--;- }else{- j++;- }- }- }- RidgeT* out = malloc(*newlength * sizeof(RidgeT));- for(unsigned r=0; r < *newlength; r++){- out[r] = ridges[r];- }- return out;-}--/* all ridges from the ridges stored in the faces */-RidgeT* allRidges(FaceT *faces, unsigned nfaces, unsigned dim, unsigned* length){- RidgeT* out = malloc(faces[0].nridges * sizeof(RidgeT));- for(unsigned i=0; i < faces[0].nridges; i++){- out[i] = copyRidge(faces[0].ridges[i], dim);- out[i].id = i;- out[i].nedges = 0;- // RidgeT out[i];- // deepCopyRidge(&(faces[0].ridges[i]), &(out[i]));- }- *length = faces[0].nridges;- unsigned n = faces[0].nridges;- for(unsigned f=1; f < nfaces; f++){- for(unsigned j=0; j < faces[f].nridges; j++){- unsigned count = 0;- for(unsigned i=0; i < n; i++){- unsigned flag = 0;- for(unsigned v=0; v < faces[f].ridges[j].nvertices; v++){- if(faces[f].ridges[j].vertices[v].id != out[i].vertices[v].id){- flag = 1;- break;- }- }- if(flag){- count++;- }else{- break;- }- }- if(count == n){- out = realloc(out, (*length+1) * sizeof(RidgeT));- if(out == NULL){- printf("realloc failure - exiting\n");- exit(1);- }- out[*length] = copyRidge(faces[f].ridges[j], dim);- out[*length].id = *length;- out[*length].nedges = 0;- // RidgeT out[*length];- // deepCopyRidge(&(faces[f].ridges[j]), &(out[*length]));- (*length)++;- }- }- n = *length;- }- return out;-}--/* assign ids to the ridges stored in the faces */-void assignRidgesIds(FaceT** faces, unsigned nfaces, RidgeT* allridges,- unsigned nallridges)-{- for(unsigned f=0; f < nfaces; f++){- for(unsigned fr=0; fr < (*(*faces + f)).nridges; fr++){- for(unsigned r=0; r < nallridges; r++){- if((allridges[r].nvertices == (*(*faces + f)).ridges[fr].nvertices) &&- equalarraysu(map_vertexid(allridges[r].vertices,- allridges[r].nvertices),- map_vertexid((*(*faces + f)).ridges[fr].vertices,- allridges[r].nvertices),- allridges[r].nvertices))- {- (*(*faces + f)).ridges[fr].id = allridges[r].id;- break;- }- }- }- }-}--// double* ridgeCentroid(RidgeT ridge, unsigned dim){-// double* out = malloc(dim * sizeof(double));-// for(unsigned i=0; i<dim; i++){-// out[i] = 0;-// for(unsigned v=0; v<dim-1; v++){-// out[i] += ridge.vertices[v].point[i];-// }-// out[i] /= dim - 1;-// }-// return out;-// }--/* the threshold distance to detect neighbor vertices */-double ridgeMaxDistance(RidgeT ridge, unsigned v, unsigned dim){- double dists[ridge.nvertices-1];- unsigned count = 0;- for(unsigned w=0; w < ridge.nvertices; w++){- if(w != v){- dists[count] = squaredDistance(ridge.vertices[v].point,- ridge.vertices[w].point, dim);- count++;- }- }- qsort(dists, ridge.nvertices-1, sizeof(double), cmpfuncdbl);- return dists[1];-}--/* neighbor vertices of a vertex from all ridges, for dim>2 */-unsigned* neighVertices(unsigned id, RidgeT* allridges, unsigned nridges,- unsigned dim, unsigned triangulate, unsigned* lengthout)-{- unsigned* neighs = malloc(0);- *lengthout = 0;- for(unsigned e=0; e < nridges; e++){- for(unsigned v=0; v < allridges[e].nvertices; v++){- if(id == allridges[e].vertices[v].id){- for(unsigned w=0; w < allridges[e].nvertices; w++){- if(w != v && (triangulate || dim == 3 || // dim3 pas besoin de tester la distance: il n'y a que deux vertices connectés- squaredDistance(allridges[e].vertices[w].point,- allridges[e].vertices[v].point, dim) <=- ridgeMaxDistance(allridges[e], v, dim)))- {- unsigned pushed;- appendu(allridges[e].vertices[w].id, &neighs, *lengthout, &pushed);- if(pushed){- (*lengthout)++;- }- }- }- break;- }- }- }- return neighs;-}--/* neighbor ridges of a vertex */-unsigned* neighRidges(unsigned id, RidgeT* allridges, unsigned nridges,- unsigned* length)-{- unsigned* neighs = malloc(0);- *length = 0;- for(unsigned e=0; e < nridges; e++){- unsigned flag = 0;- for(unsigned v=0; v < allridges[e].nvertices; v++){- if(id == allridges[e].vertices[v].id){- flag = 1;- break;- }- }- if(flag){- neighs = realloc(neighs, (*length+1)*sizeof(unsigned));- if(neighs == NULL){- printf("realloc failure - exiting\n");- exit(1);- }- neighs[*length] = e;- (*length)++;- }- }- return neighs;-}--/* whether distinct x1 and x2 belong to array of distinct values */-unsigned areElementsOf(unsigned x1, unsigned x2, unsigned* array,- unsigned length)-{- unsigned count = 0;- for(unsigned i=0; (i < length) && (count < 2); i++){- if(x1 == array[i] || x2 == array[i]){- count++;- }- }- return count==2;-}--/* make face/ridge edges from all edges */-unsigned** makeEdges(SetOfVerticesT face, unsigned** alledges,- unsigned nalledges, unsigned* lengthout)-{- *lengthout = 0;- unsigned* faceverticesids = map_vertexid(face.vertices, face.nvertices);- unsigned flags[nalledges];- for(unsigned e=0; e < nalledges; e++){- if(areElementsOf(alledges[e][0], alledges[e][1], faceverticesids,- face.nvertices))- {- flags[e] = 1;- (*lengthout)++;- }else{- flags[e] = 0;- }- }- unsigned** out = malloc(*lengthout * sizeof(unsigned*));- unsigned count = 0;- for(unsigned e=0; e < nalledges; e++){- if(flags[e] == 1){- out[count] = alledges[e];- count++;- }- }- return out;-}--/* all edges from all vertices */-unsigned** allEdges(FullVertexT* vertices, unsigned nvertices,- unsigned outlength)-{- unsigned** out = malloc(outlength * sizeof(unsigned*));- for(unsigned i=0; i < vertices[0].nneighsvertices; i++){- out[i] = malloc(2 * sizeof(unsigned));- out[i][0] = vertices[0].id;- out[i][1] = vertices[0].neighvertices[i];- qsortu(out[i], 2);- }- unsigned n = vertices[0].nneighsvertices;- for(unsigned v=1; v < nvertices; v++){- unsigned ids[2];- for(unsigned i=0; i < vertices[v].nneighsvertices; i++){- ids[0] = vertices[v].id;- ids[1] = vertices[v].neighvertices[i];- qsortu(ids, 2);- unsigned j;- for(j=0; j < n; j++){- if(ids[0] == out[j][0] && ids[1] == out[j][1]){- break;- }- }- if(j == n){- out[n] = malloc(2 * sizeof(unsigned));- out[n][0] = ids[0]; out[n][1] = ids[1];- n++;- }- if(n == outlength){- break;- }- }- if(n == outlength){- break;- }- }- return out;-}--// ATTENTION avec Qt le center dans facet->center est le centre de l'union des triangles,-// (ainsi que normal et offset mais ça ok)--// un ridge est simplicial ; pour l'hypercube il y a 2 ridges entre 2 faces,-// ils forment le carré à l'intersection--/* main function */-ConvexHullT* convexHull(- double* points,- unsigned dim,- unsigned n,- unsigned triangulate,- unsigned print,- char* summaryFile,- unsigned* exitcode-)-{- char opts[250]; /* option flags for qhull, see qh_opt.htm */- sprintf(opts, "qhull s FF %s", triangulate ? "Qt" : "");- qhT qh_qh; /* Qhull's data structure */- qhT *qh= &qh_qh;- QHULL_LIB_CHECK- qh_meminit(qh, stderr);- boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */- FILE *errfile = NULL;- FILE* outfile;- if(print){- outfile = stdout;- }else{- outfile = NULL;- }- qh_zero(qh, errfile);- exitcode[0] = qh_new_qhull(qh, dim, n, points, ismalloc, opts, outfile,- errfile);- //fclose(tmpstdout);- printf("exitcode: %u\n", exitcode[0]);-- ConvexHullT* out = malloc(sizeof(ConvexHullT));-- if (!exitcode[0]) { /* 0 if no error from qhull */-- /* print summary to file */- if(*summaryFile != 0){- FILE* sfile = fopen(summaryFile, "w");- qh_printsummary(qh, sfile);- fclose(sfile);- }-- //qh_getarea(qh, qh->facet_list); // no triowner if I do that; do qh_facetarea, not facet->f.area-- unsigned nfaces = qh->num_facets;- FaceT* faces = malloc(nfaces * sizeof(FaceT));- {- facetT *facet; unsigned i_facet = 0;- FORALLfacets{- facet->id = i_facet; /* for neighbors and ridgeOf */- faces[i_facet].area = qh_facetarea(qh, facet);- double* center = qh_getcenter(qh, facet->vertices);- faces[i_facet].center = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- faces[i_facet].center[i] = center[i];- }- double* normal = facet->normal;- faces[i_facet].normal = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- faces[i_facet].normal[i] = normal[i];- }- faces[i_facet].offset = facet->offset;- faces[i_facet].nvertices = (unsigned) qh_setsize(qh, facet->vertices);- { /* face vertices */- faces[i_facet].vertices =- (VertexT*) malloc(faces[i_facet].nvertices * sizeof(VertexT));- vertexT *vertex, **vertexp;- unsigned i_vertex = 0;- FOREACHvertex_(facet->vertices){- faces[i_facet].vertices[i_vertex].id =- (unsigned) qh_pointid(qh, vertex->point);- faces[i_facet].vertices[i_vertex].point =- malloc(dim * sizeof(double));- faces[i_facet].vertices[i_vertex].point =- getpoint(points, dim, faces[i_facet].vertices[i_vertex].id);- // plante dans Haskell: (faces[i_facet].vertices)[i_vertex].point = vertex->point;- i_vertex++;- }- qsort(faces[i_facet].vertices, faces[i_facet].nvertices,- sizeof(VertexT), cmpvertices);- }- if(dim == 3){ /* orientation of the normals */- pointT* onepoint = ((vertexT*)facet->vertices->e[0].p)->point;- double thepoint[dim]; /* onepoint+normal */- for(unsigned i=0; i < dim; i++){- thepoint[i] = onepoint[i] + faces[i_facet].normal[i];- }- /* we check that these two points are on the same side of the ridge */- double h1 = dotproduct(qh->interior_point,- faces[i_facet].normal, dim) +- faces[i_facet].offset;- double h2 = dotproduct(thepoint, faces[i_facet].normal, dim) +- faces[i_facet].offset;- if(h1*h2 > 0){- for(unsigned i=0; i < dim; i++){- faces[i_facet].normal[i] *= -1;- }- printf("change sign\n"); // seems to never occur- }else{- printf("not change sign\n");- }- }- /**/- i_facet++;- }- }-- { /* neighbor faces, faces families, and ridges */- facetT *facet;- unsigned i_facet = 0;- FORALLfacets{- {- faces[i_facet].neighborsize = qh_setsize(qh, facet->neighbors);- faces[i_facet].neighbors =- malloc(faces[i_facet].neighborsize * sizeof(unsigned));- unsigned i_neighbor = 0;- facetT *neighbor, **neighborp;- FOREACHneighbor_(facet){- faces[i_facet].neighbors[i_neighbor] = (unsigned) neighbor->id;- i_neighbor++;- }- qsortu(faces[i_facet].neighbors, faces[i_facet].neighborsize);- }- { /* face family, when option Qt */- if(facet->tricoplanar){- faces[i_facet].family = facet->f.triowner->id;- }else{- faces[i_facet].family = -1;- }- }- { /* face ridges */- qh_makeridges(qh, facet);- unsigned nridges = qh_setsize(qh, facet->ridges);- RidgeT* ridges = malloc(nridges * sizeof(RidgeT));- ridgeT *ridge, **ridgep;- unsigned i_ridge = 0;- FOREACHridge_(facet->ridges){- ridges[i_ridge].nedges = 0;- unsigned ridgeSize = qh_setsize(qh, ridge->vertices); // dim-1-// printf("ridge size: %u\n", ridgeSize);- ridges[i_ridge].nvertices = ridgeSize;- unsigned ids[ridgeSize];- for(unsigned v=0; v < ridgeSize; v++){- ids[v] =- qh_pointid(qh, ((vertexT*)ridge->vertices->e[v].p)->point);- }- qsortu(ids, ridgeSize);- ridges[i_ridge].vertices = malloc(ridgeSize * sizeof(VertexT));- for(unsigned v=0; v < ridgeSize; v++){- ridges[i_ridge].vertices[v].id = ids[v];- ridges[i_ridge].vertices[v].point = getpoint(points, dim, ids[v]);- }- unsigned ridgeofs[2];- ridgeofs[0] = ridge->bottom->id;- ridgeofs[1] = ridge->top->id;- qsortu(ridgeofs, 2);- ridges[i_ridge].ridgeOf1 = ridgeofs[0];- ridges[i_ridge].ridgeOf2 = ridgeofs[1];- /**/- i_ridge++;- }- /* merge triangulated ridges */- if(dim > 3 && !triangulate){- unsigned l;- faces[i_facet].ridges = mergeRidges(ridges, nridges, &l);- faces[i_facet].nridges = l;- }else{ /* dim 2 or 3, or triangulate option */- faces[i_facet].ridges = ridges;- faces[i_facet].nridges = nridges;- }- }- /**/- i_facet++;- }- }-- /* make unique ridges */- unsigned n_allridges;- RidgeT* allridges = allRidges(faces, nfaces, dim, &n_allridges);-// printf("nallridges: %u\n", n_allridges);-- /* assign ridges ids to the ridges stored in the faces */- assignRidgesIds(&faces, nfaces, allridges, n_allridges);-- /* all vertices */- unsigned nvertices = qh->num_vertices;- FullVertexT* vertices = malloc(nvertices * sizeof(FullVertexT));- {- qh_vertexneighbors(qh); /* make the neighbor facets of the vertices */- vertexT *vertex;- unsigned i_vertex=0;- FORALLvertices{- /* vertex id and coordinates */- vertices[i_vertex].id = (unsigned) qh_pointid(qh, vertex->point);- vertices[i_vertex].point = getpoint(points, dim, vertices[i_vertex].id);-- /* neighbor facets of the vertex */- vertices[i_vertex].nneighfacets = qh_setsize(qh, vertex->neighbors);- vertices[i_vertex].neighfacets =- malloc(vertices[i_vertex].nneighfacets * sizeof(unsigned));- facetT *neighbor, **neighborp;- unsigned i_neighbor = 0;- FOREACHneighbor_(vertex){- vertices[i_vertex].neighfacets[i_neighbor] = neighbor->id;- i_neighbor++;- }- qsortu(vertices[i_vertex].neighfacets, vertices[i_vertex].nneighfacets);-- /* neighbor vertices of the vertex */- if(dim > 2){- unsigned nneighsvertices;- vertices[i_vertex].neighvertices =- neighVertices(vertices[i_vertex].id, allridges, n_allridges,- dim, triangulate, &nneighsvertices);- vertices[i_vertex].nneighsvertices = nneighsvertices;- }else{ /* dim=2 */- vertices[i_vertex].nneighsvertices = 2;- vertices[i_vertex].neighvertices = malloc(2 * sizeof(unsigned));- unsigned count = 0;- for(unsigned f=0; f < nfaces; f++){- for(unsigned i=0; i < 2; i++){- if(faces[f].vertices[i].id == vertices[i_vertex].id){- vertices[i_vertex].neighvertices[count] =- faces[f].vertices[1-i].id;- count++;- break;- }- }- if(count == 2){- break;- }- }- }- qsortu(vertices[i_vertex].neighvertices,- vertices[i_vertex].nneighsvertices);-- /* neighbor ridges of the vertex */- if(dim > 2){- unsigned nneighridges;- vertices[i_vertex].neighridges =- neighRidges(vertices[i_vertex].id, allridges, n_allridges,- &nneighridges);- qsortu(vertices[i_vertex].neighridges, nneighridges);- vertices[i_vertex].nneighridges = nneighridges;- }else{ /* dim=2 */- vertices[i_vertex].nneighridges = 0; /* ridge = vertex singleton */- }- /**/- i_vertex++;- }- /* sort vertices according to their ids */- qsort(vertices, nvertices, sizeof(FullVertexT), cmpfullvertices);- }-- /* all edges */- unsigned nalledges = 0;- for(unsigned v=0; v < nvertices; v++){- nalledges += vertices[v].nneighsvertices;- }- nalledges /= 2;- unsigned** alledges = allEdges(vertices, nvertices, nalledges);- qsort(alledges, nalledges, sizeof(unsigned*), cmpedges);-- { /* faces edges and ridges ids */- facetT *facet; unsigned i_facet=0;- FORALLfacets{- /* facet ridges ids */- faces[i_facet].ridgesids =- map_ridgeid(faces[i_facet].ridges, faces[i_facet].nridges);- qsortu(faces[i_facet].ridgesids, faces[i_facet].nridges);- /* facet edges */- SetOfVerticesT facet_vset = {.vertices = faces[i_facet].vertices,- .nvertices = faces[i_facet].nvertices};- unsigned nfaceedges;- faces[i_facet].edges =- makeEdges(facet_vset, alledges, nalledges, &nfaceedges);- //qsort(faces[i_facet].edges, nfaceedges, sizeof(unsigned*), cmpedges); useless, I think- faces[i_facet].nedges = nfaceedges;- /**/- i_facet++;- }- }-- /* ridges edges */- if(dim > 3){- for(unsigned r=0; r < n_allridges; r++){- unsigned facetid = allridges[r].ridgeOf1;- SetOfVerticesT vset = {.vertices = allridges[r].vertices,- .nvertices = allridges[r].nvertices};- unsigned nedges;- allridges[r].edges =- makeEdges(vset, faces[facetid].edges, faces[facetid].nedges, &nedges);- allridges[r].nedges = nedges;- }- }-- /* output */- out->dim = dim;- out->vertices = vertices;- out->nvertices = nvertices;- out->faces = faces;- out->nfaces = nfaces;- out->ridges = allridges;- out->nridges = n_allridges;- out->edges = alledges;- out->nedges = nalledges;-- } // end if exitcode-- /* Do cleanup regardless of whether there is an error */- int curlong, totlong;- qh_freeqhull(qh, !qh_ALL); /* free long memory */- qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */-- printf("RETURN\n");- if(*exitcode){- free(out);- return 0;- }else{- return out;- }--}
− C/delaunay.c
@@ -1,577 +0,0 @@-#define qh_QHimport-#include "qhull_ra.h"-#include "delaunay.h"-#include "utils.h"-#include <math.h> /* to use NAN */--// void printfacet(qhT* qh, facetT* facet){-// vertexT *vertex, **vertexp;-// FOREACHvertex_(facet->vertices){-// printf("facetid: %d, pointid: %d ", facet->id, qh_pointid(qh, vertex->point));-// }-// }--unsigned facetOK_(facetT* facet, unsigned degenerate){- return !facet->upperdelaunay && (degenerate || !facet->degenerate);-} // && simplicial, && !facet->redundant - pas de simplicial avec Qt----TesselationT* tesselation(- double* sites,- unsigned dim,- unsigned n,- unsigned atinfinity,- unsigned degenerate,- double vthreshold,- unsigned* exitcode-)-{- char opts[50]; /* option flags for qhull, see qh_opt.htm */- sprintf(opts, "qhull d Qt Qbb%s%s",- atinfinity ? " Qz" : "", dim>3 ? " Qx" : "");- qhT qh_qh; /* Qhull's data structure */- qhT *qh= &qh_qh;- QHULL_LIB_CHECK- qh_meminit(qh, stderr);- boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */- FILE *errfile = NULL;- FILE* outfile = NULL;- qh_zero(qh, errfile);- *exitcode = qh_new_qhull(qh, dim, n, sites, ismalloc, opts, outfile, errfile);- //fclose(tmpstdout);- printf("exitcode: %u\n", *exitcode);-- TesselationT* out = malloc(sizeof(TesselationT)); /* output */-- if (!(*exitcode)) { /* 0 if no error from qhull */-- /* Count the number of facets we keep */- unsigned nfacets = 0; /* to store the number of facets */- {- facetT *facet; /* set by FORALLfacets */- FORALLfacets {- if(facetOK_(facet, degenerate)){- facet->id = nfacets;- nfacets++;- }else{- qh_removefacet(qh, facet);- }- }- }-- /* Initialize the tiles */- TileT* allfacets = malloc(nfacets * sizeof(TileT));-- { /* tiles families and volumes, and centers of tiles with >0 volume */- facetT* facet;- unsigned i_facet = 0;- FORALLfacets{- if(facet->tricoplanar){- allfacets[i_facet].family = facet->f.triowner->id;- // if(!facet->degenerate){- // if(i_facet == 392){- // printf("area: %f", qh_facetarea(qh, facet));- // }- // allfacets[i_facet].simplex.center =- // qh_facetcenter(qh, facet->vertices);- // }else{- // facetT *neighbor, **neighborp;- // FOREACHneighbor_(facet){- // if(facetOK_(neighbor,0) && neighbor->f.triowner->id == facet->f.triowner->id){- // allfacets[i_facet].simplex.center =- // qh_facetcenter(qh, neighbor->vertices);- // break;- // }- // }- // }- }else{- allfacets[i_facet].family = -1;- }- if(facet->degenerate){ // ?- allfacets[i_facet].simplex.volume = 0;- }else{- allfacets[i_facet].simplex.volume = fmax(0, qh_facetarea(qh, facet));- }- if(allfacets[i_facet].simplex.volume > vthreshold){- allfacets[i_facet].simplex.center = malloc(dim * sizeof(double));- double* center = qh_facetcenter(qh, facet->vertices);- for(unsigned i=0; i < dim; i++){- allfacets[i_facet].simplex.center[i] = center[i];- }- }- i_facet++;- }- }-- { /* facets ids, orientations, centers, sites ids, neighbors */- facetT* facet;- unsigned i_facet = 0; /* facet counter */- FORALLfacets {- allfacets[i_facet].id = facet->id;- allfacets[i_facet].orientation = facet->toporient ? 1 : -1;- /* center and circumradius */- if(allfacets[i_facet].simplex.volume <= vthreshold){- if(facet->tricoplanar){- unsigned ok = 0;- vertexT* apex = (vertexT*)facet->vertices->e[0].p;- facetT *neighbor, **neighborp;- FOREACHneighbor_(apex){- if(facetOK_(neighbor,degenerate) &&- allfacets[neighbor->id].family == allfacets[i_facet].family &&- allfacets[neighbor->id].simplex.volume > vthreshold)- {- allfacets[i_facet].simplex.center =- allfacets[neighbor->id].simplex.center;- ok = 1;- break;- }- }- if(!ok){ /* should not happen */- allfacets[i_facet].simplex.center = nanvector(dim);- }- }else{ /* should not happen */- allfacets[i_facet].simplex.center = nanvector(dim);- }- }-// printf("center facet %u: %f %f %f\n", i_facet, allfacets[i_facet].simplex.center[0], allfacets[i_facet].simplex.center[1], allfacets[i_facet].simplex.center[2]);- allfacets[i_facet].simplex.radius =- sqrt(squaredDistance(((vertexT*)facet->vertices->e[0].p)->point,- allfacets[i_facet].simplex.center, dim));- // allfacets[i_facet].simplex.center =- // facet->degenerate ? nanvector(dim)- // : qh_facetcenter(qh, facet->vertices);- // if(!facet->degenerate){- // allfacets[i_facet].simplex.center = //facet->center;- // qh_facetcenter(qh, facet->vertices);- // // faire une première passe : calculer les centres des triowner- // // pour ne pas les calculer pour les facets de la même famille- // printf("center1: %f %f %f\n", facet->center[0], facet->center[1], facet->center[2]);- // printf("center2: %f %f %f\n", allfacets[i_facet].simplex.center[0], allfacets[i_facet].simplex.center[1], allfacets[i_facet].simplex.center[2]);- // pointT* point = ((vertexT*)facet->vertices->e[0].p)->point;- // allfacets[i_facet].simplex.radius =- // sqrt(squaredDistance(point, allfacets[i_facet].simplex.center,- // dim));- // }// }else{- // // allfacets[i_facet].simplex.radius = NAN;- // // }-- { /* vertices ids of the facet */- allfacets[i_facet].simplex.sitesids =- malloc((dim+1) * sizeof(unsigned));- vertexT *vertex, **vertexp;- unsigned i_vertex = 0;- FOREACHvertex_(facet->vertices) {- allfacets[i_facet].simplex.sitesids[i_vertex] =- qh_pointid(qh, vertex->point);- i_vertex++;- }- qsortu(allfacets[i_facet].simplex.sitesids, dim+1);- }-- { /* neighbors facets of the facet */- facetT *neighbor, **neighborp;- unsigned flag[dim+1];- allfacets[i_facet].nneighbors = 0;- unsigned i_neighbor = 0;- FOREACHneighbor_(facet) {- if(flag[i_neighbor] = facetOK_(neighbor, degenerate)){- allfacets[i_facet].nneighbors++;- }- i_neighbor++;- }- allfacets[i_facet].neighbors =- malloc(allfacets[i_facet].nneighbors * sizeof(unsigned));- unsigned countok = 0;- i_neighbor = 0;- FOREACHneighbor_(facet) {- if(flag[i_neighbor]){- allfacets[i_facet].neighbors[countok] = neighbor->id;- countok++;- }- i_neighbor++;- }- }-- // /* facet family */- // if(facet->tricoplanar){- // allfacets[i_facet].family = facet->f.triowner->id;- // }else{- // allfacets[i_facet].family = -1;- // }-- /**/- i_facet++;- }- }-- // /* for degenerate facets, take the center of the owner */- // if(degenerate){- // facetT *facet;- // unsigned i_facet = 0;- // FORALLfacets{- // if(facet->degenerate){- // allfacets[i_facet].simplex.center =- // allfacets[allfacets[i_facet].family].simplex.center;- // pointT* point = ((vertexT*)facet->vertices->e[0].p)->point;- // allfacets[i_facet].simplex.radius =- // sqrt(squaredDistance(point, allfacets[i_facet].simplex.center,- // dim));- // }- // i_facet++;- // }- // }-- /* neighbor facets and neighbor vertices per vertex */- /* --- we will use the following combinations, also used later */- /* --- combinations[m] contains all k between 0 and dim but m */- unsigned combinations[dim+1][dim];- for(unsigned m=0; m < dim+1; m++){- unsigned kk=0;- for(unsigned k=0; k < dim+1; k++){- if(k != m){- combinations[m][kk] = k;- kk++;- }- }- }- /* --- initialize the sites */- SiteT* allsites = malloc(n * sizeof(SiteT));- /* --- array to flag neighbors - 0/1 if not neighbour/neighbour */- unsigned** verticesFacetsNeighbours = malloc(n * sizeof(unsigned*));- /* unsigned verticesFacetsNeighbours[n][nfacets] => stackoverflow */- for(unsigned v=0; v < n; v++){- allsites[v].id = v;- allsites[v].nneighsites = 0;- allsites[v].neighsites = malloc(0); /* will be filled by appending */- allsites[v].nneighridges = 0;- allsites[v].nneightiles = 0;- verticesFacetsNeighbours[v] = uzeros(nfacets);- }- /* --- fill verticesFacetsNeighbours, derive number of neighbor facets */- /* --- and derive neighbor sites */- for(unsigned i_facet=0; i_facet < nfacets; i_facet++){- for(unsigned j=0; j < dim+1; j++){- unsigned vertexid = allfacets[i_facet].simplex.sitesids[j];- if(verticesFacetsNeighbours[vertexid][i_facet] == 0){- verticesFacetsNeighbours[vertexid][i_facet] = 1;- allsites[vertexid].nneightiles++;- }- for(unsigned k=0; k < dim; k++){- unsigned vertexid2 =- allfacets[i_facet].simplex.sitesids[combinations[j][k]];- unsigned pushed;- appendu(vertexid2, &allsites[vertexid].neighsites,- allsites[vertexid].nneighsites, &pushed);- if(pushed){- allsites[vertexid].nneighsites++;- }- }- }- }-- /************************************************************/- /* second pass on facets: ridges and facet volumes */- unsigned n_ridges_dup = nfacets * (dim+1); /* number of ridges with duplicates */- SubTileT* allridges_dup = malloc(n_ridges_dup * sizeof(SubTileT));- for(unsigned r=0; r < n_ridges_dup; r++){- allridges_dup[r].simplex.sitesids = malloc(dim * sizeof(unsigned));- allridges_dup[r].flag = 0;- }-// qh_getarea(qh, qh->facet_list); /* make facets volumes, available in facet->f.area */- unsigned n_ridges = 0; /* count distinct ridges */-- { /* loop on facets */- facetT *facet;- unsigned i_ridge_dup = 0; /* ridge counter */- unsigned i_facet = 0; /* facet counter */- FORALLfacets {--// allfacets[i_facet].simplex.volume = facet->f.area;- allfacets[i_facet].nridges = dim+1;- allfacets[i_facet].ridgesids = malloc((dim+1) * sizeof(unsigned));-- /* loop on the combinations - it increments i_ridge_dup */- for(unsigned m=0; m < dim+1; m++){- allridges_dup[i_ridge_dup].ridgeOf1 = facet->id;- allridges_dup[i_ridge_dup].ridgeOf2 = -1; /* this means "nothing" */- unsigned ids[dim];- for(unsigned i=0; i < dim; i++){- ids[i] = allfacets[i_facet].simplex.sitesids[combinations[m][i]];- }- unsigned done = 0; /* flag ridge is already done */- for(unsigned r=0; r < i_ridge_dup; r++){- if(allridges_dup[r].ridgeOf2 == (int) facet->id &&- allridges_dup[r].flag==1)- {- unsigned ids2[dim];- unsigned i;- for(i=0; i < dim; i++){- ids2[i] = allridges_dup[r].simplex.sitesids[i];- if(ids2[i] != ids[i]){- break;- }- }- if(i == dim){- allfacets[i_facet].ridgesids[m] = allridges_dup[r].id;- done = 1;- break;- }- }- }- if(done == 0){ /* => then do the ridge */- allridges_dup[i_ridge_dup].flag = 1;- allridges_dup[i_ridge_dup].id = n_ridges;- allfacets[i_facet].ridgesids[m] = n_ridges;- n_ridges++;- for(unsigned i=0; i < dim; i++){- allridges_dup[i_ridge_dup].simplex.sitesids[i] = ids[i];- allsites[ids[i]].nneighridges++;- }-- { /* loop on facet neighbors to find ridgeOf2 */- facetT *neighbor, **neighborp;- FOREACHneighbor_(facet){- if(facetOK_(neighbor, degenerate)){- unsigned fnid = neighbor->id;- unsigned ok;- for(unsigned mm=0; mm < dim+1; mm++){- ok = 0;- for(unsigned i=0; i < dim; i++){- if(allfacets[fnid].simplex.sitesids[combinations[mm][i]]- != ids[i])- {- break;- }else{- ok++;- }- }- if(ok==dim){- break;- }- }- if(ok==dim){- allridges_dup[i_ridge_dup].ridgeOf2 = (int) fnid;- break;- }- }- } /* end FOREACHneighbor_(facet) */- }-- pointT* points[dim]; /* the points corresponding to the combination */- for(unsigned i=0; i < dim; i++){- points[i] = getpoint(sites, dim, ids[i]);- }- double normal[dim]; /* to store the ridge normal */- if(dim == 2){- double u1 = points[1][0] - points[0][0];- double v1 = points[1][1] - points[0][1];- allridges_dup[i_ridge_dup].simplex.volume =- sqrt(square(u1)+square(v1));- allridges_dup[i_ridge_dup].simplex.center =- middle(points[0], points[1], dim);- allridges_dup[i_ridge_dup].simplex.radius =- sqrt(squaredDistance(allridges_dup[i_ridge_dup].simplex.center,- points[0], dim));- normal[0] = v1; normal[1] = -u1;- }else{- int parity=1;- double squaredNorm = 0;- for(unsigned i=0; i < dim; i++){- double** rows = malloc((dim-1) * sizeof(double*));- for(unsigned j=0; j < dim-1; j++){- rows[j] = (double*) malloc((dim-1) * sizeof(double));- for(unsigned k=0; k < dim-1; k++){- unsigned kk = k<i ? k : k+1;- rows[j][k] = points[j+1][kk] - points[0][kk];- }- }- boolT nearzero;- normal[i] = parity * qh_determinant(qh, rows, dim-1, &nearzero);- squaredNorm += square(normal[i]);- for(unsigned j=0; j < dim-1; j++){- free(rows[j]);- }- free(rows);- parity = -parity;- }- double surface = sqrt(squaredNorm);- for(unsigned k=2; k < dim-1; k++){- surface /= k;- }- allridges_dup[i_ridge_dup].simplex.volume = surface;- }- qh_normalize2(qh, normal, dim, 1, NULL, NULL);- allridges_dup[i_ridge_dup].normal =- malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- allridges_dup[i_ridge_dup].normal[i] = normal[i];- }- allridges_dup[i_ridge_dup].offset =- - dotproduct(points[0], normal, dim);- if(dim > 2){ /* ridge center is already done if dim 2 */- // if(facet->degenerate){- // allridges_dup[i_ridge_dup].simplex.center = nanvector(dim);- // allridges_dup[i_ridge_dup].simplex.radius = NAN;- // }else{- allridges_dup[i_ridge_dup].simplex.center =- malloc(dim * sizeof(double));- double scal = 0;- for(unsigned i=0; i < dim; i++){- scal += (points[0][i]-allfacets[i_facet].simplex.center[i]) *- normal[i];- }- for(unsigned i=0; i < dim; i++){- allridges_dup[i_ridge_dup].simplex.center[i] =- allfacets[i_facet].simplex.center[i] + scal*normal[i];- }- allridges_dup[i_ridge_dup].simplex.radius =- sqrt(squaredDistance(- allridges_dup[i_ridge_dup].simplex.center,- points[0], dim));-// }- }- /* orient the normal (used for plotting unbounded Voronoi cells) */- if(allridges_dup[i_ridge_dup].ridgeOf2 == -1)- //&& (!facet->degenerate || dim==2))- {- pointT* otherpoint = /* the remaining vertex of the facet (the one not in the ridge) */- qh->interior_point; // getpoint(sites, dim, allfacets[facet->id].simplex.sitesids[m]);- double thepoint[dim]; /* the point center+normal */- for(unsigned i=0; i < dim; i++){- thepoint[i] = allridges_dup[i_ridge_dup].simplex.center[i] +- allridges_dup[i_ridge_dup].normal[i];- }- /* we check that these two points are on the same side of the ridge */- double h1 = dotproduct(otherpoint,- allridges_dup[i_ridge_dup].normal, dim) +- allridges_dup[i_ridge_dup].offset;- double h2 = dotproduct(thepoint,- allridges_dup[i_ridge_dup].normal, dim) +- allridges_dup[i_ridge_dup].offset;- // printf("deg: %u, h1: %f, h2: %f\n", facet->degenerate, h1, h2);- // printf("offset: %f\n", allridges_dup[i_ridge_dup].offset);- // printf("normal: %f %f %f\n", allridges_dup[i_ridge_dup].normal[0], allridges_dup[i_ridge_dup].normal[1], allridges_dup[i_ridge_dup].normal[2]);- if(h1*h2 >= 0){- for(unsigned i=0; i < dim; i++){- allridges_dup[i_ridge_dup].normal[i] *= -1;- }- }- }- for(unsigned i=0; i < dim; i++){- free(points[i]);- }- }- i_ridge_dup++;- } // end loop combinations (m)- qsortu(allfacets[i_facet].ridgesids, dim+1);- /**/- i_facet++;- } // end FORALLfacets- }-- /* extract unique ridges */- SubTileT* allridges = malloc(n_ridges * sizeof(SubTileT));- unsigned inc_ridge = 0;- for(unsigned l=0; l < n_ridges_dup; l++){- if(allridges_dup[l].flag){- allridges[inc_ridge] = allridges_dup[l];- inc_ridge++;- }- }-- /* make neighbor ridges per vertex */- unsigned* i_ridges_per_vertex = uzeros(n);- for(unsigned v=0; v < n; v++){- allsites[v].neighridgesids =- malloc(allsites[v].nneighridges * sizeof(unsigned));- }- for(unsigned l=0; l < n_ridges_dup; l++){- if(allridges_dup[l].flag){- for(unsigned i=0; i < dim; i++){- unsigned v = allridges_dup[l].simplex.sitesids[i];- allsites[v].neighridgesids[i_ridges_per_vertex[v]] =- allridges_dup[l].id;- i_ridges_per_vertex[v]++;- }- }- }-- /* order vertices neighbor sites and make neighbor tiles per vertex */- for(unsigned v=0; v < n; v++){- qsortu(allsites[v].neighsites, allsites[v].nneighsites);- allsites[v].neightiles =- malloc(allsites[v].nneightiles * sizeof(unsigned));- unsigned inc_facet = 0; unsigned inc_vfn = 0;- while(inc_vfn < allsites[v].nneightiles){- if(verticesFacetsNeighbours[v][inc_facet] == 1){- allsites[v].neightiles[inc_vfn] = inc_facet;- inc_vfn++;- }- inc_facet++;- }- }-- /* make the output */- out->sites = allsites;- out->tiles = allfacets;- out->ntiles = nfacets;- out->subtiles = allridges;- out->nsubtiles = n_ridges;-- free(allridges_dup);- free(i_ridges_per_vertex);- free(verticesFacetsNeighbours);-- }-- /* Do cleanup regardless of whether there is an error */- int curlong, totlong;- qh_freeqhull(qh, !qh_ALL); /* free long memory */- qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */-- printf("RETURN\n");- if(*exitcode){- free(out);- return 0;- }else{- return out;- }--}---void testdel2(){- double sites[27] = {0,0,0, 0,0,1, 0,1,0, 0,1,1, 1,0,0, 1,0,1, 1,1,0, 1,1,1, 0.5,0.5,0.5};- unsigned exitcode;- unsigned dim = 3;- TesselationT* x = tesselation(sites, dim, 9, 0, 0, 0, &exitcode);- printf("TESTDEL2 - nfacets:%u\n", x->ntiles);- for(unsigned f=0; f < x->ntiles; f++){- printf("facet %u - sites:\n", f);- for(unsigned i=0; i < dim+1; i++){- printf("%u - ", x->tiles[f].simplex.sitesids[i]);- }- printf("\n");- printf("facet %u - ridges:\n", f);- for(unsigned i=0; i < dim+1; i++){- printf("%u - ", x->tiles[f].ridgesids[i]);- }- printf("\n");- printf("facet %u - neighbors:\n", f);- for(unsigned i=0; i < x->tiles[f].nneighbors; i++){- printf("%u - ", x->tiles[f].neighbors[i]);- }- printf("\n");- }- printf("nallridges:%u\n", x->nsubtiles);- for(unsigned r=0; r < x->nsubtiles; r++){- printf("ridge %u - id %u:\n", r, x->subtiles[r].id);- for(unsigned i=0; i < dim; i++){- printf("%u - ", x->subtiles[r].simplex.sitesids[i]);- }- printf("ridgeOf: %u %d", x->subtiles[r].ridgeOf1, x->subtiles[r].ridgeOf2);- printf("\n");- }- free(x);-}
− C/geom2_r.c
@@ -1,2096 +0,0 @@-/*<html><pre> -<a href="qh-geom_r.htm"- >-------------------------------</a><a name="TOP">-</a>--- geom2_r.c- infrequently used geometric routines of qhull-- see qh-geom_r.htm and geom_r.h-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/geom2_r.c#6 $$Change: 2065 $- $DateTime: 2016/01/18 13:51:04 $$Author: bbarber $-- frequently used code goes into geom_r.c-*/--#include "qhull_ra.h"--/*================== functions in alphabetic order ============*/--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="copypoints">-</a>-- qh_copypoints(qh, points, numpoints, dimension)- return qh_malloc'd copy of points- - notes:- qh_free the returned points to avoid a memory leak-*/-coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension) {- int size;- coordT *newpoints;-- size= numpoints * dimension * (int)sizeof(coordT);- if (!(newpoints= (coordT*)qh_malloc((size_t)size))) {- qh_fprintf(qh, qh->ferr, 6004, "qhull error: insufficient memory to copy %d points\n",- numpoints);- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- memcpy((char *)newpoints, (char *)points, (size_t)size); /* newpoints!=0 by QH6004 */- return newpoints;-} /* copypoints */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="crossproduct">-</a>-- qh_crossproduct( dim, vecA, vecB, vecC )- crossproduct of 2 dim vectors- C= A x B-- notes:- from Glasner, Graphics Gems I, p. 639- only defined for dim==3-*/-void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){-- if (dim == 3) {- vecC[0]= det2_(vecA[1], vecA[2],- vecB[1], vecB[2]);- vecC[1]= - det2_(vecA[0], vecA[2],- vecB[0], vecB[2]);- vecC[2]= det2_(vecA[0], vecA[1],- vecB[0], vecB[1]);- }-} /* vcross */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="determinant">-</a>-- qh_determinant(qh, rows, dim, nearzero )- compute signed determinant of a square matrix- uses qh.NEARzero to test for degenerate matrices-- returns:- determinant- overwrites rows and the matrix- if dim == 2 or 3- nearzero iff determinant < qh->NEARzero[dim-1]- (!quite correct, not critical)- if dim >= 4- nearzero iff diagonal[k] < qh->NEARzero[k]-*/-realT qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero) {- realT det=0;- int i;- boolT sign= False;-- *nearzero= False;- if (dim < 2) {- qh_fprintf(qh, qh->ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }else if (dim == 2) {- det= det2_(rows[0][0], rows[0][1],- rows[1][0], rows[1][1]);- if (fabs_(det) < 10*qh->NEARzero[1]) /* not really correct, what should this be? */- *nearzero= True;- }else if (dim == 3) {- det= det3_(rows[0][0], rows[0][1], rows[0][2],- rows[1][0], rows[1][1], rows[1][2],- rows[2][0], rows[2][1], rows[2][2]);- if (fabs_(det) < 10*qh->NEARzero[2]) /* what should this be? det 5.5e-12 was flat for qh_maxsimplex of qdelaunay 0,0 27,27 -36,36 -9,63 */- *nearzero= True;- }else {- qh_gausselim(qh, rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/- det= 1.0;- for (i=dim; i--; )- det *= (rows[i])[i];- if (sign)- det= -det;- }- return det;-} /* determinant */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="detjoggle">-</a>-- qh_detjoggle(qh, points, numpoints, dimension )- determine default max joggle for point array- as qh_distround * qh_JOGGLEdefault-- returns:- initial value for JOGGLEmax from points and REALepsilon-- notes:- computes DISTround since qh_maxmin not called yet- if qh->SCALElast, last dimension will be scaled later to MAXwidth-- loop duplicated from qh_maxmin-*/-realT qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension) {- realT abscoord, distround, joggle, maxcoord, mincoord;- pointT *point, *pointtemp;- realT maxabs= -REALmax;- realT sumabs= 0;- realT maxwidth= 0;- int k;-- for (k=0; k < dimension; k++) {- if (qh->SCALElast && k == dimension-1)- abscoord= maxwidth;- else if (qh->DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */- abscoord= 2 * maxabs * maxabs; /* may be low by qh->hull_dim/2 */- else {- maxcoord= -REALmax;- mincoord= REALmax;- FORALLpoint_(qh, points, numpoints) {- maximize_(maxcoord, point[k]);- minimize_(mincoord, point[k]);- }- maximize_(maxwidth, maxcoord-mincoord);- abscoord= fmax_(maxcoord, -mincoord);- }- sumabs += abscoord;- maximize_(maxabs, abscoord);- } /* for k */- distround= qh_distround(qh, qh->hull_dim, maxabs, sumabs);- joggle= distround * qh_JOGGLEdefault;- maximize_(joggle, REALepsilon * qh_JOGGLEdefault);- trace2((qh, qh->ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));- return joggle;-} /* detjoggle */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="detroundoff">-</a>-- qh_detroundoff(qh)- determine maximum roundoff errors from- REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,- qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1-- accounts for qh.SETroundoff, qh.RANDOMdist, qh->MERGEexact- qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,- qh.postmerge_centrum, qh.MINoutside,- qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar-- returns:- sets qh.DISTround, etc. (see below)- appends precision constants to qh.qhull_options-- see:- qh_maxmin() for qh.NEARzero-- design:- determine qh.DISTround for distance computations- determine minimum denominators for qh_divzero- determine qh.ANGLEround for angle computations- adjust qh.premerge_cos,... for roundoff error- determine qh.ONEmerge for maximum error due to a single merge- determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,- qh.MINoutside, qh.WIDEfacet- initialize qh.max_vertex and qh.minvertex-*/-void qh_detroundoff(qhT *qh) {-- qh_option(qh, "_max-width", NULL, &qh->MAXwidth);- if (!qh->SETroundoff) {- qh->DISTround= qh_distround(qh, qh->hull_dim, qh->MAXabs_coord, qh->MAXsumcoord);- if (qh->RANDOMdist)- qh->DISTround += qh->RANDOMfactor * qh->MAXabs_coord;- qh_option(qh, "Error-roundoff", NULL, &qh->DISTround);- }- qh->MINdenom= qh->MINdenom_1 * qh->MAXabs_coord;- qh->MINdenom_1_2= sqrt(qh->MINdenom_1 * qh->hull_dim) ; /* if will be normalized */- qh->MINdenom_2= qh->MINdenom_1_2 * qh->MAXabs_coord;- /* for inner product */- qh->ANGLEround= 1.01 * qh->hull_dim * REALepsilon;- if (qh->RANDOMdist)- qh->ANGLEround += qh->RANDOMfactor;- if (qh->premerge_cos < REALmax/2) {- qh->premerge_cos -= qh->ANGLEround;- if (qh->RANDOMdist)- qh_option(qh, "Angle-premerge-with-random", NULL, &qh->premerge_cos);- }- if (qh->postmerge_cos < REALmax/2) {- qh->postmerge_cos -= qh->ANGLEround;- if (qh->RANDOMdist)- qh_option(qh, "Angle-postmerge-with-random", NULL, &qh->postmerge_cos);- }- qh->premerge_centrum += 2 * qh->DISTround; /*2 for centrum and distplane()*/- qh->postmerge_centrum += 2 * qh->DISTround;- if (qh->RANDOMdist && (qh->MERGEexact || qh->PREmerge))- qh_option(qh, "Centrum-premerge-with-random", NULL, &qh->premerge_centrum);- if (qh->RANDOMdist && qh->POSTmerge)- qh_option(qh, "Centrum-postmerge-with-random", NULL, &qh->postmerge_centrum);- { /* compute ONEmerge, max vertex offset for merging simplicial facets */- realT maxangle= 1.0, maxrho;-- minimize_(maxangle, qh->premerge_cos);- minimize_(maxangle, qh->postmerge_cos);- /* max diameter * sin theta + DISTround for vertex to its hyperplane */- qh->ONEmerge= sqrt((realT)qh->hull_dim) * qh->MAXwidth *- sqrt(1.0 - maxangle * maxangle) + qh->DISTround;- maxrho= qh->hull_dim * qh->premerge_centrum + qh->DISTround;- maximize_(qh->ONEmerge, maxrho);- maxrho= qh->hull_dim * qh->postmerge_centrum + qh->DISTround;- maximize_(qh->ONEmerge, maxrho);- if (qh->MERGING)- qh_option(qh, "_one-merge", NULL, &qh->ONEmerge);- }- qh->NEARinside= qh->ONEmerge * qh_RATIOnearinside; /* only used if qh->KEEPnearinside */- if (qh->JOGGLEmax < REALmax/2 && (qh->KEEPcoplanar || qh->KEEPinside)) {- realT maxdist; /* adjust qh.NEARinside for joggle */- qh->KEEPnearinside= True;- maxdist= sqrt((realT)qh->hull_dim) * qh->JOGGLEmax + qh->DISTround;- maxdist= 2*maxdist; /* vertex and coplanar point can joggle in opposite directions */- maximize_(qh->NEARinside, maxdist); /* must agree with qh_nearcoplanar() */- }- if (qh->KEEPnearinside)- qh_option(qh, "_near-inside", NULL, &qh->NEARinside);- if (qh->JOGGLEmax < qh->DISTround) {- qh_fprintf(qh, qh->ferr, 6006, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",- qh->JOGGLEmax, qh->DISTround);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->MINvisible > REALmax/2) {- if (!qh->MERGING)- qh->MINvisible= qh->DISTround;- else if (qh->hull_dim <= 3)- qh->MINvisible= qh->premerge_centrum;- else- qh->MINvisible= qh_COPLANARratio * qh->premerge_centrum;- if (qh->APPROXhull && qh->MINvisible > qh->MINoutside)- qh->MINvisible= qh->MINoutside;- qh_option(qh, "Visible-distance", NULL, &qh->MINvisible);- }- if (qh->MAXcoplanar > REALmax/2) {- qh->MAXcoplanar= qh->MINvisible;- qh_option(qh, "U-coplanar-distance", NULL, &qh->MAXcoplanar);- }- if (!qh->APPROXhull) { /* user may specify qh->MINoutside */- qh->MINoutside= 2 * qh->MINvisible;- if (qh->premerge_cos < REALmax/2)- maximize_(qh->MINoutside, (1- qh->premerge_cos) * qh->MAXabs_coord);- qh_option(qh, "Width-outside", NULL, &qh->MINoutside);- }- qh->WIDEfacet= qh->MINoutside;- maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MAXcoplanar);- maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MINvisible);- qh_option(qh, "_wide-facet", NULL, &qh->WIDEfacet);- if (qh->MINvisible > qh->MINoutside + 3 * REALepsilon- && !qh->BESToutside && !qh->FORCEoutput)- qh_fprintf(qh, qh->ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n",- qh->MINvisible, qh->MINoutside);- qh->max_vertex= qh->DISTround;- qh->min_vertex= -qh->DISTround;- /* numeric constants reported in printsummary */-} /* detroundoff */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="detsimplex">-</a>-- qh_detsimplex(qh, apex, points, dim, nearzero )- compute determinant of a simplex with point apex and base points-- returns:- signed determinant and nearzero from qh_determinant-- notes:- uses qh.gm_matrix/qh.gm_row (assumes they're big enough)-- design:- construct qm_matrix by subtracting apex from points- compute determinate-*/-realT qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero) {- pointT *coorda, *coordp, *gmcoord, *point, **pointp;- coordT **rows;- int k, i=0;- realT det;-- zinc_(Zdetsimplex);- gmcoord= qh->gm_matrix;- rows= qh->gm_row;- FOREACHpoint_(points) {- if (i == dim)- break;- rows[i++]= gmcoord;- coordp= point;- coorda= apex;- for (k=dim; k--; )- *(gmcoord++)= *coordp++ - *coorda++;- }- if (i < dim) {- qh_fprintf(qh, qh->ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",- i, dim);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- det= qh_determinant(qh, rows, dim, nearzero);- trace2((qh, qh->ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",- det, qh_pointid(qh, apex), dim, *nearzero));- return det;-} /* detsimplex */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="distnorm">-</a>-- qh_distnorm( dim, point, normal, offset )- return distance from point to hyperplane at normal/offset-- returns:- dist-- notes:- dist > 0 if point is outside of hyperplane-- see:- qh_distplane in geom_r.c-*/-realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {- coordT *normalp= normal, *coordp= point;- realT dist;- int k;-- dist= *offsetp;- for (k=dim; k--; )- dist += *(coordp++) * *(normalp++);- return dist;-} /* distnorm */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="distround">-</a>-- qh_distround(qh, dimension, maxabs, maxsumabs )- compute maximum round-off error for a distance computation- to a normalized hyperplane- maxabs is the maximum absolute value of a coordinate- maxsumabs is the maximum possible sum of absolute coordinate values-- returns:- max dist round for REALepsilon-- notes:- calculate roundoff error according to Golub & van Loan, 1983, Lemma 3.2-1, "Rounding Errors"- use sqrt(dim) since one vector is normalized- or use maxsumabs since one vector is < 1-*/-realT qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs) {- realT maxdistsum, maxround;-- maxdistsum= sqrt((realT)dimension) * maxabs;- minimize_( maxdistsum, maxsumabs);- maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);- /* adds maxabs for offset */- trace4((qh, qh->ferr, 4008, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",- maxround, maxabs, maxsumabs, maxdistsum));- return maxround;-} /* distround */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="divzero">-</a>-- qh_divzero( numer, denom, mindenom1, zerodiv )- divide by a number that's nearly zero- mindenom1= minimum denominator for dividing into 1.0-- returns:- quotient- sets zerodiv and returns 0.0 if it would overflow-- design:- if numer is nearly zero and abs(numer) < abs(denom)- return numer/denom- else if numer is nearly zero- return 0 and zerodiv- else if denom/numer non-zero- return numer/denom- else- return 0 and zerodiv-*/-realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {- realT temp, numerx, denomx;--- if (numer < mindenom1 && numer > -mindenom1) {- numerx= fabs_(numer);- denomx= fabs_(denom);- if (numerx < denomx) {- *zerodiv= False;- return numer/denom;- }else {- *zerodiv= True;- return 0.0;- }- }- temp= denom/numer;- if (temp > mindenom1 || temp < -mindenom1) {- *zerodiv= False;- return numer/denom;- }else {- *zerodiv= True;- return 0.0;- }-} /* divzero */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="facetarea">-</a>-- qh_facetarea(qh, facet )- return area for a facet-- notes:- if non-simplicial,- uses centrum to triangulate facet and sums the projected areas.- if (qh->DELAUNAY),- computes projected area instead for last coordinate- assumes facet->normal exists- projecting tricoplanar facets to the hyperplane does not appear to make a difference-- design:- if simplicial- compute area- else- for each ridge- compute area from centrum to ridge- negate area if upper Delaunay facet-*/-realT qh_facetarea(qhT *qh, facetT *facet) {- vertexT *apex;- pointT *centrum;- realT area= 0.0;- ridgeT *ridge, **ridgep;-- if (facet->simplicial) {- apex= SETfirstt_(facet->vertices, vertexT);- area= qh_facetarea_simplex(qh, qh->hull_dim, apex->point, facet->vertices,- apex, facet->toporient, facet->normal, &facet->offset);- }else {- if (qh->CENTERtype == qh_AScentrum)- centrum= facet->center;- else- centrum= qh_getcentrum(qh, facet);- FOREACHridge_(facet->ridges)- area += qh_facetarea_simplex(qh, qh->hull_dim, centrum, ridge->vertices,- NULL, (boolT)(ridge->top == facet), facet->normal, &facet->offset);- if (qh->CENTERtype != qh_AScentrum)- qh_memfree(qh, centrum, qh->normal_size);- }- if (facet->upperdelaunay && qh->DELAUNAY)- area= -area; /* the normal should be [0,...,1] */- trace4((qh, qh->ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));- return area;-} /* facetarea */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="facetarea_simplex">-</a>-- qh_facetarea_simplex(qh, dim, apex, vertices, notvertex, toporient, normal, offset )- return area for a simplex defined by- an apex, a base of vertices, an orientation, and a unit normal- if simplicial or tricoplanar facet,- notvertex is defined and it is skipped in vertices-- returns:- computes area of simplex projected to plane [normal,offset]- returns 0 if vertex too far below plane (qh->WIDEfacet)- vertex can't be apex of tricoplanar facet-- notes:- if (qh->DELAUNAY),- computes projected area instead for last coordinate- uses qh->gm_matrix/gm_row and qh->hull_dim- helper function for qh_facetarea-- design:- if Notvertex- translate simplex to apex- else- project simplex to normal/offset- translate simplex to apex- if Delaunay- set last row/column to 0 with -1 on diagonal- else- set last row to Normal- compute determinate- scale and flip sign for area-*/-realT qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,- vertexT *notvertex, boolT toporient, coordT *normal, realT *offset) {- pointT *coorda, *coordp, *gmcoord;- coordT **rows, *normalp;- int k, i=0;- realT area, dist;- vertexT *vertex, **vertexp;- boolT nearzero;-- gmcoord= qh->gm_matrix;- rows= qh->gm_row;- FOREACHvertex_(vertices) {- if (vertex == notvertex)- continue;- rows[i++]= gmcoord;- coorda= apex;- coordp= vertex->point;- normalp= normal;- if (notvertex) {- for (k=dim; k--; )- *(gmcoord++)= *coordp++ - *coorda++;- }else {- dist= *offset;- for (k=dim; k--; )- dist += *coordp++ * *normalp++;- if (dist < -qh->WIDEfacet) {- zinc_(Znoarea);- return 0.0;- }- coordp= vertex->point;- normalp= normal;- for (k=dim; k--; )- *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;- }- }- if (i != dim-1) {- qh_fprintf(qh, qh->ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",- i, dim);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- rows[i]= gmcoord;- if (qh->DELAUNAY) {- for (i=0; i < dim-1; i++)- rows[i][dim-1]= 0.0;- for (k=dim; k--; )- *(gmcoord++)= 0.0;- rows[dim-1][dim-1]= -1.0;- }else {- normalp= normal;- for (k=dim; k--; )- *(gmcoord++)= *normalp++;- }- zinc_(Zdetsimplex);- area= qh_determinant(qh, rows, dim, &nearzero);- if (toporient)- area= -area;- area *= qh->AREAfactor;- trace4((qh, qh->ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",- area, qh_pointid(qh, apex), toporient, nearzero));- return area;-} /* facetarea_simplex */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="facetcenter">-</a>-- qh_facetcenter(qh, vertices )- return Voronoi center (Voronoi vertex) for a facet's vertices-- returns:- return temporary point equal to the center-- see:- qh_voronoi_center()-*/-pointT *qh_facetcenter(qhT *qh, setT *vertices) {- setT *points= qh_settemp(qh, qh_setsize(qh, vertices));- vertexT *vertex, **vertexp;- pointT *center;-- FOREACHvertex_(vertices)- qh_setappend(qh, &points, vertex->point);- center= qh_voronoi_center(qh, qh->hull_dim-1, points);- qh_settempfree(qh, &points);- return center;-} /* facetcenter */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="findgooddist">-</a>-- qh_findgooddist(qh, point, facetA, dist, facetlist )- find best good facet visible for point from facetA- assumes facetA is visible from point-- returns:- best facet, i.e., good facet that is furthest from point- distance to best facet- NULL if none-- moves good, visible facets (and some other visible facets)- to end of qh->facet_list-- notes:- uses qh->visit_id-- design:- initialize bestfacet if facetA is good- move facetA to end of facetlist- for each facet on facetlist- for each unvisited neighbor of facet- move visible neighbors to end of facetlist- update best good neighbor- if no good neighbors, update best facet-*/-facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp,- facetT **facetlist) {- realT bestdist= -REALmax, dist;- facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;- boolT goodseen= False;-- if (facetA->good) {- zzinc_(Zcheckpart); /* calls from check_bestdist occur after print stats */- qh_distplane(qh, point, facetA, &bestdist);- bestfacet= facetA;- goodseen= True;- }- qh_removefacet(qh, facetA);- qh_appendfacet(qh, facetA);- *facetlist= facetA;- facetA->visitid= ++qh->visit_id;- FORALLfacet_(*facetlist) {- FOREACHneighbor_(facet) {- if (neighbor->visitid == qh->visit_id)- continue;- neighbor->visitid= qh->visit_id;- if (goodseen && !neighbor->good)- continue;- zzinc_(Zcheckpart);- qh_distplane(qh, point, neighbor, &dist);- if (dist > 0) {- qh_removefacet(qh, neighbor);- qh_appendfacet(qh, neighbor);- if (neighbor->good) {- goodseen= True;- if (dist > bestdist) {- bestdist= dist;- bestfacet= neighbor;- }- }- }- }- }- if (bestfacet) {- *distp= bestdist;- trace2((qh, qh->ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",- qh_pointid(qh, point), bestdist, bestfacet->id));- return bestfacet;- }- trace4((qh, qh->ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",- qh_pointid(qh, point), facetA->id));- return NULL;-} /* findgooddist */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="getarea">-</a>-- qh_getarea(qh, facetlist )- set area of all facets in facetlist- collect statistics- nop if hasAreaVolume-- returns:- sets qh->totarea/totvol to total area and volume of convex hull- for Delaunay triangulation, computes projected area of the lower or upper hull- ignores upper hull if qh->ATinfinity-- notes:- could compute outer volume by expanding facet area by rays from interior- the following attempt at perpendicular projection underestimated badly:- qh.totoutvol += (-dist + facet->maxoutside + qh->DISTround)- * area/ qh->hull_dim;- design:- for each facet on facetlist- compute facet->area- update qh.totarea and qh.totvol-*/-void qh_getarea(qhT *qh, facetT *facetlist) {- realT area;- realT dist;- facetT *facet;-- if (qh->hasAreaVolume)- return;- if (qh->REPORTfreq)- qh_fprintf(qh, qh->ferr, 8020, "computing area of each facet and volume of the convex hull\n");- else- trace1((qh, qh->ferr, 1001, "qh_getarea: computing volume and area for each facet\n"));- qh->totarea= qh->totvol= 0.0;- FORALLfacet_(facetlist) {- if (!facet->normal)- continue;- if (facet->upperdelaunay && qh->ATinfinity)- continue;- if (!facet->isarea) {- facet->f.area= qh_facetarea(qh, facet);- facet->isarea= True;- }- area= facet->f.area;- if (qh->DELAUNAY) {- if (facet->upperdelaunay == qh->UPPERdelaunay)- qh->totarea += area;- }else {- qh->totarea += area;- qh_distplane(qh, qh->interior_point, facet, &dist);- qh->totvol += -dist * area/ qh->hull_dim;- }- if (qh->PRINTstatistics) {- wadd_(Wareatot, area);- wmax_(Wareamax, area);- wmin_(Wareamin, area);- }- }- qh->hasAreaVolume= True;-} /* getarea */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="gram_schmidt">-</a>-- qh_gram_schmidt(qh, dim, row )- implements Gram-Schmidt orthogonalization by rows-- returns:- false if zero norm- overwrites rows[dim][dim]-- notes:- see Golub & van Loan, 1983, Algorithm 6.2-2, "Modified Gram-Schmidt"- overflow due to small divisors not handled-- design:- for each row- compute norm for row- if non-zero, normalize row- for each remaining rowA- compute inner product of row and rowA- reduce rowA by row * inner product-*/-boolT qh_gram_schmidt(qhT *qh, int dim, realT **row) {- realT *rowi, *rowj, norm;- int i, j, k;-- for (i=0; i < dim; i++) {- rowi= row[i];- for (norm= 0.0, k= dim; k--; rowi++)- norm += *rowi * *rowi;- norm= sqrt(norm);- wmin_(Wmindenom, norm);- if (norm == 0.0) /* either 0 or overflow due to sqrt */- return False;- for (k=dim; k--; )- *(--rowi) /= norm;- for (j=i+1; j < dim; j++) {- rowj= row[j];- for (norm= 0.0, k=dim; k--; )- norm += *rowi++ * *rowj++;- for (k=dim; k--; )- *(--rowj) -= *(--rowi) * norm;- }- }- return True;-} /* gram_schmidt */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="inthresholds">-</a>-- qh_inthresholds(qh, normal, angle )- return True if normal within qh.lower_/upper_threshold-- returns:- estimate of angle by summing of threshold diffs- angle may be NULL- smaller "angle" is better-- notes:- invalid if qh.SPLITthresholds-- see:- qh.lower_threshold in qh_initbuild()- qh_initthresholds()-- design:- for each dimension- test threshold-*/-boolT qh_inthresholds(qhT *qh, coordT *normal, realT *angle) {- boolT within= True;- int k;- realT threshold;-- if (angle)- *angle= 0.0;- for (k=0; k < qh->hull_dim; k++) {- threshold= qh->lower_threshold[k];- if (threshold > -REALmax/2) {- if (normal[k] < threshold)- within= False;- if (angle) {- threshold -= normal[k];- *angle += fabs_(threshold);- }- }- if (qh->upper_threshold[k] < REALmax/2) {- threshold= qh->upper_threshold[k];- if (normal[k] > threshold)- within= False;- if (angle) {- threshold -= normal[k];- *angle += fabs_(threshold);- }- }- }- return within;-} /* inthresholds */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="joggleinput">-</a>-- qh_joggleinput(qh)- randomly joggle input to Qhull by qh.JOGGLEmax- initial input is qh.first_point/qh.num_points of qh.hull_dim- repeated calls use qh.input_points/qh.num_points-- returns:- joggles points at qh.first_point/qh.num_points- copies data to qh.input_points/qh.input_malloc if first time- determines qh.JOGGLEmax if it was zero- if qh.DELAUNAY- computes the Delaunay projection of the joggled points-- notes:- if qh.DELAUNAY, unnecessarily joggles the last coordinate- the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease-- design:- if qh.DELAUNAY- set qh.SCALElast for reduced precision errors- if first call- initialize qh.input_points to the original input points- if qh.JOGGLEmax == 0- determine default qh.JOGGLEmax- else- increase qh.JOGGLEmax according to qh.build_cnt- joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]- if qh.DELAUNAY- sets the Delaunay projection-*/-void qh_joggleinput(qhT *qh) {- int i, seed, size;- coordT *coordp, *inputp;- realT randr, randa, randb;-- if (!qh->input_points) { /* first call */- qh->input_points= qh->first_point;- qh->input_malloc= qh->POINTSmalloc;- size= qh->num_points * qh->hull_dim * sizeof(coordT);- if (!(qh->first_point=(coordT*)qh_malloc((size_t)size))) {- qh_fprintf(qh, qh->ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",- qh->num_points);- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- qh->POINTSmalloc= True;- if (qh->JOGGLEmax == 0.0) {- qh->JOGGLEmax= qh_detjoggle(qh, qh->input_points, qh->num_points, qh->hull_dim);- qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);- }- }else { /* repeated call */- if (!qh->RERUN && qh->build_cnt > qh_JOGGLEretry) {- if (((qh->build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {- realT maxjoggle= qh->MAXwidth * qh_JOGGLEmaxincrease;- if (qh->JOGGLEmax < maxjoggle) {- qh->JOGGLEmax *= qh_JOGGLEincrease;- minimize_(qh->JOGGLEmax, maxjoggle);- }- }- }- qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);- }- if (qh->build_cnt > 1 && qh->JOGGLEmax > fmax_(qh->MAXwidth/4, 0.1)) {- qh_fprintf(qh, qh->ferr, 6010, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input. If possible, recompile Qhull with higher-precision reals.\n",- qh->JOGGLEmax);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- /* for some reason, using qh->ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */- seed= qh_RANDOMint;- qh_option(qh, "_joggle-seed", &seed, NULL);- trace0((qh, qh->ferr, 6, "qh_joggleinput: joggle input by %2.2g with seed %d\n",- qh->JOGGLEmax, seed));- inputp= qh->input_points;- coordp= qh->first_point;- randa= 2.0 * qh->JOGGLEmax/qh_RANDOMmax;- randb= -qh->JOGGLEmax;- size= qh->num_points * qh->hull_dim;- for (i=size; i--; ) {- randr= qh_RANDOMint;- *(coordp++)= *(inputp++) + (randr * randa + randb);- }- if (qh->DELAUNAY) {- qh->last_low= qh->last_high= qh->last_newhigh= REALmax;- qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);- }-} /* joggleinput */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="maxabsval">-</a>-- qh_maxabsval( normal, dim )- return pointer to maximum absolute value of a dim vector- returns NULL if dim=0-*/-realT *qh_maxabsval(realT *normal, int dim) {- realT maxval= -REALmax;- realT *maxp= NULL, *colp, absval;- int k;-- for (k=dim, colp= normal; k--; colp++) {- absval= fabs_(*colp);- if (absval > maxval) {- maxval= absval;- maxp= colp;- }- }- return maxp;-} /* maxabsval */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="maxmin">-</a>-- qh_maxmin(qh, points, numpoints, dimension )- return max/min points for each dimension- determine max and min coordinates-- returns:- returns a temporary set of max and min points- may include duplicate points. Does not include qh.GOODpoint- sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth- qh.MAXlastcoord, qh.MINlastcoord- initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok-- notes:- loop duplicated in qh_detjoggle()-- design:- initialize global precision variables- checks definition of REAL...- for each dimension- for each point- collect maximum and minimum point- collect maximum of maximums and minimum of minimums- determine qh.NEARzero for Gaussian Elimination-*/-setT *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension) {- int k;- realT maxcoord, temp;- pointT *minimum, *maximum, *point, *pointtemp;- setT *set;-- qh->max_outside= 0.0;- qh->MAXabs_coord= 0.0;- qh->MAXwidth= -REALmax;- qh->MAXsumcoord= 0.0;- qh->min_vertex= 0.0;- qh->WAScoplanar= False;- if (qh->ZEROcentrum)- qh->ZEROall_ok= True;- if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax- && REALmax > 0.0 && -REALmax < 0.0)- ; /* all ok */- else {- qh_fprintf(qh, qh->ferr, 6011, "qhull error: floating point constants in user.h are wrong\n\-REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",- REALepsilon, REALmin, REALmax, -REALmax);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- set= qh_settemp(qh, 2*dimension);- for (k=0; k < dimension; k++) {- if (points == qh->GOODpointp)- minimum= maximum= points + dimension;- else- minimum= maximum= points;- FORALLpoint_(qh, points, numpoints) {- if (point == qh->GOODpointp)- continue;- if (maximum[k] < point[k])- maximum= point;- else if (minimum[k] > point[k])- minimum= point;- }- if (k == dimension-1) {- qh->MINlastcoord= minimum[k];- qh->MAXlastcoord= maximum[k];- }- if (qh->SCALElast && k == dimension-1)- maxcoord= qh->MAXwidth;- else {- maxcoord= fmax_(maximum[k], -minimum[k]);- if (qh->GOODpointp) {- temp= fmax_(qh->GOODpointp[k], -qh->GOODpointp[k]);- maximize_(maxcoord, temp);- }- temp= maximum[k] - minimum[k];- maximize_(qh->MAXwidth, temp);- }- maximize_(qh->MAXabs_coord, maxcoord);- qh->MAXsumcoord += maxcoord;- qh_setappend(qh, &set, maximum);- qh_setappend(qh, &set, minimum);- /* calculation of qh NEARzero is based on Golub & van Loan, 1983,- Eq. 4.4-13 for "Gaussian elimination with complete pivoting".- Golub & van Loan say that n^3 can be ignored and 10 be used in- place of rho */- qh->NEARzero[k]= 80 * qh->MAXsumcoord * REALepsilon;- }- if (qh->IStracing >=1)- qh_printpoints(qh, qh->ferr, "qh_maxmin: found the max and min points(by dim):", set);- return(set);-} /* maxmin */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="maxouter">-</a>-- qh_maxouter(qh)- return maximum distance from facet to outer plane- normally this is qh.max_outside+qh.DISTround- does not include qh.JOGGLEmax-- see:- qh_outerinner()-- notes:- need to add another qh.DISTround if testing actual point with computation-- for joggle:- qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)- need to use Wnewvertexmax since could have a coplanar point for a high- facet that is replaced by a low facet- need to add qh.JOGGLEmax if testing input points-*/-realT qh_maxouter(qhT *qh) {- realT dist;-- dist= fmax_(qh->max_outside, qh->DISTround);- dist += qh->DISTround;- trace4((qh, qh->ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh->max_outside));- return dist;-} /* maxouter */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="maxsimplex">-</a>-- qh_maxsimplex(qh, dim, maxpoints, points, numpoints, simplex )- determines maximum simplex for a set of points- starts from points already in simplex- skips qh.GOODpointp (assumes that it isn't in maxpoints)-- returns:- simplex with dim+1 points-- notes:- assumes at least pointsneeded points in points- maximizes determinate for x,y,z,w, etc.- uses maxpoints as long as determinate is clearly non-zero-- design:- initialize simplex with at least two points- (find points with max or min x coordinate)- for each remaining dimension- add point that maximizes the determinate- (use points from maxpoints first)-*/-void qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {- pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;- boolT nearzero, maxnearzero= False;- int k, sizinit;- realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;-- sizinit= qh_setsize(qh, *simplex);- if (sizinit < 2) {- if (qh_setsize(qh, maxpoints) >= 2) {- FOREACHpoint_(maxpoints) {- if (maxcoord < point[0]) {- maxcoord= point[0];- maxx= point;- }- if (mincoord > point[0]) {- mincoord= point[0];- minx= point;- }- }- }else {- FORALLpoint_(qh, points, numpoints) {- if (point == qh->GOODpointp)- continue;- if (maxcoord < point[0]) {- maxcoord= point[0];- maxx= point;- }- if (mincoord > point[0]) {- mincoord= point[0];- minx= point;- }- }- }- qh_setunique(qh, simplex, minx);- if (qh_setsize(qh, *simplex) < 2)- qh_setunique(qh, simplex, maxx);- sizinit= qh_setsize(qh, *simplex);- if (sizinit < 2) {- qh_precision(qh, "input has same x coordinate");- if (zzval_(Zsetplane) > qh->hull_dim+1) {- qh_fprintf(qh, qh->ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",- qh_setsize(qh, maxpoints)+numpoints);- qh_errexit(qh, qh_ERRprec, NULL, NULL);- }else {- qh_fprintf(qh, qh->ferr, 6013, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh->hull_dim);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- }- }- for (k=sizinit; k < dim+1; k++) {- maxpoint= NULL;- maxdet= -REALmax;- FOREACHpoint_(maxpoints) {- if (!qh_setin(*simplex, point)) {- det= qh_detsimplex(qh, point, *simplex, k, &nearzero);- if ((det= fabs_(det)) > maxdet) {- maxdet= det;- maxpoint= point;- maxnearzero= nearzero;- }- }- }- if (!maxpoint || maxnearzero) {- zinc_(Zsearchpoints);- if (!maxpoint) {- trace0((qh, qh->ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));- }else {- trace0((qh, qh->ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",- k+1, qh_pointid(qh, maxpoint), maxdet));- }- FORALLpoint_(qh, points, numpoints) {- if (point == qh->GOODpointp)- continue;- if (!qh_setin(*simplex, point)) {- det= qh_detsimplex(qh, point, *simplex, k, &nearzero);- if ((det= fabs_(det)) > maxdet) {- maxdet= det;- maxpoint= point;- maxnearzero= nearzero;- }- }- }- } /* !maxpoint */- if (!maxpoint) {- qh_fprintf(qh, qh->ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- qh_setappend(qh, simplex, maxpoint);- trace1((qh, qh->ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",- qh_pointid(qh, maxpoint), k+1, maxdet));- } /* k */-} /* maxsimplex */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="minabsval">-</a>-- qh_minabsval( normal, dim )- return minimum absolute value of a dim vector-*/-realT qh_minabsval(realT *normal, int dim) {- realT minval= 0;- realT maxval= 0;- realT *colp;- int k;-- for (k=dim, colp=normal; k--; colp++) {- maximize_(maxval, *colp);- minimize_(minval, *colp);- }- return fmax_(maxval, -minval);-} /* minabsval */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="mindiff">-</a>-- qh_mindif(qh, vecA, vecB, dim )- return index of min abs. difference of two vectors-*/-int qh_mindiff(realT *vecA, realT *vecB, int dim) {- realT mindiff= REALmax, diff;- realT *vecAp= vecA, *vecBp= vecB;- int k, mink= 0;-- for (k=0; k < dim; k++) {- diff= *vecAp++ - *vecBp++;- diff= fabs_(diff);- if (diff < mindiff) {- mindiff= diff;- mink= k;- }- }- return mink;-} /* mindiff */----/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="orientoutside">-</a>-- qh_orientoutside(qh, facet )- make facet outside oriented via qh.interior_point-- returns:- True if facet reversed orientation.-*/-boolT qh_orientoutside(qhT *qh, facetT *facet) {- int k;- realT dist;-- qh_distplane(qh, qh->interior_point, facet, &dist);- if (dist > 0) {- for (k=qh->hull_dim; k--; )- facet->normal[k]= -facet->normal[k];- facet->offset= -facet->offset;- return True;- }- return False;-} /* orientoutside */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="outerinner">-</a>-- qh_outerinner(qh, facet, outerplane, innerplane )- if facet and qh.maxoutdone (i.e., qh_check_maxout)- returns outer and inner plane for facet- else- returns maximum outer and inner plane- accounts for qh.JOGGLEmax-- see:- qh_maxouter(qh), qh_check_bestdist(), qh_check_points()-- notes:- outerplaner or innerplane may be NULL- facet is const- Does not error (QhullFacet)-- includes qh.DISTround for actual points- adds another qh.DISTround if testing with floating point arithmetic-*/-void qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {- realT dist, mindist;- vertexT *vertex, **vertexp;-- if (outerplane) {- if (!qh_MAXoutside || !facet || !qh->maxoutdone) {- *outerplane= qh_maxouter(qh); /* includes qh.DISTround */- }else { /* qh_MAXoutside ... */-#if qh_MAXoutside- *outerplane= facet->maxoutside + qh->DISTround;-#endif-- }- if (qh->JOGGLEmax < REALmax/2)- *outerplane += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);- }- if (innerplane) {- if (facet) {- mindist= REALmax;- FOREACHvertex_(facet->vertices) {- zinc_(Zdistio);- qh_distplane(qh, vertex->point, facet, &dist);- minimize_(mindist, dist);- }- *innerplane= mindist - qh->DISTround;- }else- *innerplane= qh->min_vertex - qh->DISTround;- if (qh->JOGGLEmax < REALmax/2)- *innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);- }-} /* outerinner */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="pointdist">-</a>-- qh_pointdist( point1, point2, dim )- return distance between two points-- notes:- returns distance squared if 'dim' is negative-*/-coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {- coordT dist, diff;- int k;-- dist= 0.0;- for (k= (dim > 0 ? dim : -dim); k--; ) {- diff= *point1++ - *point2++;- dist += diff * diff;- }- if (dim > 0)- return(sqrt(dist));- return dist;-} /* pointdist */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="printmatrix">-</a>-- qh_printmatrix(qh, fp, string, rows, numrow, numcol )- print matrix to fp given by row vectors- print string as header- qh may be NULL if fp is defined-- notes:- print a vector by qh_printmatrix(qh, fp, "", &vect, 1, len)-*/-void qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol) {- realT *rowp;- realT r; /*bug fix*/- int i,k;-- qh_fprintf(qh, fp, 9001, "%s\n", string);- for (i=0; i < numrow; i++) {- rowp= rows[i];- for (k=0; k < numcol; k++) {- r= *rowp++;- qh_fprintf(qh, fp, 9002, "%6.3g ", r);- }- qh_fprintf(qh, fp, 9003, "\n");- }-} /* printmatrix */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="printpoints">-</a>-- qh_printpoints(qh, fp, string, points )- print pointids to fp for a set of points- if string, prints string and 'p' point ids-*/-void qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points) {- pointT *point, **pointp;-- if (string) {- qh_fprintf(qh, fp, 9004, "%s", string);- FOREACHpoint_(points)- qh_fprintf(qh, fp, 9005, " p%d", qh_pointid(qh, point));- qh_fprintf(qh, fp, 9006, "\n");- }else {- FOREACHpoint_(points)- qh_fprintf(qh, fp, 9007, " %d", qh_pointid(qh, point));- qh_fprintf(qh, fp, 9008, "\n");- }-} /* printpoints */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="projectinput">-</a>-- qh_projectinput(qh)- project input points using qh.lower_bound/upper_bound and qh->DELAUNAY- if qh.lower_bound[k]=qh.upper_bound[k]= 0,- removes dimension k- if halfspace intersection- removes dimension k from qh.feasible_point- input points in qh->first_point, num_points, input_dim-- returns:- new point array in qh->first_point of qh->hull_dim coordinates- sets qh->POINTSmalloc- if qh->DELAUNAY- projects points to paraboloid- lowbound/highbound is also projected- if qh->ATinfinity- adds point "at-infinity"- if qh->POINTSmalloc- frees old point array-- notes:- checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY--- design:- sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)- determines newdim and newnum for qh->hull_dim and qh->num_points- projects points to newpoints- projects qh.lower_bound to itself- projects qh.upper_bound to itself- if qh->DELAUNAY- if qh->ATINFINITY- projects points to paraboloid- computes "infinity" point as vertex average and 10% above all points- else- uses qh_setdelaunay to project points to paraboloid-*/-void qh_projectinput(qhT *qh) {- int k,i;- int newdim= qh->input_dim, newnum= qh->num_points;- signed char *project;- int projectsize= (qh->input_dim+1)*sizeof(*project);- pointT *newpoints, *coord, *infinity;- realT paraboloid, maxboloid= 0;-- project= (signed char*)qh_memalloc(qh, projectsize);- memset((char*)project, 0, (size_t)projectsize);- for (k=0; k < qh->input_dim; k++) { /* skip Delaunay bound */- if (qh->lower_bound[k] == 0 && qh->upper_bound[k] == 0) {- project[k]= -1;- newdim--;- }- }- if (qh->DELAUNAY) {- project[k]= 1;- newdim++;- if (qh->ATinfinity)- newnum++;- }- if (newdim != qh->hull_dim) {- qh_memfree(qh, project, projectsize);- qh_fprintf(qh, qh->ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh->hull_dim);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- if (!(newpoints= qh->temp_malloc= (coordT*)qh_malloc(newnum*newdim*sizeof(coordT)))){- qh_memfree(qh, project, projectsize);- qh_fprintf(qh, qh->ferr, 6016, "qhull error: insufficient memory to project %d points\n",- qh->num_points);- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- /* qh_projectpoints throws error if mismatched dimensions */- qh_projectpoints(qh, project, qh->input_dim+1, qh->first_point,- qh->num_points, qh->input_dim, newpoints, newdim);- trace1((qh, qh->ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));- qh_projectpoints(qh, project, qh->input_dim+1, qh->lower_bound,- 1, qh->input_dim+1, qh->lower_bound, newdim+1);- qh_projectpoints(qh, project, qh->input_dim+1, qh->upper_bound,- 1, qh->input_dim+1, qh->upper_bound, newdim+1);- if (qh->HALFspace) {- if (!qh->feasible_point) {- qh_memfree(qh, project, projectsize);- qh_fprintf(qh, qh->ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- qh_projectpoints(qh, project, qh->input_dim, qh->feasible_point,- 1, qh->input_dim, qh->feasible_point, newdim);- }- qh_memfree(qh, project, projectsize);- if (qh->POINTSmalloc)- qh_free(qh->first_point);- qh->first_point= newpoints;- qh->POINTSmalloc= True;- qh->temp_malloc= NULL;- if (qh->DELAUNAY && qh->ATinfinity) {- coord= qh->first_point;- infinity= qh->first_point + qh->hull_dim * qh->num_points;- for (k=qh->hull_dim-1; k--; )- infinity[k]= 0.0;- for (i=qh->num_points; i--; ) {- paraboloid= 0.0;- for (k=0; k < qh->hull_dim-1; k++) {- paraboloid += *coord * *coord;- infinity[k] += *coord;- coord++;- }- *(coord++)= paraboloid;- maximize_(maxboloid, paraboloid);- }- /* coord == infinity */- for (k=qh->hull_dim-1; k--; )- *(coord++) /= qh->num_points;- *(coord++)= maxboloid * 1.1;- qh->num_points++;- trace0((qh, qh->ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));- }else if (qh->DELAUNAY) /* !qh->ATinfinity */- qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);-} /* projectinput */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="projectpoints">-</a>-- qh_projectpoints(qh, project, n, points, numpoints, dim, newpoints, newdim )- project points/numpoints/dim to newpoints/newdim- if project[k] == -1- delete dimension k- if project[k] == 1- add dimension k by duplicating previous column- n is size of project-- notes:- newpoints may be points if only adding dimension at end-- design:- check that 'project' and 'newdim' agree- for each dimension- if project == -1- skip dimension- else- determine start of column in newpoints- determine start of column in points- if project == +1, duplicate previous column- copy dimension (column) from points to newpoints-*/-void qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,- int numpoints, int dim, realT *newpoints, int newdim) {- int testdim= dim, oldk=0, newk=0, i,j=0,k;- realT *newp, *oldp;-- for (k=0; k < n; k++)- testdim += project[k];- if (testdim != newdim) {- qh_fprintf(qh, qh->ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",- newdim, testdim);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- for (j=0; j<n; j++) {- if (project[j] == -1)- oldk++;- else {- newp= newpoints+newk++;- if (project[j] == +1) {- if (oldk >= dim)- continue;- oldp= points+oldk;- }else- oldp= points+oldk++;- for (i=numpoints; i--; ) {- *newp= *oldp;- newp += newdim;- oldp += dim;- }- }- if (oldk >= dim)- break;- }- trace1((qh, qh->ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",- numpoints, dim, newdim));-} /* projectpoints */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="rotateinput">-</a>-- qh_rotateinput(qh, rows )- rotate input using row matrix- input points given by qh->first_point, num_points, hull_dim- assumes rows[dim] is a scratch buffer- if qh->POINTSmalloc, overwrites input points, else mallocs a new array-- returns:- rotated input- sets qh->POINTSmalloc-- design:- see qh_rotatepoints-*/-void qh_rotateinput(qhT *qh, realT **rows) {-- if (!qh->POINTSmalloc) {- qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);- qh->POINTSmalloc= True;- }- qh_rotatepoints(qh, qh->first_point, qh->num_points, qh->hull_dim, rows);-} /* rotateinput */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="rotatepoints">-</a>-- qh_rotatepoints(qh, points, numpoints, dim, row )- rotate numpoints points by a d-dim row matrix- assumes rows[dim] is a scratch buffer-- returns:- rotated points in place-- design:- for each point- for each coordinate- use row[dim] to compute partial inner product- for each coordinate- rotate by partial inner product-*/-void qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **row) {- realT *point, *rowi, *coord= NULL, sum, *newval;- int i,j,k;-- if (qh->IStracing >= 1)- qh_printmatrix(qh, qh->ferr, "qh_rotatepoints: rotate points by", row, dim, dim);- for (point= points, j= numpoints; j--; point += dim) {- newval= row[dim];- for (i=0; i < dim; i++) {- rowi= row[i];- coord= point;- for (sum= 0.0, k= dim; k--; )- sum += *rowi++ * *coord++;- *(newval++)= sum;- }- for (k=dim; k--; )- *(--coord)= *(--newval);- }-} /* rotatepoints */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="scaleinput">-</a>-- qh_scaleinput(qh)- scale input points using qh->low_bound/high_bound- input points given by qh->first_point, num_points, hull_dim- if qh->POINTSmalloc, overwrites input points, else mallocs a new array-- returns:- scales coordinates of points to low_bound[k], high_bound[k]- sets qh->POINTSmalloc-- design:- see qh_scalepoints-*/-void qh_scaleinput(qhT *qh) {-- if (!qh->POINTSmalloc) {- qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);- qh->POINTSmalloc= True;- }- qh_scalepoints(qh, qh->first_point, qh->num_points, qh->hull_dim,- qh->lower_bound, qh->upper_bound);-} /* scaleinput */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="scalelast">-</a>-- qh_scalelast(qh, points, numpoints, dim, low, high, newhigh )- scale last coordinate to [0,m] for Delaunay triangulations- input points given by points, numpoints, dim-- returns:- changes scale of last coordinate from [low, high] to [0, newhigh]- overwrites last coordinate of each point- saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()-- notes:- when called by qh_setdelaunay, low/high may not match actual data-- design:- compute scale and shift factors- apply to last coordinate of each point-*/-void qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,- coordT high, coordT newhigh) {- realT scale, shift;- coordT *coord;- int i;- boolT nearzero= False;-- trace4((qh, qh->ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",- low, high, newhigh));- qh->last_low= low;- qh->last_high= high;- qh->last_newhigh= newhigh;- scale= qh_divzero(newhigh, high - low,- qh->MINdenom_1, &nearzero);- if (nearzero) {- if (qh->DELAUNAY)- qh_fprintf(qh, qh->ferr, 6019, "qhull input error: can not scale last coordinate. Input is cocircular\n or cospherical. Use option 'Qz' to add a point at infinity.\n");- else- qh_fprintf(qh, qh->ferr, 6020, "qhull input error: can not scale last coordinate. New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",- newhigh, low, high, high-low);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- shift= - low * newhigh / (high-low);- coord= points + dim - 1;- for (i=numpoints; i--; coord += dim)- *coord= *coord * scale + shift;-} /* scalelast */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="scalepoints">-</a>-- qh_scalepoints(qh, points, numpoints, dim, newlows, newhighs )- scale points to new lowbound and highbound- retains old bound when newlow= -REALmax or newhigh= +REALmax-- returns:- scaled points- overwrites old points-- design:- for each coordinate- compute current low and high bound- compute scale and shift factors- scale all points- enforce new low and high bound for all points-*/-void qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,- realT *newlows, realT *newhighs) {- int i,k;- realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;- boolT nearzero= False;-- for (k=0; k < dim; k++) {- newhigh= newhighs[k];- newlow= newlows[k];- if (newhigh > REALmax/2 && newlow < -REALmax/2)- continue;- low= REALmax;- high= -REALmax;- for (i=numpoints, coord=points+k; i--; coord += dim) {- minimize_(low, *coord);- maximize_(high, *coord);- }- if (newhigh > REALmax/2)- newhigh= high;- if (newlow < -REALmax/2)- newlow= low;- if (qh->DELAUNAY && k == dim-1 && newhigh < newlow) {- qh_fprintf(qh, qh->ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",- k, k, newhigh, newlow);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- scale= qh_divzero(newhigh - newlow, high - low,- qh->MINdenom_1, &nearzero);- if (nearzero) {- qh_fprintf(qh, qh->ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",- k, newlow, newhigh, low, high);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- shift= (newlow * high - low * newhigh)/(high-low);- coord= points+k;- for (i=numpoints; i--; coord += dim)- *coord= *coord * scale + shift;- coord= points+k;- if (newlow < newhigh) {- mincoord= newlow;- maxcoord= newhigh;- }else {- mincoord= newhigh;- maxcoord= newlow;- }- for (i=numpoints; i--; coord += dim) {- minimize_(*coord, maxcoord); /* because of roundoff error */- maximize_(*coord, mincoord);- }- trace0((qh, qh->ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",- k, low, high, newlow, newhigh, numpoints, scale, shift));- }-} /* scalepoints */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="setdelaunay">-</a>-- qh_setdelaunay(qh, dim, count, points )- project count points to dim-d paraboloid for Delaunay triangulation-- dim is one more than the dimension of the input set- assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)-- points is a dim*count realT array. The first dim-1 coordinates- are the coordinates of the first input point. array[dim] is- the first coordinate of the second input point. array[2*dim] is- the first coordinate of the third input point.-- if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)- calls qh_scalelast to scale the last coordinate the same as the other points-- returns:- for each point- sets point[dim-1] to sum of squares of coordinates- scale points to 'Qbb' if needed-- notes:- to project one point, use- qh_setdelaunay(qh, qh->hull_dim, 1, point)-- Do not use options 'Qbk', 'QBk', or 'QbB' since they scale- the coordinates after the original projection.--*/-void qh_setdelaunay(qhT *qh, int dim, int count, pointT *points) {- int i, k;- coordT *coordp, coord;- realT paraboloid;-- trace0((qh, qh->ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));- coordp= points;- for (i=0; i < count; i++) {- coord= *coordp++;- paraboloid= coord*coord;- for (k=dim-2; k--; ) {- coord= *coordp++;- paraboloid += coord*coord;- }- *coordp++ = paraboloid;- }- if (qh->last_low < REALmax/2)- qh_scalelast(qh, points, count, dim, qh->last_low, qh->last_high, qh->last_newhigh);-} /* setdelaunay */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="sethalfspace">-</a>-- qh_sethalfspace(qh, dim, coords, nextp, normal, offset, feasible )- set point to dual of halfspace relative to feasible point- halfspace is normal coefficients and offset.-- returns:- false and prints error if feasible point is outside of hull- overwrites coordinates for point at dim coords- nextp= next point (coords)- does not call qh_errexit-- design:- compute distance from feasible point to halfspace- divide each normal coefficient by -dist-*/-boolT qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,- coordT *normal, coordT *offset, coordT *feasible) {- coordT *normp= normal, *feasiblep= feasible, *coordp= coords;- realT dist;- realT r; /*bug fix*/- int k;- boolT zerodiv;-- dist= *offset;- for (k=dim; k--; )- dist += *(normp++) * *(feasiblep++);- if (dist > 0)- goto LABELerroroutside;- normp= normal;- if (dist < -qh->MINdenom) {- for (k=dim; k--; )- *(coordp++)= *(normp++) / -dist;- }else {- for (k=dim; k--; ) {- *(coordp++)= qh_divzero(*(normp++), -dist, qh->MINdenom_1, &zerodiv);- if (zerodiv)- goto LABELerroroutside;- }- }- *nextp= coordp;- if (qh->IStracing >= 4) {- qh_fprintf(qh, qh->ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);- for (k=dim, coordp=coords; k--; ) {- r= *coordp++;- qh_fprintf(qh, qh->ferr, 8022, " %6.2g", r);- }- qh_fprintf(qh, qh->ferr, 8023, "\n");- }- return True;-LABELerroroutside:- feasiblep= feasible;- normp= normal;- qh_fprintf(qh, qh->ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");- for (k=dim; k--; )- qh_fprintf(qh, qh->ferr, 8024, qh_REAL_1, r=*(feasiblep++));- qh_fprintf(qh, qh->ferr, 8025, "\n halfspace: ");- for (k=dim; k--; )- qh_fprintf(qh, qh->ferr, 8026, qh_REAL_1, r=*(normp++));- qh_fprintf(qh, qh->ferr, 8027, "\n at offset: ");- qh_fprintf(qh, qh->ferr, 8028, qh_REAL_1, *offset);- qh_fprintf(qh, qh->ferr, 8029, " and distance: ");- qh_fprintf(qh, qh->ferr, 8030, qh_REAL_1, dist);- qh_fprintf(qh, qh->ferr, 8031, "\n");- return False;-} /* sethalfspace */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="sethalfspace_all">-</a>-- qh_sethalfspace_all(qh, dim, count, halfspaces, feasible )- generate dual for halfspace intersection with feasible point- array of count halfspaces- each halfspace is normal coefficients followed by offset- the origin is inside the halfspace if the offset is negative- feasible is a point inside all halfspaces (http://www.qhull.org/html/qhalf.htm#notes)-- returns:- malloc'd array of count X dim-1 points-- notes:- call before qh_init_B or qh_initqhull_globals- free memory when done- unused/untested code: please email bradb@shore.net if this works ok for you- if using option 'Fp', qh->feasible_point must be set (e.g., to 'feasible')- qh->feasible_point is a malloc'd array that is freed by qh_freebuffers.-- design:- see qh_sethalfspace-*/-coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible) {- int i, newdim;- pointT *newpoints;- coordT *coordp, *normalp, *offsetp;-- trace0((qh, qh->ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));- newdim= dim - 1;- if (!(newpoints=(coordT*)qh_malloc(count*newdim*sizeof(coordT)))){- qh_fprintf(qh, qh->ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",- count);- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- coordp= newpoints;- normalp= halfspaces;- for (i=0; i < count; i++) {- offsetp= normalp + newdim;- if (!qh_sethalfspace(qh, newdim, coordp, &coordp, normalp, offsetp, feasible)) {- qh_free(newpoints); /* feasible is not inside halfspace as reported by qh_sethalfspace */- qh_fprintf(qh, qh->ferr, 8032, "The halfspace was at index %d\n", i);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- normalp= offsetp + 1;- }- return newpoints;-} /* sethalfspace_all */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="sharpnewfacets">-</a>-- qh_sharpnewfacets(qh)-- returns:- true if could be an acute angle (facets in different quadrants)-- notes:- for qh_findbest-- design:- for all facets on qh.newfacet_list- if two facets are in different quadrants- set issharp-*/-boolT qh_sharpnewfacets(qhT *qh) {- facetT *facet;- boolT issharp = False;- int *quadrant, k;-- quadrant= (int*)qh_memalloc(qh, qh->hull_dim * sizeof(int));- FORALLfacet_(qh->newfacet_list) {- if (facet == qh->newfacet_list) {- for (k=qh->hull_dim; k--; )- quadrant[ k]= (facet->normal[ k] > 0);- }else {- for (k=qh->hull_dim; k--; ) {- if (quadrant[ k] != (facet->normal[ k] > 0)) {- issharp= True;- break;- }- }- }- if (issharp)- break;- }- qh_memfree(qh, quadrant, qh->hull_dim * sizeof(int));- trace3((qh, qh->ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));- return issharp;-} /* sharpnewfacets */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="voronoi_center">-</a>-- qh_voronoi_center(qh, dim, points )- return Voronoi center for a set of points- dim is the orginal dimension of the points- gh.gm_matrix/qh.gm_row are scratch buffers-- returns:- center as a temporary point (qh_memalloc)- if non-simplicial,- returns center for max simplex of points-- notes:- only called by qh_facetcenter- from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65-- design:- if non-simplicial- determine max simplex for points- translate point0 of simplex to origin- compute sum of squares of diagonal- compute determinate- compute Voronoi center (see Bowyer & Woodwark)-*/-pointT *qh_voronoi_center(qhT *qh, int dim, setT *points) {- pointT *point, **pointp, *point0;- pointT *center= (pointT*)qh_memalloc(qh, qh->center_size);- setT *simplex;- int i, j, k, size= qh_setsize(qh, points);- coordT *gmcoord;- realT *diffp, sum2, *sum2row, *sum2p, det, factor;- boolT nearzero, infinite;-- if (size == dim+1)- simplex= points;- else if (size < dim+1) {- qh_memfree(qh, center, qh->center_size);- qh_fprintf(qh, qh->ferr, 6025, "qhull internal error (qh_voronoi_center):\n need at least %d points to construct a Voronoi center\n",- dim+1);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- simplex= points; /* never executed -- avoids warning */- }else {- simplex= qh_settemp(qh, dim+1);- qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);- }- point0= SETfirstt_(simplex, pointT);- gmcoord= qh->gm_matrix;- for (k=0; k < dim; k++) {- qh->gm_row[k]= gmcoord;- FOREACHpoint_(simplex) {- if (point != point0)- *(gmcoord++)= point[k] - point0[k];- }- }- sum2row= gmcoord;- for (i=0; i < dim; i++) {- sum2= 0.0;- for (k=0; k < dim; k++) {- diffp= qh->gm_row[k] + i;- sum2 += *diffp * *diffp;- }- *(gmcoord++)= sum2;- }- det= qh_determinant(qh, qh->gm_row, dim, &nearzero);- factor= qh_divzero(0.5, det, qh->MINdenom, &infinite);- if (infinite) {- for (k=dim; k--; )- center[k]= qh_INFINITE;- if (qh->IStracing)- qh_printpoints(qh, qh->ferr, "qh_voronoi_center: at infinity for ", simplex);- }else {- for (i=0; i < dim; i++) {- gmcoord= qh->gm_matrix;- sum2p= sum2row;- for (k=0; k < dim; k++) {- qh->gm_row[k]= gmcoord;- if (k == i) {- for (j=dim; j--; )- *(gmcoord++)= *sum2p++;- }else {- FOREACHpoint_(simplex) {- if (point != point0)- *(gmcoord++)= point[k] - point0[k];- }- }- }- center[i]= qh_determinant(qh, qh->gm_row, dim, &nearzero)*factor + point0[i];- }-#ifndef qh_NOtrace- if (qh->IStracing >= 3) {- qh_fprintf(qh, qh->ferr, 8033, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);- qh_printmatrix(qh, qh->ferr, "center:", ¢er, 1, dim);- if (qh->IStracing >= 5) {- qh_printpoints(qh, qh->ferr, "points", simplex);- FOREACHpoint_(simplex)- qh_fprintf(qh, qh->ferr, 8034, "p%d dist %.2g, ", qh_pointid(qh, point),- qh_pointdist(point, center, dim));- qh_fprintf(qh, qh->ferr, 8035, "\n");- }- }-#endif- }- if (simplex != points)- qh_settempfree(qh, &simplex);- return center;-} /* voronoi_center */-
− C/geom_r.c
@@ -1,1234 +0,0 @@-/*<html><pre> -<a href="qh-geom_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- geom_r.c- geometric routines of qhull-- see qh-geom_r.htm and geom_r.h-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/geom_r.c#2 $$Change: 1995 $- $DateTime: 2015/10/13 21:59:42 $$Author: bbarber $-- infrequent code goes into geom2_r.c-*/--#include "qhull_ra.h"--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="distplane">-</a>-- qh_distplane(qh, point, facet, dist )- return distance from point to facet-- returns:- dist- if qh.RANDOMdist, joggles result-- notes:- dist > 0 if point is above facet (i.e., outside)- does not error (for qh_sortfacets, qh_outerinner)-- see:- qh_distnorm in geom2_r.c- qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies-*/-void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {- coordT *normal= facet->normal, *coordp, randr;- int k;-- switch (qh->hull_dim){- case 2:- *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];- break;- case 3:- *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];- break;- case 4:- *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];- break;- case 5:- *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];- break;- case 6:- *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];- break;- case 7:- *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];- break;- case 8:- *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];- break;- default:- *dist= facet->offset;- coordp= point;- for (k=qh->hull_dim; k--; )- *dist += *coordp++ * *normal++;- break;- }- zinc_(Zdistplane);- if (!qh->RANDOMdist && qh->IStracing < 4)- return;- if (qh->RANDOMdist) {- randr= qh_RANDOMint;- *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *- qh->RANDOMfactor * qh->MAXabs_coord;- }- if (qh->IStracing >= 4) {- qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");- qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);- qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);- }- return;-} /* distplane */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="findbest">-</a>-- qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )- find facet that is furthest below a point- for upperDelaunay facets- returns facet only if !qh_NOupper and clearly above-- input:- starts search at 'startfacet' (can not be flipped)- if !bestoutside(qh_ALL), stops at qh.MINoutside-- returns:- best facet (reports error if NULL)- early out if isoutside defined and bestdist > qh.MINoutside- dist is distance to facet- isoutside is true if point is outside of facet- numpart counts the number of distance tests-- see also:- qh_findbestnew()-- notes:- If merging (testhorizon), searches horizon facets of coplanar best facets because- after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d- avoid calls to distplane, function calls, and real number operations.- caller traces result- Optimized for outside points. Tried recording a search set for qh_findhorizon.- Made code more complicated.-- when called by qh_partitionvisible():- indicated by qh_ISnewfacets- qh.newfacet_list is list of simplicial, new facets- qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)- qh.bestfacet_notsharp set if qh_sharpnewfacets returns False-- when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),- qh_check_bestdist(), qh_addpoint()- indicated by !qh_ISnewfacets- returns best facet in neighborhood of given facet- this is best facet overall if dist > - qh.MAXcoplanar- or hull has at least a "spherical" curvature-- design:- initialize and test for early exit- repeat while there are better facets- for each neighbor of facet- exit if outside facet found- test for better facet- if point is inside and partitioning- test for new facets with a "sharp" intersection- if so, future calls go to qh_findbestnew()- test horizon facets-*/-facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,- boolT bestoutside, boolT isnewfacets, boolT noupper,- realT *dist, boolT *isoutside, int *numpart) {- realT bestdist= -REALmax/2 /* avoid underflow */;- facetT *facet, *neighbor, **neighborp;- facetT *bestfacet= NULL, *lastfacet= NULL;- int oldtrace= qh->IStracing;- unsigned int visitid= ++qh->visit_id;- int numpartnew=0;- boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */-- zinc_(Zfindbest);- if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {- if (qh->TRACElevel > qh->IStracing)- qh->IStracing= qh->TRACElevel;- qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",- qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);- qh_fprintf(qh, qh->ferr, 8005, " testhorizon? %d noupper? %d", testhorizon, noupper);- qh_fprintf(qh, qh->ferr, 8006, " Last point added was p%d.", qh->furthest_id);- qh_fprintf(qh, qh->ferr, 8007, " Last merge was #%d. max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);- }- if (isoutside)- *isoutside= True;- if (!startfacet->flipped) { /* test startfacet */- *numpart= 1;- qh_distplane(qh, point, startfacet, dist); /* this code is duplicated below */- if (!bestoutside && *dist >= qh->MINoutside- && (!startfacet->upperdelaunay || !noupper)) {- bestfacet= startfacet;- goto LABELreturn_best;- }- bestdist= *dist;- if (!startfacet->upperdelaunay) {- bestfacet= startfacet;- }- }else- *numpart= 0;- startfacet->visitid= visitid;- facet= startfacet;- while (facet) {- trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",- facet->id, bestdist, getid_(bestfacet)));- lastfacet= facet;- FOREACHneighbor_(facet) {- if (!neighbor->newfacet && isnewfacets)- continue;- if (neighbor->visitid == visitid)- continue;- neighbor->visitid= visitid;- if (!neighbor->flipped) { /* code duplicated above */- (*numpart)++;- qh_distplane(qh, point, neighbor, dist);- if (*dist > bestdist) {- if (!bestoutside && *dist >= qh->MINoutside- && (!neighbor->upperdelaunay || !noupper)) {- bestfacet= neighbor;- goto LABELreturn_best;- }- if (!neighbor->upperdelaunay) {- bestfacet= neighbor;- bestdist= *dist;- break; /* switch to neighbor */- }else if (!bestfacet) {- bestdist= *dist;- break; /* switch to neighbor */- }- } /* end of *dist>bestdist */- } /* end of !flipped */- } /* end of FOREACHneighbor */- facet= neighbor; /* non-NULL only if *dist>bestdist */- } /* end of while facet (directed search) */- if (isnewfacets) {- if (!bestfacet) {- bestdist= -REALmax/2;- bestfacet= qh_findbestnew(qh, point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);- testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */- }else if (!qh->findbest_notsharp && bestdist < - qh->DISTround) {- if (qh_sharpnewfacets(qh)) {- /* seldom used, qh_findbestnew will retest all facets */- zinc_(Zfindnewsharp);- bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);- testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */- qh->findbestnew= True;- }else- qh->findbest_notsharp= True;- }- }- if (!bestfacet)- bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart);- if (testhorizon)- bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);- *dist= bestdist;- if (isoutside && bestdist < qh->MINoutside)- *isoutside= False;-LABELreturn_best:- zadd_(Zfindbesttot, *numpart);- zmax_(Zfindbestmax, *numpart);- (*numpart) += numpartnew;- qh->IStracing= oldtrace;- return bestfacet;-} /* findbest */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="findbesthorizon">-</a>-- qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )- search coplanar and better horizon facets from startfacet/bestdist- ischeckmax turns off statistics and minsearch update- all arguments must be initialized- returns(ischeckmax):- best facet- returns(!ischeckmax):- best facet that is not upperdelaunay- allows upperdelaunay that is clearly outside- returns:- bestdist is distance to bestfacet- numpart -- updates number of distance tests-- notes:- no early out -- use qh_findbest() or qh_findbestnew()- Searches coplanar or better horizon facets-- when called by qh_check_maxout() (qh_IScheckmax)- startfacet must be closest to the point- Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum- even though other facets are below the point.- updates facet->maxoutside for good, visited facets- may return NULL-- searchdist is qh.max_outside + 2 * DISTround- + max( MINvisible('Vn'), MAXcoplanar('Un'));- This setting is a guess. It must be at least max_outside + 2*DISTround- because a facet may have a geometric neighbor across a vertex-- design:- for each horizon facet of coplanar best facets- continue if clearly inside- unless upperdelaunay or clearly outside- update best facet-*/-facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {- facetT *bestfacet= startfacet;- realT dist;- facetT *neighbor, **neighborp, *facet;- facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */- int numpartinit= *numpart, coplanarfacetset_size;- unsigned int visitid= ++qh->visit_id;- boolT newbest= False; /* for tracing */- realT minsearch, searchdist; /* skip facets that are too far from point */-- if (!ischeckmax) {- zinc_(Zfindhorizon);- }else {-#if qh_MAXoutside- if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)- startfacet->maxoutside= *bestdist;-#endif- }- searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */- minsearch= *bestdist - searchdist;- if (ischeckmax) {- /* Always check coplanar facets. Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */- minimize_(minsearch, -searchdist);- }- coplanarfacetset_size= 0;- facet= startfacet;- while (True) {- trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n",- facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,- minsearch, searchdist));- FOREACHneighbor_(facet) {- if (neighbor->visitid == visitid)- continue;- neighbor->visitid= visitid;- if (!neighbor->flipped) {- qh_distplane(qh, point, neighbor, &dist);- (*numpart)++;- if (dist > *bestdist) {- if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {- bestfacet= neighbor;- *bestdist= dist;- newbest= True;- if (!ischeckmax) {- minsearch= dist - searchdist;- if (dist > *bestdist + searchdist) {- zinc_(Zfindjump); /* everything in qh.coplanarfacetset at least searchdist below */- coplanarfacetset_size= 0;- }- }- }- }else if (dist < minsearch)- continue; /* if ischeckmax, dist can't be positive */-#if qh_MAXoutside- if (ischeckmax && dist > neighbor->maxoutside)- neighbor->maxoutside= dist;-#endif- } /* end of !flipped */- if (nextfacet) {- if (!coplanarfacetset_size++) {- SETfirst_(qh->coplanarfacetset)= nextfacet;- SETtruncate_(qh->coplanarfacetset, 1);- }else- qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv- and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv */- }- nextfacet= neighbor;- } /* end of EACHneighbor */- facet= nextfacet;- if (facet)- nextfacet= NULL;- else if (!coplanarfacetset_size)- break;- else if (!--coplanarfacetset_size) {- facet= SETfirstt_(qh->coplanarfacetset, facetT);- SETtruncate_(qh->coplanarfacetset, 0);- }else- facet= (facetT*)qh_setdellast(qh->coplanarfacetset);- } /* while True, for each facet in qh.coplanarfacetset */- if (!ischeckmax) {- zadd_(Zfindhorizontot, *numpart - numpartinit);- zmax_(Zfindhorizonmax, *numpart - numpartinit);- if (newbest)- zinc_(Zparthorizon);- }- trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));- return bestfacet;-} /* findbesthorizon */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="findbestnew">-</a>-- qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )- find best newfacet for point- searches all of qh.newfacet_list starting at startfacet- searches horizon facets of coplanar best newfacets- searches all facets if startfacet == qh.facet_list- returns:- best new or horizon facet that is not upperdelaunay- early out if isoutside and not 'Qf'- dist is distance to facet- isoutside is true if point is outside of facet- numpart is number of distance tests-- notes:- Always used for merged new facets (see qh_USEfindbestnew)- Avoids upperdelaunay facet unless (isoutside and outside)-- Uses qh.visit_id, qh.coplanarfacetset.- If share visit_id with qh_findbest, coplanarfacetset is incorrect.-- If merging (testhorizon), searches horizon facets of coplanar best facets because- a point maybe coplanar to the bestfacet, below its horizon facet,- and above a horizon facet of a coplanar newfacet. For example,- rbox 1000 s Z1 G1e-13 | qhull- rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc-- qh_findbestnew() used if- qh_sharpnewfacets -- newfacets contains a sharp angle- if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)-- see also:- qh_partitionall() and qh_findbest()-- design:- for each new facet starting from startfacet- test distance from point to facet- return facet if clearly outside- unless upperdelaunay and a lowerdelaunay exists- update best facet- test horizon facets-*/-facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,- realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {- realT bestdist= -REALmax/2;- facetT *bestfacet= NULL, *facet;- int oldtrace= qh->IStracing, i;- unsigned int visitid= ++qh->visit_id;- realT distoutside= 0.0;- boolT isdistoutside; /* True if distoutside is defined */- boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */-- if (!startfacet) {- if (qh->MERGING)- qh_fprintf(qh, qh->ferr, 6001, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets. Can not continue.\n");- else- qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",- qh->furthest_id);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- zinc_(Zfindnew);- if (qh->BESToutside || bestoutside)- isdistoutside= False;- else {- isdistoutside= True;- distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */- }- if (isoutside)- *isoutside= True;- *numpart= 0;- if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {- if (qh->TRACElevel > qh->IStracing)- qh->IStracing= qh->TRACElevel;- qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",- qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);- qh_fprintf(qh, qh->ferr, 8009, " Last point added p%d visitid %d.", qh->furthest_id, visitid);- qh_fprintf(qh, qh->ferr, 8010, " Last merge was #%d.\n", zzval_(Ztotmerge));- }- /* visit all new facets starting with startfacet, maybe qh->facet_list */- for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {- FORALLfacet_(facet) {- if (facet == startfacet && i)- break;- facet->visitid= visitid;- if (!facet->flipped) {- qh_distplane(qh, point, facet, dist);- (*numpart)++;- if (*dist > bestdist) {- if (!facet->upperdelaunay || *dist >= qh->MINoutside) {- bestfacet= facet;- if (isdistoutside && *dist >= distoutside)- goto LABELreturn_bestnew;- bestdist= *dist;- }- }- } /* end of !flipped */- } /* FORALLfacet from startfacet or qh->newfacet_list */- }- if (testhorizon || !bestfacet) /* testhorizon is always True. Keep the same code as qh_findbest */- bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,- !qh_NOupper, &bestdist, numpart);- *dist= bestdist;- if (isoutside && *dist < qh->MINoutside)- *isoutside= False;-LABELreturn_bestnew:- zadd_(Zfindnewtot, *numpart);- zmax_(Zfindnewmax, *numpart);- trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));- qh->IStracing= oldtrace;- return bestfacet;-} /* findbestnew */--/* ============ hyperplane functions -- keep code together [?] ============ */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="backnormal">-</a>-- qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )- given an upper-triangular rows array and a sign,- solve for normal equation x using back substitution over rows U-- returns:- normal= x-- if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),- if fails on last row- this means that the hyperplane intersects [0,..,1]- sets last coordinate of normal to sign- otherwise- sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]- sets nearzero-- notes:- assumes numrow == numcol-1-- see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"-- solves Ux=b where Ax=b and PA=LU- b= [0,...,0,sign or 0] (sign is either -1 or +1)- last row of A= [0,...,0,1]-- 1) Ly=Pb == y=b since P only permutes the 0's of b-- design:- for each row from end- perform back substitution- if near zero- use qh_divzero for division- if zero divide and not last row- set tail of normal to 0-*/-void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,- coordT *normal, boolT *nearzero) {- int i, j;- coordT *normalp, *normal_tail, *ai, *ak;- realT diagonal;- boolT waszero;- int zerocol= -1;-- normalp= normal + numcol - 1;- *normalp--= (sign ? -1.0 : 1.0);- for (i=numrow; i--; ) {- *normalp= 0.0;- ai= rows[i] + i + 1;- ak= normalp+1;- for (j=i+1; j < numcol; j++)- *normalp -= *ai++ * *ak++;- diagonal= (rows[i])[i];- if (fabs_(diagonal) > qh->MINdenom_2)- *(normalp--) /= diagonal;- else {- waszero= False;- *normalp= qh_divzero(*normalp, diagonal, qh->MINdenom_1_2, &waszero);- if (waszero) {- zerocol= i;- *(normalp--)= (sign ? -1.0 : 1.0);- for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)- *normal_tail= 0.0;- }else- normalp--;- }- }- if (zerocol != -1) {- zzinc_(Zback0);- *nearzero= True;- trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));- qh_precision(qh, "zero diagonal on back substitution");- }-} /* backnormal */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="gausselim">-</a>-- qh_gausselim(qh, rows, numrow, numcol, sign )- Gaussian elimination with partial pivoting-- returns:- rows is upper triangular (includes row exchanges)- flips sign for each row exchange- sets nearzero if pivot[k] < qh.NEARzero[k], else clears it-- notes:- if nearzero, the determinant's sign may be incorrect.- assumes numrow <= numcol-- design:- for each row- determine pivot and exchange rows if necessary- test for near zero- perform gaussian elimination step-*/-void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {- realT *ai, *ak, *rowp, *pivotrow;- realT n, pivot, pivot_abs= 0.0, temp;- int i, j, k, pivoti, flip=0;-- *nearzero= False;- for (k=0; k < numrow; k++) {- pivot_abs= fabs_((rows[k])[k]);- pivoti= k;- for (i=k+1; i < numrow; i++) {- if ((temp= fabs_((rows[i])[k])) > pivot_abs) {- pivot_abs= temp;- pivoti= i;- }- }- if (pivoti != k) {- rowp= rows[pivoti];- rows[pivoti]= rows[k];- rows[k]= rowp;- *sign ^= 1;- flip ^= 1;- }- if (pivot_abs <= qh->NEARzero[k]) {- *nearzero= True;- if (pivot_abs == 0.0) { /* remainder of column == 0 */- if (qh->IStracing >= 4) {- qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);- qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);- }- zzinc_(Zgauss0);- qh_precision(qh, "zero pivot for Gaussian elimination");- goto LABELnextcol;- }- }- pivotrow= rows[k] + k;- pivot= *pivotrow++; /* signed value of pivot, and remainder of row */- for (i=k+1; i < numrow; i++) {- ai= rows[i] + k;- ak= pivotrow;- n= (*ai++)/pivot; /* divzero() not needed since |pivot| >= |*ai| */- for (j= numcol - (k+1); j--; )- *ai++ -= n * *ak++;- }- LABELnextcol:- ;- }- wmin_(Wmindenom, pivot_abs); /* last pivot element */- if (qh->IStracing >= 5)- qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);-} /* gausselim */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="getangle">-</a>-- qh_getangle(qh, vect1, vect2 )- returns the dot product of two vectors- if qh.RANDOMdist, joggles result-- notes:- the angle may be > 1.0 or < -1.0 because of roundoff errors--*/-realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {- realT angle= 0, randr;- int k;-- for (k=qh->hull_dim; k--; )- angle += *vect1++ * *vect2++;- if (qh->RANDOMdist) {- randr= qh_RANDOMint;- angle += (2.0 * randr / qh_RANDOMmax - 1.0) *- qh->RANDOMfactor;- }- trace4((qh, qh->ferr, 4006, "qh_getangle: %2.2g\n", angle));- return(angle);-} /* getangle */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="getcenter">-</a>-- qh_getcenter(qh, vertices )- returns arithmetic center of a set of vertices as a new point-- notes:- allocates point array for center-*/-pointT *qh_getcenter(qhT *qh, setT *vertices) {- int k;- pointT *center, *coord;- vertexT *vertex, **vertexp;- int count= qh_setsize(qh, vertices);-- if (count < 2) {- qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- center= (pointT *)qh_memalloc(qh, qh->normal_size);- for (k=0; k < qh->hull_dim; k++) {- coord= center+k;- *coord= 0.0;- FOREACHvertex_(vertices)- *coord += vertex->point[k];- *coord /= count; /* count>=2 by QH6003 */- }- return(center);-} /* getcenter */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="getcentrum">-</a>-- qh_getcentrum(qh, facet )- returns the centrum for a facet as a new point-- notes:- allocates the centrum-*/-pointT *qh_getcentrum(qhT *qh, facetT *facet) {- realT dist;- pointT *centrum, *point;-- point= qh_getcenter(qh, facet->vertices);- zzinc_(Zcentrumtests);- qh_distplane(qh, point, facet, &dist);- centrum= qh_projectpoint(qh, point, facet, dist);- qh_memfree(qh, point, qh->normal_size);- trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",- facet->id, qh_setsize(qh, facet->vertices), dist));- return centrum;-} /* getcentrum */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="getdistance">-</a>-- qh_getdistance(qh, facet, neighbor, mindist, maxdist )- returns the maxdist and mindist distance of any vertex from neighbor-- returns:- the max absolute value-- design:- for each vertex of facet that is not in neighbor- test the distance from vertex to neighbor-*/-realT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {- vertexT *vertex, **vertexp;- realT dist, maxd, mind;-- FOREACHvertex_(facet->vertices)- vertex->seen= False;- FOREACHvertex_(neighbor->vertices)- vertex->seen= True;- mind= 0.0;- maxd= 0.0;- FOREACHvertex_(facet->vertices) {- if (!vertex->seen) {- zzinc_(Zbestdist);- qh_distplane(qh, vertex->point, neighbor, &dist);- if (dist < mind)- mind= dist;- else if (dist > maxd)- maxd= dist;- }- }- *mindist= mind;- *maxdist= maxd;- mind= -mind;- if (maxd > mind)- return maxd;- else- return mind;-} /* getdistance */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="normalize">-</a>-- qh_normalize(qh, normal, dim, toporient )- normalize a vector and report if too small- does not use min norm-- see:- qh_normalize2-*/-void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {- qh_normalize2(qh, normal, dim, toporient, NULL, NULL);-} /* normalize */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="normalize2">-</a>-- qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )- normalize a vector and report if too small- qh.MINdenom/MINdenom1 are the upper limits for divide overflow-- returns:- normalized vector- flips sign if !toporient- if minnorm non-NULL,- sets ismin if normal < minnorm-- notes:- if zero norm- sets all elements to sqrt(1.0/dim)- if divide by zero (divzero())- sets largest element to +/-1- bumps Znearlysingular-- design:- computes norm- test for minnorm- if not near zero- normalizes normal- else if zero norm- sets normal to standard value- else- uses qh_divzero to normalize- if nearzero- sets norm to direction of maximum value-*/-void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,- realT *minnorm, boolT *ismin) {- int k;- realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;- boolT zerodiv;-- norm1= normal+1;- norm2= normal+2;- norm3= normal+3;- if (dim == 2)- norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));- else if (dim == 3)- norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));- else if (dim == 4) {- norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)- + (*norm3)*(*norm3));- }else if (dim > 4) {- norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)- + (*norm3)*(*norm3);- for (k=dim-4, colp=normal+4; k--; colp++)- norm += (*colp) * (*colp);- norm= sqrt(norm);- }- if (minnorm) {- if (norm < *minnorm)- *ismin= True;- else- *ismin= False;- }- wmin_(Wmindenom, norm);- if (norm > qh->MINdenom) {- if (!toporient)- norm= -norm;- *normal /= norm;- *norm1 /= norm;- if (dim == 2)- ; /* all done */- else if (dim == 3)- *norm2 /= norm;- else if (dim == 4) {- *norm2 /= norm;- *norm3 /= norm;- }else if (dim >4) {- *norm2 /= norm;- *norm3 /= norm;- for (k=dim-4, colp=normal+4; k--; )- *colp++ /= norm;- }- }else if (norm == 0.0) {- temp= sqrt(1.0/dim);- for (k=dim, colp=normal; k--; )- *colp++ = temp;- }else {- if (!toporient)- norm= -norm;- for (k=dim, colp=normal; k--; colp++) { /* k used below */- temp= qh_divzero(*colp, norm, qh->MINdenom_1, &zerodiv);- if (!zerodiv)- *colp= temp;- else {- maxp= qh_maxabsval(normal, dim);- temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);- for (k=dim, colp=normal; k--; colp++)- *colp= 0.0;- *maxp= temp;- zzinc_(Znearlysingular);- trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",- norm, qh->furthest_id));- return;- }- }- }-} /* normalize */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="projectpoint">-</a>-- qh_projectpoint(qh, point, facet, dist )- project point onto a facet by dist-- returns:- returns a new point-- notes:- if dist= distplane(point,facet)- this projects point to hyperplane- assumes qh_memfree_() is valid for normal_size-*/-pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {- pointT *newpoint, *np, *normal;- int normsize= qh->normal_size;- int k;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */-- qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);- np= newpoint;- normal= facet->normal;- for (k=qh->hull_dim; k--; )- *(np++)= *point++ - dist * *normal++;- return(newpoint);-} /* projectpoint */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="setfacetplane">-</a>-- qh_setfacetplane(qh, facet )- sets the hyperplane for a facet- if qh.RANDOMdist, joggles hyperplane-- notes:- uses global buffers qh.gm_matrix and qh.gm_row- overwrites facet->normal if already defined- updates Wnewvertex if PRINTstatistics- sets facet->upperdelaunay if upper envelope of Delaunay triangulation-- design:- copy vertex coordinates to qh.gm_matrix/gm_row- compute determinate- if nearzero- recompute determinate with gaussian elimination- if nearzero- force outside orientation by testing interior point-*/-void qh_setfacetplane(qhT *qh, facetT *facet) {- pointT *point;- vertexT *vertex, **vertexp;- int normsize= qh->normal_size;- int k,i, oldtrace= 0;- realT dist;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */- coordT *coord, *gmcoord;- pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;- boolT nearzero= False;-- zzinc_(Zsetplane);- if (!facet->normal)- qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);- if (facet == qh->tracefacet) {- oldtrace= qh->IStracing;- qh->IStracing= 5;- qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);- qh_fprintf(qh, qh->ferr, 8013, " Last point added to hull was p%d.", qh->furthest_id);- if (zzval_(Ztotmerge))- qh_fprintf(qh, qh->ferr, 8014, " Last merge was #%d.", zzval_(Ztotmerge));- qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");- qh_printsummary(qh, qh->ferr);- }- if (qh->hull_dim <= 4) {- i= 0;- if (qh->RANDOMdist) {- gmcoord= qh->gm_matrix;- FOREACHvertex_(facet->vertices) {- qh->gm_row[i++]= gmcoord;- coord= vertex->point;- for (k=qh->hull_dim; k--; )- *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);- }- }else {- FOREACHvertex_(facet->vertices)- qh->gm_row[i++]= vertex->point;- }- qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,- facet->normal, &facet->offset, &nearzero);- }- if (qh->hull_dim > 4 || nearzero) {- i= 0;- gmcoord= qh->gm_matrix;- FOREACHvertex_(facet->vertices) {- if (vertex->point != point0) {- qh->gm_row[i++]= gmcoord;- coord= vertex->point;- point= point0;- for (k=qh->hull_dim; k--; )- *(gmcoord++)= *coord++ - *point++;- }- }- qh->gm_row[i]= gmcoord; /* for areasimplex */- if (qh->RANDOMdist) {- gmcoord= qh->gm_matrix;- for (i=qh->hull_dim-1; i--; ) {- for (k=qh->hull_dim; k--; )- *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);- }- }- qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,- facet->normal, &facet->offset, &nearzero);- if (nearzero) {- if (qh_orientoutside(qh, facet)) {- trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh->furthest_id));- /* this is part of using Gaussian Elimination. For example in 5-d- 1 1 1 1 0- 1 1 1 1 1- 0 0 0 1 0- 0 1 0 0 0- 1 0 0 0 0- norm= 0.38 0.38 -0.76 0.38 0- has a determinate of 1, but g.e. after subtracting pt. 0 has- 0's in the diagonal, even with full pivoting. It does work- if you subtract pt. 4 instead. */- }- }- }- facet->upperdelaunay= False;- if (qh->DELAUNAY) {- if (qh->UPPERdelaunay) { /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */- if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)- facet->upperdelaunay= True;- }else {- if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)- facet->upperdelaunay= True;- }- }- if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- FOREACHvertex_(facet->vertices) {- if (vertex->point != point0) {- boolT istrace= False;- zinc_(Zdiststat);- qh_distplane(qh, vertex->point, facet, &dist);- dist= fabs_(dist);- zinc_(Znewvertex);- wadd_(Wnewvertex, dist);- if (dist > wwval_(Wnewvertexmax)) {- wwval_(Wnewvertexmax)= dist;- if (dist > qh->max_outside) {- qh->max_outside= dist; /* used by qh_maxouter(qh) */- if (dist > qh->TRACEdist)- istrace= True;- }- }else if (-dist > qh->TRACEdist)- istrace= True;- if (istrace) {- qh_fprintf(qh, qh->ferr, 8016, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",- qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);- qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);- }- }- }- qh->RANDOMdist= qh->old_randomdist;- }- if (qh->IStracing >= 3) {- qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",- facet->id, facet->offset);- for (k=0; k < qh->hull_dim; k++)- qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);- qh_fprintf(qh, qh->ferr, 8019, "\n");- }- if (facet == qh->tracefacet)- qh->IStracing= oldtrace;-} /* setfacetplane */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="sethyperplane_det">-</a>-- qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )- given dim X dim array indexed by rows[], one row per point,- toporient(flips all signs),- and point0 (any row)- set normalized hyperplane equation from oriented simplex-- returns:- normal (normalized)- offset (places point0 on the hyperplane)- sets nearzero if hyperplane not through points-- notes:- only defined for dim == 2..4- rows[] is not modified- solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane- see Bower & Woodworth, A programmer's geometry, Butterworths 1983.-- derivation of 3-d minnorm- Goal: all vertices V_i within qh.one_merge of hyperplane- Plan: exactly translate the facet so that V_0 is the origin- exactly rotate the facet so that V_1 is on the x-axis and y_2=0.- exactly rotate the effective perturbation to only effect n_0- this introduces a factor of sqrt(3)- n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm- Let M_d be the max coordinate difference- Let M_a be the greater of M_d and the max abs. coordinate- Let u be machine roundoff and distround be max error for distance computation- The max error for n_0 is sqrt(3) u M_a M_d / norm. n_1 is approx. 1 and n_2 is approx. 0- The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm. Offset=0 at origin- Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge- Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d-- derivation of 4-d minnorm- same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0- [if two vertices fixed on x-axis, can rotate the other two in yzw.]- n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3- [all other terms contain at least two factors nearly zero.]- The max error for n_0 is sqrt(4) u M_a M_d M_d / norm- Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge- Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d-*/-void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,- boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {- realT maxround, dist;- int i;- pointT *point;--- if (dim == 2) {- normal[0]= dY(1,0);- normal[1]= dX(0,1);- qh_normalize2(qh, normal, dim, toporient, NULL, NULL);- *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);- *nearzero= False; /* since nearzero norm => incident points */- }else if (dim == 3) {- normal[0]= det2_(dY(2,0), dZ(2,0),- dY(1,0), dZ(1,0));- normal[1]= det2_(dX(1,0), dZ(1,0),- dX(2,0), dZ(2,0));- normal[2]= det2_(dX(2,0), dY(2,0),- dX(1,0), dY(1,0));- qh_normalize2(qh, normal, dim, toporient, NULL, NULL);- *offset= -(point0[0]*normal[0] + point0[1]*normal[1]- + point0[2]*normal[2]);- maxround= qh->DISTround;- for (i=dim; i--; ) {- point= rows[i];- if (point != point0) {- dist= *offset + (point[0]*normal[0] + point[1]*normal[1]- + point[2]*normal[2]);- if (dist > maxround || dist < -maxround) {- *nearzero= True;- break;- }- }- }- }else if (dim == 4) {- normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),- dY(1,0), dZ(1,0), dW(1,0),- dY(3,0), dZ(3,0), dW(3,0));- normal[1]= det3_(dX(2,0), dZ(2,0), dW(2,0),- dX(1,0), dZ(1,0), dW(1,0),- dX(3,0), dZ(3,0), dW(3,0));- normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),- dX(1,0), dY(1,0), dW(1,0),- dX(3,0), dY(3,0), dW(3,0));- normal[3]= det3_(dX(2,0), dY(2,0), dZ(2,0),- dX(1,0), dY(1,0), dZ(1,0),- dX(3,0), dY(3,0), dZ(3,0));- qh_normalize2(qh, normal, dim, toporient, NULL, NULL);- *offset= -(point0[0]*normal[0] + point0[1]*normal[1]- + point0[2]*normal[2] + point0[3]*normal[3]);- maxround= qh->DISTround;- for (i=dim; i--; ) {- point= rows[i];- if (point != point0) {- dist= *offset + (point[0]*normal[0] + point[1]*normal[1]- + point[2]*normal[2] + point[3]*normal[3]);- if (dist > maxround || dist < -maxround) {- *nearzero= True;- break;- }- }- }- }- if (*nearzero) {- zzinc_(Zminnorm);- trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh->furthest_id));- zzinc_(Znearlysingular);- }-} /* sethyperplane_det */---/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="sethyperplane_gauss">-</a>-- qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )- given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)- set normalized hyperplane equation from oriented simplex-- returns:- normal (normalized)- offset (places point0 on the hyperplane)-- notes:- if nearzero- orientation may be incorrect because of incorrect sign flips in gausselim- solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]- or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]- i.e., N is normal to the hyperplane, and the unnormalized- distance to [0 .. 1] is either 1 or 0-- design:- perform gaussian elimination- flip sign for negative values- perform back substitution- normalize result- compute offset-*/-void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,- boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {- coordT *pointcoord, *normalcoef;- int k;- boolT sign= toporient, nearzero2= False;-- qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);- for (k=dim-1; k--; ) {- if ((rows[k])[k] < 0)- sign ^= 1;- }- if (*nearzero) {- zzinc_(Znearlysingular);- trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));- qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);- }else {- qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);- if (nearzero2) {- zzinc_(Znearlysingular);- trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));- }- }- if (nearzero2)- *nearzero= True;- qh_normalize2(qh, normal, dim, True, NULL, NULL);- pointcoord= point0;- normalcoef= normal;- *offset= -(*pointcoord++ * *normalcoef++);- for (k=dim-1; k--; )- *offset -= *pointcoord++ * *normalcoef++;-} /* sethyperplane_gauss */---
− C/global_r.c
@@ -1,2100 +0,0 @@--/*<html><pre> -<a href="qh-globa_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- global_r.c- initializes all the globals of the qhull application-- see README-- see libqhull_r.h for qh.globals and function prototypes-- see qhull_ra.h for internal functions-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/global_r.c#16 $$Change: 2066 $- $DateTime: 2016/01/18 19:29:17 $$Author: bbarber $- */--#include "qhull_ra.h"--/*========= qh->definition -- globals defined in libqhull_r.h =======================*/--/*-<a href ="qh-globa_r.htm#TOC"- >--------------------------------</a><a name="qh_version">-</a>-- qh_version- version string by year and date- qh_version2 for Unix users and -V-- the revision increases on code changes only-- notes:- change date: Changes.txt, Announce.txt, index.htm, README.txt,- qhull-news.html, Eudora signatures, CMakeLists.txt- change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt- check that CmakeLists @version is the same as qh_version2- change year: Copying.txt- check download size- 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-*/--const char qh_version[]= "2015.2.r 2016/01/18";-const char qh_version2[]= "qhull_r 7.2.0 (2015.2.r 2016/01/18)";--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="appendprint">-</a>-- qh_appendprint(qh, printFormat )- append printFormat to qh.PRINTout unless already defined-*/-void qh_appendprint(qhT *qh, 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_r.htm#TOC"- >-------------------------------</a><a name="checkflags">-</a>-- qh_checkflags(qh, commandStr, hiddenFlags )- errors if commandStr contains hiddenFlags- hiddenFlags starts and ends with a space and is space delimited (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(qhT *qh, char *command, char *hiddenflags) {- char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */- char key, opt, prevopt;- char chkkey[]= " ";- char chkopt[]= " ";- char chkopt2[]= " ";- boolT waserr= False;-- if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {- qh_fprintf(qh, qh->ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (strpbrk(hiddenflags, ",\n\r\t")) {- qh_fprintf(qh, qh->ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);- qh_errexit(qh, 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 == 'T' && (*s == 'I' || *s == 'O')) { /* TI or TO 'file name' */- s= qh_skipfilename(qh, ++s);- 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]= '\'';- 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);- waserr= True;- }- }- if (waserr)- qh_errexit(qh, qh_ERRinput, NULL, NULL);-} /* checkflags */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="qh_clear_outputflags">-</a>-- qh_clear_outputflags(qh)- Clear output flags for QhullPoints-*/-void qh_clear_outputflags(qhT *qh) {- int i,k;-- qh->ANNOTATEoutput= False;- qh->DOintersections= False;- qh->DROPdim= -1;- qh->FORCEoutput= False;- qh->GETarea= False;- qh->GOODpoint= 0;- qh->GOODpointp= NULL;- qh->GOODthreshold= False;- qh->GOODvertex= 0;- qh->GOODvertexp= NULL;- qh->IStracing= 0;- qh->KEEParea= False;- qh->KEEPmerge= False;- qh->KEEPminArea= REALmax;- qh->PRINTcentrums= False;- qh->PRINTcoplanar= False;- qh->PRINTdots= False;- qh->PRINTgood= False;- qh->PRINTinner= False;- qh->PRINTneighbors= False;- qh->PRINTnoplanes= False;- qh->PRINToptions1st= False;- qh->PRINTouter= False;- qh->PRINTprecision= True;- qh->PRINTridges= False;- qh->PRINTspheres= False;- qh->PRINTstatistics= False;- qh->PRINTsummary= False;- qh->PRINTtransparent= False;- qh->SPLITthresholds= False;- qh->TRACElevel= 0;- qh->TRInormals= False;- qh->USEstdout= False;- qh->VERIFYoutput= False;- for (k=qh->input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */- qh->lower_threshold[k]= -REALmax;- qh->upper_threshold[k]= REALmax;- qh->lower_bound[k]= -REALmax;- qh->upper_bound[k]= REALmax;- }-- for (i=0; i < qh_PRINTEND; i++) {- qh->PRINTout[i]= qh_PRINTnone;- }-- if (!qh->qhull_commandsiz2)- qh->qhull_commandsiz2= (int)strlen(qh->qhull_command); /* WARN64 */- else {- qh->qhull_command[qh->qhull_commandsiz2]= '\0';- }- if (!qh->qhull_optionsiz2)- qh->qhull_optionsiz2= (int)strlen(qh->qhull_options); /* WARN64 */- else {- qh->qhull_options[qh->qhull_optionsiz2]= '\0';- qh->qhull_optionlen= qh_OPTIONline; /* start a new line */- }-} /* clear_outputflags */--/*-<a href="qh-globa_r.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(qhT *qh) {--#if (qh_CLOCKtype == 2)- struct tms time;- static long clktck; /* initialized first call and never updated */- double ratio, cpu;- unsigned long ticks;-- if (!clktck) {- if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {- qh_fprintf(qh, qh->ferr, 6030, "qhull internal error (qh_clock): sysconf() failed. Use qh_CLOCKtype 1 in user.h\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- }- if (times(&time) == -1) {- qh_fprintf(qh, qh->ferr, 6031, "qhull internal error (qh_clock): times() failed. Use qh_CLOCKtype 1 in user.h\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- ratio= qh_SECticks / (double)clktck;- ticks= time.tms_utime * ratio;- return ticks;-#else- qh_fprintf(qh, qh->ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* never returns */- return 0;-#endif-} /* clock */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="freebuffers">-</a>-- qh_freebuffers()- free up global memory buffers-- notes:- must match qh_initbuffers()-*/-void qh_freebuffers(qhT *qh) {-- trace5((qh, qh->ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));- /* allocated by qh_initqhull_buffers */- qh_memfree(qh, qh->NEARzero, qh->hull_dim * sizeof(realT));- qh_memfree(qh, qh->lower_threshold, (qh->input_dim+1) * sizeof(realT));- qh_memfree(qh, qh->upper_threshold, (qh->input_dim+1) * sizeof(realT));- qh_memfree(qh, qh->lower_bound, (qh->input_dim+1) * sizeof(realT));- qh_memfree(qh, qh->upper_bound, (qh->input_dim+1) * sizeof(realT));- qh_memfree(qh, qh->gm_matrix, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));- qh_memfree(qh, 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, &qh->other_points);- qh_setfree(qh, &qh->del_vertices);- qh_setfree(qh, &qh->coplanarfacetset);- if (qh->line) /* allocated by qh_readinput, freed if no error */- qh_free(qh->line);- if (qh->half_space)- qh_free(qh->half_space);- if (qh->temp_malloc)- qh_free(qh->temp_malloc);- if (qh->feasible_point) /* allocated by qh_readfeasible */- qh_free(qh->feasible_point);- if (qh->feasible_string) /* allocated by qh_initflags */- qh_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) {- qh_free(qh->first_point);- qh->first_point= NULL;- }- if (qh->input_points && qh->input_malloc) { /* set by qh_joggleinput */- qh_free(qh->input_points);- qh->input_points= NULL;- }- trace5((qh, qh->ferr, 5002, "qh_freebuffers: finished\n"));-} /* freebuffers */---/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="freebuild">-</a>-- qh_freebuild(qh, allmem )- free global memory used by qh_initbuild and qh_buildhull- if !allmem,- does not free short memory (e.g., facetT, 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(qhT *qh, boolT allmem) {- facetT *facet;- vertexT *vertex;- ridgeT *ridge, **ridgep;- mergeT *merge, **mergep;-- trace1((qh, qh->ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));- if (qh->del_vertices)- qh_settruncate(qh, qh->del_vertices, 0);- if (allmem) {- while ((vertex= qh->vertex_list)) {- if (vertex->next)- qh_delvertex(qh, vertex);- else {- qh_memfree(qh, vertex, (int)sizeof(vertexT));- qh->newvertex_list= qh->vertex_list= NULL;- }- }- }else if (qh->VERTEXneighbors) {- FORALLvertices- qh_setfreelong(qh, &(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(qh, &(ridge->vertices));- qh_memfree(qh, ridge, (int)sizeof(ridgeT));- }else- ridge->seen= True;- }- qh_setfree(qh, &(facet->outsideset));- qh_setfree(qh, &(facet->coplanarset));- qh_setfree(qh, &(facet->neighbors));- qh_setfree(qh, &(facet->ridges));- qh_setfree(qh, &(facet->vertices));- if (facet->next)- qh_delfacet(qh, facet);- else {- qh_memfree(qh, facet, (int)sizeof(facetT));- qh->visible_list= qh->newfacet_list= qh->facet_list= NULL;- }- }- }else {- FORALLfacets {- qh_setfreelong(qh, &(facet->outsideset));- qh_setfreelong(qh, &(facet->coplanarset));- if (!facet->simplicial) {- qh_setfreelong(qh, &(facet->neighbors));- qh_setfreelong(qh, &(facet->ridges));- qh_setfreelong(qh, &(facet->vertices));- }- }- }- qh_setfree(qh, &(qh->hash_table));- qh_memfree(qh, qh->interior_point, qh->normal_size);- qh->interior_point= NULL;- FOREACHmerge_(qh->facet_mergeset) /* usually empty */- qh_memfree(qh, merge, (int)sizeof(mergeT));- qh->facet_mergeset= NULL; /* temp set */- qh->degen_mergeset= NULL; /* temp set */- qh_settempfree_all(qh);-} /* freebuild */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="freeqhull">-</a>-- qh_freeqhull(qh, allmem )-- free global memory and set qhT to 0- if !allmem,- does not free short memory (freed by qh_memfreeshort unless qh_NOmem)--notes:- sets qh.NOerrexit in case caller forgets to- Does not throw errors--see:- see qh_initqhull_start2()- For libqhull_r, qhstatT is part of qhT--design:- free global and temporary memory from qh_initbuild and qh_buildhull- free buffers-*/-void qh_freeqhull(qhT *qh, boolT allmem) {-- qh->NOerrexit= True; /* no more setjmp since called at exit and ~QhullQh */- trace1((qh, qh->ferr, 1006, "qh_freeqhull: free global memory\n"));- qh_freebuild(qh, allmem);- qh_freebuffers(qh);- /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */- memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));- qh->NOerrexit= True;-} /* freeqhull2 */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="init_A">-</a>-- qh_init_A(qh, 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(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {- qh_meminit(qh, errfile);- qh_initqhull_start(qh, infile, outfile, errfile);- qh_init_qhull_command(qh, argc, argv);-} /* init_A */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="init_B">-</a>-- qh_init_B(qh, 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 qh_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(qh)-- 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(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {- qh_initqhull_globals(qh, points, numpoints, dim, ismalloc);- if (qh->qhmem.LASTsize == 0)- qh_initqhull_mem(qh);- /* mem_r.c and qset_r.c are initialized */- qh_initqhull_buffers(qh);- qh_initthresholds(qh, qh->qhull_command);- if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay))- qh_projectinput(qh);- if (qh->SCALEinput)- qh_scaleinput(qh);- if (qh->ROTATErandom >= 0) {- qh_randommatrix(qh, 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, qh->hull_dim, qh->gm_row);- qh_rotateinput(qh, qh->gm_row);- }-} /* init_B */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="init_qhull_command">-</a>-- qh_init_qhull_command(qh, argc, argv )- build qh.qhull_command from argc/argv- Calls qh_exit if qhull_command is too short-- returns:- a space-delimited 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(qhT *qh, int argc, char *argv[]) {-- if (!qh_argv_to_command(argc, argv, qh->qhull_command, (int)sizeof(qh->qhull_command))){- /* Assumes qh.ferr is defined. */- qh_fprintf(qh, qh->ferr, 6033, "qhull input error: more than %d characters in command line.\n",- (int)sizeof(qh->qhull_command));- qh_exit(qh_ERRinput); /* error reported, can not use qh_errexit */- }-} /* init_qhull_command */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initflags">-</a>-- qh_initflags(qh, commandStr )- set flags and initialized constants from commandStr- calls qh_exit() if qh->NOerrexit-- 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_r.c for documentation-- design:- for each space-delimited option group- if top-level option- check syntax- append appropriate option to option string- set appropriate global variable or append printFormat to print options- else- for each sub-option- check syntax- append appropriate option to option string- set appropriate global variable or append printFormat to print options-*/-void qh_initflags(qhT *qh, char *command) {- int k, i, lastproject;- char *s= command, *t, *prev_s, *start, key;- boolT isgeom= False, wasproject;- realT r;-- if(qh->NOerrexit){- 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.");- qh_exit(6245);- }- if (command <= &qh->qhull_command[0] || command > &qh->qhull_command[0] + sizeof(qh->qhull_command)) {- if (command != &qh->qhull_command[0]) {- *qh->qhull_command= '\0';- strncat(qh->qhull_command, command, sizeof(qh->qhull_command)-strlen(qh->qhull_command)-1);- }- 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(qh, "delaunay", NULL, NULL);- qh->DELAUNAY= True;- break;- case 'f':- qh_option(qh, "facets", NULL, NULL);- qh_appendprint(qh, qh_PRINTfacets);- break;- case 'i':- qh_option(qh, "incidence", NULL, NULL);- qh_appendprint(qh, qh_PRINTincidences);- break;- case 'm':- qh_option(qh, "mathematica", NULL, NULL);- qh_appendprint(qh, qh_PRINTmathematica);- break;- case 'n':- qh_option(qh, "normals", NULL, NULL);- qh_appendprint(qh, qh_PRINTnormals);- break;- case 'o':- qh_option(qh, "offFile", NULL, NULL);- qh_appendprint(qh, qh_PRINToff);- break;- case 'p':- qh_option(qh, "points", NULL, NULL);- qh_appendprint(qh, qh_PRINTpoints);- break;- case 's':- qh_option(qh, "summary", NULL, NULL);- qh->PRINTsummary= True;- break;- case 'v':- qh_option(qh, "voronoi", NULL, NULL);- qh->VORONOI= True;- qh->DELAUNAY= True;- break;- case 'A':- if (!isdigit(*s) && *s != '.' && *s != '-')- qh_fprintf(qh, qh->ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'. Ignored.\n");- else {- if (*s == '-') {- qh->premerge_cos= -qh_strtod(s, &s);- qh_option(qh, "Angle-premerge-", NULL, &qh->premerge_cos);- qh->PREmerge= True;- }else {- qh->postmerge_cos= qh_strtod(s, &s);- qh_option(qh, "Angle-postmerge", NULL, &qh->postmerge_cos);- qh->POSTmerge= True;- }- qh->MERGING= True;- }- break;- case 'C':- if (!isdigit(*s) && *s != '.' && *s != '-')- qh_fprintf(qh, qh->ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'. Ignored.\n");- else {- if (*s == '-') {- qh->premerge_centrum= -qh_strtod(s, &s);- qh_option(qh, "Centrum-premerge-", NULL, &qh->premerge_centrum);- qh->PREmerge= True;- }else {- qh->postmerge_centrum= qh_strtod(s, &s);- qh_option(qh, "Centrum-postmerge", NULL, &qh->postmerge_centrum);- qh->POSTmerge= True;- }- qh->MERGING= True;- }- break;- case 'E':- if (*s == '-')- qh_fprintf(qh, qh->ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'. Ignored.\n");- else if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'. Ignored.\n");- else {- qh->DISTround= qh_strtod(s, &s);- qh_option(qh, "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- qh_fprintf(qh, qh->ferr, 7006, "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((size_t)(t-start+1), (size_t)1))) {- qh_fprintf(qh, qh->ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- strncpy(qh->feasible_string, start, (size_t)(t-start));- qh_option(qh, "Halfspace-about", NULL, NULL);- qh_option(qh, qh->feasible_string, NULL, NULL);- }else- qh_option(qh, "Halfspace", NULL, NULL);- break;- case 'R':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'. Ignored\n");- else {- qh->RANDOMfactor= qh_strtod(s, &s);- qh_option(qh, "Random_perturb", NULL, &qh->RANDOMfactor);- qh->RANDOMdist= True;- }- break;- case 'V':- if (!isdigit(*s) && *s != '-')- qh_fprintf(qh, qh->ferr, 7008, "qhull warning: missing visible distance for option 'Vn'. Ignored\n");- else {- qh->MINvisible= qh_strtod(s, &s);- qh_option(qh, "Visible", NULL, &qh->MINvisible);- }- break;- case 'U':- if (!isdigit(*s) && *s != '-')- qh_fprintf(qh, qh->ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'. Ignored\n");- else {- qh->MAXcoplanar= qh_strtod(s, &s);- qh_option(qh, "U-coplanar", NULL, &qh->MAXcoplanar);- }- break;- case 'W':- if (*s == '-')- qh_fprintf(qh, qh->ferr, 7010, "qhull warning: negative outside width for option 'Wn'. Ignored.\n");- else if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7011, "qhull warning: missing outside width for option 'Wn'. Ignored\n");- else {- qh->MINoutside= qh_strtod(s, &s);- qh_option(qh, "W-outside", NULL, &qh->MINoutside);- qh->APPROXhull= True;- }- break;- /************ sub menus ***************/- case 'F':- while (*s && !isspace(*s)) {- switch (*s++) {- case 'a':- qh_option(qh, "Farea", NULL, NULL);- qh_appendprint(qh, qh_PRINTarea);- qh->GETarea= True;- break;- case 'A':- qh_option(qh, "FArea-total", NULL, NULL);- qh->GETarea= True;- break;- case 'c':- qh_option(qh, "Fcoplanars", NULL, NULL);- qh_appendprint(qh, qh_PRINTcoplanars);- break;- case 'C':- qh_option(qh, "FCentrums", NULL, NULL);- qh_appendprint(qh, qh_PRINTcentrums);- break;- case 'd':- qh_option(qh, "Fd-cdd-in", NULL, NULL);- qh->CDDinput= True;- break;- case 'D':- qh_option(qh, "FD-cdd-out", NULL, NULL);- qh->CDDoutput= True;- break;- case 'F':- qh_option(qh, "FFacets-xridge", NULL, NULL);- qh_appendprint(qh, qh_PRINTfacets_xridge);- break;- case 'i':- qh_option(qh, "Finner", NULL, NULL);- qh_appendprint(qh, qh_PRINTinner);- break;- case 'I':- qh_option(qh, "FIDs", NULL, NULL);- qh_appendprint(qh, qh_PRINTids);- break;- case 'm':- qh_option(qh, "Fmerges", NULL, NULL);- qh_appendprint(qh, qh_PRINTmerges);- break;- case 'M':- qh_option(qh, "FMaple", NULL, NULL);- qh_appendprint(qh, qh_PRINTmaple);- break;- case 'n':- qh_option(qh, "Fneighbors", NULL, NULL);- qh_appendprint(qh, qh_PRINTneighbors);- break;- case 'N':- qh_option(qh, "FNeighbors-vertex", NULL, NULL);- qh_appendprint(qh, qh_PRINTvneighbors);- break;- case 'o':- qh_option(qh, "Fouter", NULL, NULL);- qh_appendprint(qh, qh_PRINTouter);- break;- case 'O':- if (qh->PRINToptions1st) {- qh_option(qh, "FOptions", NULL, NULL);- qh_appendprint(qh, qh_PRINToptions);- }else- qh->PRINToptions1st= True;- break;- case 'p':- qh_option(qh, "Fpoint-intersect", NULL, NULL);- qh_appendprint(qh, qh_PRINTpointintersect);- break;- case 'P':- qh_option(qh, "FPoint-nearest", NULL, NULL);- qh_appendprint(qh, qh_PRINTpointnearest);- break;- case 'Q':- qh_option(qh, "FQhull", NULL, NULL);- qh_appendprint(qh, qh_PRINTqhull);- break;- case 's':- qh_option(qh, "Fsummary", NULL, NULL);- qh_appendprint(qh, qh_PRINTsummary);- break;- case 'S':- qh_option(qh, "FSize", NULL, NULL);- qh_appendprint(qh, qh_PRINTsize);- qh->GETarea= True;- break;- case 't':- qh_option(qh, "Ftriangles", NULL, NULL);- qh_appendprint(qh, qh_PRINTtriangles);- break;- case 'v':- /* option set in qh_initqhull_globals */- qh_appendprint(qh, qh_PRINTvertices);- break;- case 'V':- qh_option(qh, "FVertex-average", NULL, NULL);- qh_appendprint(qh, qh_PRINTaverage);- break;- case 'x':- qh_option(qh, "Fxtremes", NULL, NULL);- qh_appendprint(qh, qh_PRINTextremes);- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7012, "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, qh_PRINTgeom);- while (*s && !isspace(*s)) {- switch (*s++) {- case 'a':- qh_option(qh, "Gall-points", NULL, NULL);- qh->PRINTdots= True;- break;- case 'c':- qh_option(qh, "Gcentrums", NULL, NULL);- qh->PRINTcentrums= True;- break;- case 'h':- qh_option(qh, "Gintersections", NULL, NULL);- qh->DOintersections= True;- break;- case 'i':- qh_option(qh, "Ginner", NULL, NULL);- qh->PRINTinner= True;- break;- case 'n':- qh_option(qh, "Gno-planes", NULL, NULL);- qh->PRINTnoplanes= True;- break;- case 'o':- qh_option(qh, "Gouter", NULL, NULL);- qh->PRINTouter= True;- break;- case 'p':- qh_option(qh, "Gpoints", NULL, NULL);- qh->PRINTcoplanar= True;- break;- case 'r':- qh_option(qh, "Gridges", NULL, NULL);- qh->PRINTridges= True;- break;- case 't':- qh_option(qh, "Gtransparent", NULL, NULL);- qh->PRINTtransparent= True;- break;- case 'v':- qh_option(qh, "Gvertices", NULL, NULL);- qh->PRINTspheres= True;- break;- case 'D':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n");- else {- if (qh->DROPdim >= 0)- qh_fprintf(qh, qh->ferr, 7013, "qhull warning: can only drop one dimension. Previous 'GD%d' ignored\n",- qh->DROPdim);- qh->DROPdim= qh_strtol(s, &s);- qh_option(qh, "GDrop-dim", &qh->DROPdim, NULL);- }- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7014, "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(qh, "Pdrop-facets-dim-less", &i, &r);- else- qh_option(qh, "PDrop-facets-dim-more", &i, &r);- break;- case 'g':- qh_option(qh, "Pgood-facets", NULL, NULL);- qh->PRINTgood= True;- break;- case 'G':- qh_option(qh, "PGood-facet-neighbors", NULL, NULL);- qh->PRINTneighbors= True;- break;- case 'o':- qh_option(qh, "Poutput-forced", NULL, NULL);- qh->FORCEoutput= True;- break;- case 'p':- qh_option(qh, "Pprecision-ignore", NULL, NULL);- qh->PRINTprecision= False;- break;- case 'A':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n");- else {- qh->KEEParea= qh_strtol(s, &s);- qh_option(qh, "PArea-keep", &qh->KEEParea, NULL);- qh->GETarea= True;- }- break;- case 'F':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n");- else {- qh->KEEPminArea= qh_strtod(s, &s);- qh_option(qh, "PFacet-area-keep", NULL, &qh->KEEPminArea);- qh->GETarea= True;- }- break;- case 'M':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n");- else {- qh->KEEPmerge= qh_strtol(s, &s);- qh_option(qh, "PMerge-keep", &qh->KEEPmerge, NULL);- }- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7015, "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(qh, "QbBound-unit-box", NULL, &r);- break;- }- if (key == 'b' && *s == 'b') {- s++;- qh->SCALElast= True;- qh_option(qh, "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, qh->ferr, 2004, "qh_initflags: project dimension %d\n", k));- qh_option(qh, "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(qh, "Qbound-dim-low", &k, &r);- }else {- qh->SCALEinput= True;- if (r == 0.0)- r= qh_DEFAULTbox;- qh_option(qh, "QBound-dim-high", &k, &r);- }- }- break;- case 'c':- qh_option(qh, "Qcoplanar-keep", NULL, NULL);- qh->KEEPcoplanar= True;- break;- case 'f':- qh_option(qh, "Qfurthest-outside", NULL, NULL);- qh->BESToutside= True;- break;- case 'g':- qh_option(qh, "Qgood-facets-only", NULL, NULL);- qh->ONLYgood= True;- break;- case 'i':- qh_option(qh, "Qinterior-keep", NULL, NULL);- qh->KEEPinside= True;- break;- case 'm':- qh_option(qh, "Qmax-outside-only", NULL, NULL);- qh->ONLYmax= True;- break;- case 'r':- qh_option(qh, "Qrandom-outside", NULL, NULL);- qh->RANDOMoutside= True;- break;- case 's':- qh_option(qh, "Qsearch-initial-simplex", NULL, NULL);- qh->ALLpoints= True;- break;- case 't':- qh_option(qh, "Qtriangulate", NULL, NULL);- qh->TRIangulate= True;- break;- case 'T':- qh_option(qh, "QTestPoints", NULL, NULL);- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n");- else {- qh->TESTpoints= qh_strtol(s, &s);- qh_option(qh, "QTestPoints", &qh->TESTpoints, NULL);- }- break;- case 'u':- qh_option(qh, "QupperDelaunay", NULL, NULL);- qh->UPPERdelaunay= True;- break;- case 'v':- qh_option(qh, "Qvertex-neighbors-convex", NULL, NULL);- qh->TESTvneighbors= True;- break;- case 'x':- qh_option(qh, "Qxact-merge", NULL, NULL);- qh->MERGEexact= True;- break;- case 'z':- qh_option(qh, "Qz-infinity-point", NULL, NULL);- qh->ATinfinity= True;- break;- case '0':- qh_option(qh, "Q0-no-premerge", NULL, NULL);- qh->NOpremerge= True;- break;- case '1':- if (!isdigit(*s)) {- qh_option(qh, "Q1-no-angle-sort", NULL, NULL);- qh->ANGLEmerge= False;- break;- }- switch (*s++) {- case '0':- qh_option(qh, "Q10-no-narrow", NULL, NULL);- qh->NOnarrow= True;- break;- case '1':- qh_option(qh, "Q11-trinormals Qtriangulate", NULL, NULL);- qh->TRInormals= True;- qh->TRIangulate= True;- break;- case '2':- qh_option(qh, "Q12-no-wide-dup", NULL, NULL);- qh->NOwide= True;- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);- while (*++s && !isspace(*s));- break;- }- break;- case '2':- qh_option(qh, "Q2-no-merge-independent", NULL, NULL);- qh->MERGEindependent= False;- goto LABELcheckdigit;- break; /* no warnings */- case '3':- qh_option(qh, "Q3-no-merge-vertices", NULL, NULL);- qh->MERGEvertices= False;- LABELcheckdigit:- if (isdigit(*s))- qh_fprintf(qh, qh->ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit. '%c' skipped.\n",- *s++);- break;- case '4':- qh_option(qh, "Q4-avoid-old-into-new", NULL, NULL);- qh->AVOIDold= True;- break;- case '5':- qh_option(qh, "Q5-no-check-outer", NULL, NULL);- qh->SKIPcheckmax= True;- break;- case '6':- qh_option(qh, "Q6-no-concave-merge", NULL, NULL);- qh->SKIPconvex= True;- break;- case '7':- qh_option(qh, "Q7-no-breadth-first", NULL, NULL);- qh->VIRTUALmemory= True;- break;- case '8':- qh_option(qh, "Q8-no-near-inside", NULL, NULL);- qh->NOnearinside= True;- break;- case '9':- qh_option(qh, "Q9-pick-furthest", NULL, NULL);- qh->PICKfurthest= True;- break;- case 'G':- i= qh_strtol(s, &t);- if (qh->GOODpoint)- qh_fprintf(qh, qh->ferr, 7018, "qhull warning: good point already defined for option 'QGn'. Ignored\n");- else if (s == t)- qh_fprintf(qh, qh->ferr, 7019, "qhull warning: missing good point id for option 'QGn'. Ignored\n");- else if (i < 0 || *s == '-') {- qh->GOODpoint= i-1;- qh_option(qh, "QGood-if-dont-see-point", &i, NULL);- }else {- qh->GOODpoint= i+1;- qh_option(qh, "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(qh, "QJoggle", NULL, &qh->JOGGLEmax);- }- break;- case 'R':- if (!isdigit(*s) && *s != '-')- qh_fprintf(qh, qh->ferr, 7020, "qhull warning: missing random seed for option 'QRn'. Ignored\n");- else {- qh->ROTATErandom= i= qh_strtol(s, &s);- if (i > 0)- qh_option(qh, "QRotate-id", &i, NULL );- else if (i < -1)- qh_option(qh, "QRandom-seed", &i, NULL );- }- break;- case 'V':- i= qh_strtol(s, &t);- if (qh->GOODvertex)- qh_fprintf(qh, qh->ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'. Ignored\n");- else if (s == t)- qh_fprintf(qh, qh->ferr, 7022, "qhull warning: no good point id given for option 'QVn'. Ignored\n");- else if (i < 0) {- qh->GOODvertex= i - 1;- qh_option(qh, "QV-good-facets-not-point", &i, NULL);- }else {- qh_option(qh, "QV-good-facets-point", &i, NULL);- qh->GOODvertex= i + 1;- }- s= t;- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7023, "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 'a':- qh_option(qh, "Tannotate-output", NULL, NULL);- qh->ANNOTATEoutput= True;- break;- case 'c':- qh_option(qh, "Tcheck-frequently", NULL, NULL);- qh->CHECKfrequently= True;- break;- case 's':- qh_option(qh, "Tstatistics", NULL, NULL);- qh->PRINTstatistics= True;- break;- case 'v':- qh_option(qh, "Tverify", NULL, NULL);- qh->VERIFYoutput= True;- break;- case 'z':- if (qh->ferr == qh_FILEstderr) {- /* The C++ interface captures the output in qh_fprint_qhull() */- qh_option(qh, "Tz-stdout", NULL, NULL);- qh->USEstdout= True;- }else if (!qh->fout)- qh_fprintf(qh, qh->ferr, 7024, "qhull warning: output file undefined(stdout). Option 'Tz' ignored.\n");- else {- qh_option(qh, "Tz-stdout", NULL, NULL);- qh->USEstdout= True;- qh->ferr= qh->fout;- qh->qhmem.ferr= qh->fout;- }- break;- case 'C':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'. Ignored\n");- else {- i= qh_strtol(s, &s);- qh_option(qh, "TCone-stop", &i, NULL);- qh->STOPcone= i + 1;- }- break;- case 'F':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'. Ignored\n");- else {- qh->REPORTfreq= qh_strtol(s, &s);- qh_option(qh, "TFacet-log", &qh->REPORTfreq, NULL);- qh->REPORTfreq2= qh->REPORTfreq/2; /* for tracemerging() */- }- break;- case 'I':- if (!isspace(*s))- qh_fprintf(qh, qh->ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s);- while (isspace(*s))- s++;- t= qh_skipfilename(qh, s);- {- char filename[qh_FILENAMElen];-- qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */- s= t;- if (!freopen(filename, "r", stdin)) {- qh_fprintf(qh, qh->ferr, 6041, "qhull error: could not open file \"%s\".", filename);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }else {- qh_option(qh, "TInput-file", NULL, NULL);- qh_option(qh, filename, NULL, NULL);- }- }- break;- case 'O':- if (!isspace(*s))- qh_fprintf(qh, qh->ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s);- while (isspace(*s))- s++;- t= qh_skipfilename(qh, s);- {- char filename[qh_FILENAMElen];-- qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */- s= t;- if (!qh->fout) {- 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");- }else if (!freopen(filename, "w", qh->fout)) {- qh_fprintf(qh, qh->ferr, 6044, "qhull error: could not open file \"%s\".", filename);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }else {- qh_option(qh, "TOutput-file", NULL, NULL);- qh_option(qh, filename, NULL, NULL);- }- }- break;- case 'P':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7029, "qhull warning: missing point id for trace option 'TPn'. Ignored\n");- else {- qh->TRACEpoint= qh_strtol(s, &s);- qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);- }- break;- case 'M':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'. Ignored\n");- else {- qh->TRACEmerge= qh_strtol(s, &s);- qh_option(qh, "Trace-merge", &qh->TRACEmerge, NULL);- }- break;- case 'R':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'. Ignored\n");- else {- qh->RERUN= qh_strtol(s, &s);- qh_option(qh, "TRerun", &qh->RERUN, NULL);- }- break;- case 'V':- i= qh_strtol(s, &t);- if (s == t)- qh_fprintf(qh, qh->ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'. Ignored\n");- else if (i < 0) {- qh->STOPpoint= i - 1;- qh_option(qh, "TV-stop-before-point", &i, NULL);- }else {- qh->STOPpoint= i + 1;- qh_option(qh, "TV-stop-after-point", &i, NULL);- }- s= t;- break;- case 'W':- if (!isdigit(*s))- qh_fprintf(qh, qh->ferr, 7033, "qhull warning: missing max width for trace option 'TWn'. Ignored\n");- else {- qh->TRACEdist= (realT) qh_strtod(s, &s);- qh_option(qh, "TWide-trace", NULL, &qh->TRACEdist);- }- break;- default:- s--;- qh_fprintf(qh, qh->ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);- while (*++s && !isspace(*s));- break;- }- }- break;- default:- qh_fprintf(qh, qh->ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1],- (int)s[-1]);- break;- }- if (s-1 == prev_s && *s && !isspace(*s)) {- qh_fprintf(qh, qh->ferr, 7036, "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 (qh->STOPcone && qh->JOGGLEmax < REALmax/2)- qh_fprintf(qh, qh->ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");- if (isgeom && !qh->FORCEoutput && qh->PRINTout[1])- qh_fprintf(qh, qh->ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n");- /* set derived values in qh_initqhull_globals */-} /* initflags */---/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_buffers">-</a>-- qh_initqhull_buffers(qh)- initialize global memory buffers-- notes:- must match qh_freebuffers()-*/-void qh_initqhull_buffers(qhT *qh) {- int k;-- qh->TEMPsize= (qh->qhmem.LASTsize - sizeof(setT))/SETelemsize;- if (qh->TEMPsize <= 0 || qh->TEMPsize > qh->qhmem.LASTsize)- qh->TEMPsize= 8; /* e.g., if qh_NOmem */- qh->other_points= qh_setnew(qh, qh->TEMPsize);- qh->del_vertices= qh_setnew(qh, qh->TEMPsize);- qh->coplanarfacetset= qh_setnew(qh, qh->TEMPsize);- qh->NEARzero= (realT *)qh_memalloc(qh, qh->hull_dim * sizeof(realT));- qh->lower_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));- qh->upper_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));- qh->lower_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));- qh->upper_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));- for (k=qh->input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */- 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, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));- qh->gm_row= (coordT **)qh_memalloc(qh, (qh->hull_dim+1) * sizeof(coordT *));-} /* initqhull_buffers */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_globals">-</a>-- qh_initqhull_globals(qh, 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)- initialize qh.CENTERtype, qh.normal_size,- qh.center_size, qh.TRACEpoint/level,- initialize and test random numbers- qh_initqhull_outputflags() -- adjust and test output flags-*/-void qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {- int seed, pointsneeded, extra= 0, i, randi, k;- realT randr;- realT factorial;-- time_t timedata;-- trace0((qh, qh->ferr, 13, "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(qh, "_pre-merge", NULL, NULL);- }else {- qh->MERGEexact= True;- qh_option(qh, "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)- qh_fprintf(qh, qh->ferr, 7038, "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(qh, "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(qh, "_zero-centrum", NULL, NULL);- }- if (qh->JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh->PRINTprecision)- 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",- REALepsilon);-#ifdef qh_NOmerge- if (qh->MERGING) {- qh_fprintf(qh, qh->ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }-#endif- if (qh->DELAUNAY && qh->KEEPcoplanar && !qh->KEEPinside) {- qh->KEEPinside= True;- qh_option(qh, "Qinterior-keep", NULL, NULL);- }- if (qh->DELAUNAY && qh->HALFspace) {- qh_fprintf(qh, qh->ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (!qh->DELAUNAY && (qh->UPPERdelaunay || qh->ATinfinity)) {- qh_fprintf(qh, qh->ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->UPPERdelaunay && qh->ATinfinity) {- qh_fprintf(qh, qh->ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->SCALElast && !qh->DELAUNAY && qh->PRINTprecision)- qh_fprintf(qh, qh->ferr, 7040, "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) {- qh_fprintf(qh, qh->ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n");- qh_errexit(qh, qh_ERRinput, NULL ,NULL);- }- if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay)) {- qh->hull_dim -= qh->PROJECTinput;- if (qh->DELAUNAY) {- qh->hull_dim++;- if (qh->ATinfinity)- extra= 1;- }- }- if (qh->hull_dim <= 1) {- qh_fprintf(qh, qh->ferr, 6050, "qhull error: dimension %d must be > 1\n", qh->hull_dim);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- for (k=2, factorial=1.0; k < qh->hull_dim; k++)- factorial *= k;- qh->AREAfactor= 1.0 / factorial;- trace2((qh, qh->ferr, 2005, "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(qh, "Q3-no-merge-vertices-dim-high", NULL, NULL);- }- if (qh->GOODpoint)- pointsneeded++;-#ifdef qh_NOtrace- if (qh->IStracing) {- qh_fprintf(qh, qh->ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)");- qh_errexit(qh, 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 != qh_IDunknown || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {- qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);- qh->IStracing= 0;- }- if (qh->ROTATErandom == 0 || qh->ROTATErandom == -1) {- seed= (int)time(&timedata);- if (qh->ROTATErandom == -1) {- seed= -seed;- qh_option(qh, "QRandom-seed", &seed, NULL );- }else- qh_option(qh, "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_(qh, seed);- randr= 0.0;- for (i=1000; i--; ) {- randi= qh_RANDOMint;- randr += randi;- if (randi > qh_RANDOMmax) {- qh_fprintf(qh, qh->ferr, 8036, "\-qhull configuration error (qh_RANDOMmax in user.h):\n\- random integer %d > qh_RANDOMmax(qh, %.8g)\n",- randi, qh_RANDOMmax);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- }- qh_RANDOMseed_(qh, seed);- randr = randr/1000;- if (randr < qh_RANDOMmax * 0.1- || randr > qh_RANDOMmax * 0.9)- qh_fprintf(qh, qh->ferr, 8037, "\-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 * 0.5, qh_RANDOMmax);- qh->RANDOMa= 2.0 * qh->RANDOMfactor/qh_RANDOMmax;- qh->RANDOMb= 1.0 - qh->RANDOMfactor;- if (qh_HASHfactor < 1.1) {- 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",- qh_HASHfactor);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- if (numpoints+extra < pointsneeded) {- qh_fprintf(qh, qh->ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",- numpoints, pointsneeded);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- qh_initqhull_outputflags(qh);-} /* initqhull_globals */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_mem">-</a>-- qh_initqhull_mem(qh, )- initialize mem_r.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(qh) to add up to 10 additional sizes for quick allocation- (see numsizes below)-- returns:- mem_r.c already for qh_memalloc/qh_memfree (errors if called beforehand)-- notes:- qh_produceoutput() prints memsizes--*/-void qh_initqhull_mem(qhT *qh) {- int numsizes;- int i;-- numsizes= 8+10;- qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, numsizes,- qh_MEMbufsize, qh_MEMinitbuf);- qh_memsize(qh, (int)sizeof(vertexT));- if (qh->MERGING) {- qh_memsize(qh, (int)sizeof(ridgeT));- qh_memsize(qh, (int)sizeof(mergeT));- }- qh_memsize(qh, (int)sizeof(facetT));- i= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize; /* ridge.vertices */- qh_memsize(qh, i);- qh_memsize(qh, qh->normal_size); /* normal */- i += SETelemsize; /* facet.vertices, .ridges, .neighbors */- qh_memsize(qh, i);- qh_user_memsizes(qh);- qh_memsetup(qh);-} /* initqhull_mem */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_outputflags">-</a>-- qh_initqhull_outputflags- initialize flags concerned with output-- returns:- adjust user flags as needed-- see:- qh_clear_outputflags() resets the flags-- design:- test for qh.PRINTgood (i.e., only print 'good' facets)- check for conflicting print output options-*/-void qh_initqhull_outputflags(qhT *qh) {- boolT printgeom= False, printmath= False, printcoplanar= False;- int i;-- trace3((qh, qh->ferr, 3024, "qh_initqhull_outputflags: %s\n", qh->qhull_command));- 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(qh, "Pgood", NULL, NULL);- }- }- if (qh->PRINTtransparent) {- if (qh->hull_dim != 4 || !qh->DELAUNAY || qh->VORONOI || qh->DROPdim >= 0) {- qh_fprintf(qh, qh->ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");- qh_errexit(qh, 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 || qh->PRINTout[i] == qh_PRINTmaple)- 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) {- qh_fprintf(qh, qh->ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }else if (qh->PRINTout[i] == qh_PRINTtriangles && (qh->HALFspace || qh->VORONOI)) {- qh_fprintf(qh, qh->ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }else if (qh->PRINTout[i] == qh_PRINTcentrums && qh->VORONOI) {- qh_fprintf(qh, qh->ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }else if (qh->PRINTout[i] == qh_PRINTvertices) {- if (qh->VORONOI)- qh_option(qh, "Fvoronoi", NULL, NULL);- else- qh_option(qh, "Fvertices", NULL, NULL);- }- }- if (printcoplanar && qh->DELAUNAY && qh->JOGGLEmax < REALmax/2) {- if (qh->PRINTprecision)- qh_fprintf(qh, qh->ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");- }- if (printmath && (qh->hull_dim > 3 || qh->VORONOI)) {- 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");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (printgeom) {- if (qh->hull_dim > 4) {- qh_fprintf(qh, qh->ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->PRINTnoplanes && !(qh->PRINTcoplanar + qh->PRINTcentrums- + qh->PRINTdots + qh->PRINTspheres + qh->DOintersections + qh->PRINTridges)) {- qh_fprintf(qh, qh->ferr, 6058, "qhull input error: no output specified for Geomview\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->VORONOI && (qh->hull_dim > 3 || qh->DROPdim >= 0)) {- qh_fprintf(qh, qh->ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");- qh_errexit(qh, 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)) {- qh_fprintf(qh, qh->ferr, 7042, "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;- }- }- if (!qh->KEEPcoplanar && !qh->KEEPinside && !qh->ONLYgood) {- if ((qh->PRINTcoplanar && qh->PRINTspheres) || printcoplanar) {- if (qh->QHULLfinished) {- qh_fprintf(qh, qh->ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");- }else {- qh->KEEPcoplanar = True;- qh_option(qh, "Qcoplanar", NULL, NULL);- }- }- }- 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)- 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);- }else- qh->DROPdim= -1;- }else if (qh->VORONOI) {- qh->DROPdim= qh->hull_dim-1;- qh->PRINTdim= qh->hull_dim-1;- }-} /* qh_initqhull_outputflags */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_start">-</a>-- qh_initqhull_start(qh, infile, outfile, errfile )- allocate memory if needed and call qh_initqhull_start2()-*/-void qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {-- qh_initstatistics(qh);- qh_initqhull_start2(qh, infile, outfile, errfile);-} /* initqhull_start */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initqhull_start2">-</a>-- qh_initqhull_start2(qh, infile, outfile, errfile )- start initialization of qhull- initialize statistics, stdio, default values for global variables- assumes qh is allocated- notes:- report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized- see:- qh_maxmin() determines the precision constants- qh_freeqhull()-*/-void qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {- time_t timedata;- int seed;-- qh_CPUclock; /* start the clock(for qh_clock). One-shot. */- /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */- memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT)); /* every field is 0, FALSE, NULL */- qh->NOerrexit= True;- qh->ANGLEmerge= True;- qh->DROPdim= -1;- qh->ferr= errfile;- qh->fin= infile;- qh->fout= outfile;- qh->furthest_id= qh_IDunknown;- qh->JOGGLEmax= REALmax;- qh->KEEPminArea = REALmax;- qh->last_low= REALmax;- qh->last_high= REALmax;- qh->last_newhigh= REALmax;- qh->last_random= 1;- 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= qh_IDunknown; /* recompile or use 'TPn' */- qh->tracefacet_id= UINT_MAX; /* recompile to trace a facet */- qh->tracevertex_id= UINT_MAX; /* recompile to trace a vertex */- seed= (int)time(&timedata);- qh_RANDOMseed_(qh, seed);- qh->run_id= qh_RANDOMint;- if(!qh->run_id)- qh->run_id++; /* guarantee non-zero */- qh_option(qh, "run-id", &qh->run_id, NULL);- strcat(qh->qhull, "qhull");-} /* initqhull_start2 */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="initthresholds">-</a>-- qh_initthresholds(qh, 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(qhT *qh, char *command) {- realT value;- int idx, maxdim, k;- char *s= command; /* non-const due to strtol */- 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)) {- qh_fprintf(qh, qh->ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s. Ignored\n",- key, s-1);- continue;- }- idx= qh_strtol(s, &s);- if (idx >= qh->hull_dim) {- qh_fprintf(qh, qh->ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d. Ignored\n",- idx, key, qh->hull_dim);- continue;- }- if (*s == ':') {- s++;- value= qh_strtod(s, &s);- if (fabs((double)value) > 1.0) {- qh_fprintf(qh, qh->ferr, 7046, "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[idx]= value;- else- qh->upper_threshold[idx]= 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)) {- qh_fprintf(qh, qh->ferr, 7047, "qhull warning: no dimension given for Qhull option %c. Ignored\n",- key);- continue;- }- idx= qh_strtol(s, &s);- if (idx >= maxdim) {- qh_fprintf(qh, qh->ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n",- idx, 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[idx]= value;- else- qh->upper_bound[idx]= 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_r.htm#TOC"- >-------------------------------</a><a name="lib_check">-</a>-- qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )- Report error if library does not agree with caller-- notes:- NOerrors -- qh_lib_check can not call qh_errexit()-*/-void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {- boolT iserror= False;--#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG) /* user_r.h */- // _CrtSetBreakAlloc(744); /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */- _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );- _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );- _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );- _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );- _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );- _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );- _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );-#endif-- if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */- qh_fprintf_stderr(6257, "qh_lib_check: Incorrect qhull library called. Caller uses non-reentrant Qhull with a static qhT. Library is reentrant.\n");- iserror= True;- }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */- 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");- iserror= True;- }else if (qhullLibraryType!=QHULL_REENTRANT) { /* 2 */- 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);- iserror= True;- }- if (qhTsize != sizeof(qhT)) {- 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));- iserror= True;- }- if (vertexTsize != sizeof(vertexT)) {- 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));- iserror= True;- }- if (ridgeTsize != sizeof(ridgeT)) {- 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));- iserror= True;- }- if (facetTsize != sizeof(facetT)) {- 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));- iserror= True;- }- if (setTsize && setTsize != sizeof(setT)) {- 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));- iserror= True;- }- if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {- 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));- iserror= True;- }- if (iserror) {- qh_fprintf_stderr(6259, "qh_lib_check: Cannot continue. Library '%s' is reentrant (e.g., qhull_r.so)\n", qh_version2);- qh_exit(qh_ERRqhull); /* can not use qh_errexit() */- }-} /* lib_check */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="option">-</a>-- qh_option(qh, option, intVal, realVal )- add an option description to qh.qhull_options-- notes:- NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]- will be printed with statistics ('Ts') and errors- strlen(option) < 40-*/-void qh_option(qhT *qh, const 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= (int)strlen(buf); /* WARN64 */- qh->qhull_optionlen += len;- maxlen= sizeof(qh->qhull_options) - len -1;- maximize_(maxlen, 0);- if (qh->qhull_optionlen >= qh_OPTIONline && maxlen > 0) {- qh->qhull_optionlen= len;- strncat(qh->qhull_options, "\n", (size_t)(maxlen--));- }- strncat(qh->qhull_options, buf, (size_t)maxlen);-} /* option */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="zero">-</a>-- qh_zero( qh, errfile )- Initialize and zero Qhull's memory for qh_new_qhull()-- notes:- Not needed in global.c because static variables are initialized to zero-*/-void qh_zero(qhT *qh, FILE *errfile) {- memset((char *)qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */- qh->NOerrexit= True;- qh_meminit(qh, errfile);-} /* zero */-
− C/halfspaces.c
@@ -1,68 +0,0 @@-#define qh_QHimport-#include "qhull_ra.h"--double** intersections(- double* halfspaces,- double* interiorpoint,- unsigned dim,- unsigned n,- unsigned* nintersections,- unsigned* exitcode,- unsigned print-)-{- char opts[250];- sprintf(opts, "qhull s Fp FF H H%f", interiorpoint[0]); //, interiorpoint[1] , interiorpoint[2]);- for(unsigned i=1; i < dim; i++){- char x[20];- sprintf(x, ",%f", interiorpoint[i]);- strcat(opts, x);- }- printf(opts); printf("\n");-- qhT qh_qh; /* Qhull's data structure */- qhT* qh= &qh_qh;- QHULL_LIB_CHECK- qh_meminit(qh, stderr);- boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */- FILE *errfile = NULL;- FILE* outfile = print ? stdout : NULL;- qh_zero(qh, errfile);- *exitcode = qh_new_qhull(qh, dim+1, n, halfspaces, ismalloc, opts, outfile,- errfile);- printf("exitcode: %u\n", *exitcode);-- double** out;- if(!(*exitcode)){- *nintersections = qh->num_facets;- out = malloc(*nintersections * sizeof(double*));- facetT *facet;- unsigned i_facet = 0;- FORALLfacets{- if(facet->offset != 0){- out[i_facet] = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- out[i_facet][i] = - facet->normal[i] / facet->offset +- qh->feasible_point[i]; // = interiorpoint ? yes- }- i_facet++;- }else{- (*nintersections)--;- }- }-- }-- /* Do cleanup regardless of whether there is an error */- int curlong, totlong;- qh_freeqhull(qh, !qh_ALL); /* free long memory */- qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */-- if(*exitcode){- free(out);- return 0;- }else{- return out;- }--}
− C/io_r.c
@@ -1,4062 +0,0 @@-/*<html><pre> -<a href="qh-io_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- io_r.c- Input/Output routines of qhull application-- see qh-io_r.htm and io_r.h-- see user_r.c for qh_errprint and qh_printfacetlist-- unix_r.c calls qh_readpoints and qh_produce_output-- unix_r.c and user_r.c are the only callers of io_r.c functions- This allows the user to avoid loading io_r.o from qhull.a-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/io_r.c#4 $$Change: 2064 $- $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $-*/--#include "qhull_ra.h"--/*========= -functions in alphabetical order after qh_produce_output(qh) =====*/--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="produce_output">-</a>-- qh_produce_output(qh)- qh_produce_output2(qh)- prints out the result of qhull in desired format- qh_produce_output2(qh) does not call qh_prepare_output(qh)- if qh.GETarea- computes and prints area and volume- qh.PRINTout[] is an array of output formats-- notes:- prints output in qh.PRINTout order-*/-void qh_produce_output(qhT *qh) {- int tempsize= qh_setsize(qh, qh->qhmem.tempstack);-- qh_prepare_output(qh);- qh_produce_output2(qh);- if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {- qh_fprintf(qh, qh->ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",- qh_setsize(qh, qh->qhmem.tempstack));- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }-} /* produce_output */---void qh_produce_output2(qhT *qh) {- int i, tempsize= qh_setsize(qh, qh->qhmem.tempstack), d_1;-- if (qh->PRINTsummary)- qh_printsummary(qh, qh->ferr);- else if (qh->PRINTout[0] == qh_PRINTnone)- qh_printsummary(qh, qh->fout);- for (i=0; i < qh_PRINTEND; i++)- qh_printfacets(qh, qh->fout, qh->PRINTout[i], qh->facet_list, NULL, !qh_ALL);- qh_allstatistics(qh);- if (qh->PRINTprecision && !qh->MERGING && (qh->JOGGLEmax > REALmax/2 || qh->RERUN))- qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);- if (qh->VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))- qh_printstats(qh, qh->ferr, qh->qhstat.vridges, NULL);- if (qh->PRINTstatistics) {- qh_printstatistics(qh, qh->ferr, "");- qh_memstatistics(qh, qh->ferr);- d_1= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;- qh_fprintf(qh, qh->ferr, 8040, "\- size in bytes: merge %d ridge %d vertex %d facet %d\n\- normal %d ridge vertices %d facet vertices or neighbors %d\n",- (int)sizeof(mergeT), (int)sizeof(ridgeT),- (int)sizeof(vertexT), (int)sizeof(facetT),- qh->normal_size, d_1, d_1 + SETelemsize);- }- if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {- qh_fprintf(qh, qh->ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",- qh_setsize(qh, qh->qhmem.tempstack));- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }-} /* produce_output2 */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="dfacet">-</a>-- qh_dfacet(qh, id )- print facet by id, for debugging--*/-void qh_dfacet(qhT *qh, unsigned id) {- facetT *facet;-- FORALLfacets {- if (facet->id == id) {- qh_printfacet(qh, qh->fout, facet);- break;- }- }-} /* dfacet */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="dvertex">-</a>-- qh_dvertex(qh, id )- print vertex by id, for debugging-*/-void qh_dvertex(qhT *qh, unsigned id) {- vertexT *vertex;-- FORALLvertices {- if (vertex->id == id) {- qh_printvertex(qh, qh->fout, vertex);- break;- }- }-} /* dvertex */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="compare_facetarea">-</a>-- qh_compare_facetarea(p1, p2 )- used by qsort() to order facets by area-*/-int qh_compare_facetarea(const void *p1, const void *p2) {- const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);-- if (!a->isarea)- return -1;- if (!b->isarea)- return 1;- if (a->f.area > b->f.area)- return 1;- else if (a->f.area == b->f.area)- return 0;- return -1;-} /* compare_facetarea */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="compare_facetmerge">-</a>-- qh_compare_facetmerge(p1, p2 )- used by qsort() to order facets by number of merges-*/-int qh_compare_facetmerge(const void *p1, const void *p2) {- const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);-- return(a->nummerge - b->nummerge);-} /* compare_facetvisit */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="compare_facetvisit">-</a>-- qh_compare_facetvisit(p1, p2 )- used by qsort() to order facets by visit id or id-*/-int qh_compare_facetvisit(const void *p1, const void *p2) {- const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);- int i,j;-- if (!(i= a->visitid))- i= 0 - a->id; /* do not convert to int, sign distinguishes id from visitid */- if (!(j= b->visitid))- j= 0 - b->id;- return(i - j);-} /* compare_facetvisit */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="compare_vertexpoint">-</a>-- qh_compare_vertexpoint( p1, p2 )- used by qsort() to order vertices by point id-- Not usable in qhulllib_r since qh_pointid depends on qh-- int qh_compare_vertexpoint(const void *p1, const void *p2) {- const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);-- return((qh_pointid(qh, a->point) > qh_pointid(qh, b->point)?1:-1));-}*/--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="copyfilename">-</a>-- qh_copyfilename(qh, dest, size, source, length )- copy filename identified by qh_skipfilename()-- notes:- see qh_skipfilename() for syntax-*/-void qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length) {- char c= *source;-- if (length > size + 1) {- qh_fprintf(qh, qh->ferr, 6040, "qhull error: filename is more than %d characters, %s\n", size-1, source);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- strncpy(filename, source, length);- filename[length]= '\0';- if (c == '\'' || c == '"') {- char *s= filename + 1;- char *t= filename;- while (*s) {- if (*s == c) {- if (s[-1] == '\\')- t[-1]= c;- }else- *t++= *s;- s++;- }- *t= '\0';- }-} /* copyfilename */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="countfacets">-</a>-- qh_countfacets(qh, facetlist, facets, printall,- numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars )- count good facets for printing and set visitid- if allfacets, ignores qh_skipfacet()-- notes:- qh_printsummary and qh_countfacets must match counts-- returns:- numfacets, numsimplicial, total neighbors, numridges, coplanars- each facet with ->visitid indicating 1-relative position- ->visitid==0 indicates not good-- notes- numfacets >= numsimplicial- if qh.NEWfacets,- does not count visible facets (matches qh_printafacet)-- design:- for all facets on facetlist and in facets set- unless facet is skipped or visible (i.e., will be deleted)- mark facet->visitid- update counts-*/-void qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,- int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {- facetT *facet, **facetp;- int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;-- FORALLfacet_(facetlist) {- if ((facet->visible && qh->NEWfacets)- || (!printall && qh_skipfacet(qh, facet)))- facet->visitid= 0;- else {- facet->visitid= ++numfacets;- totneighbors += qh_setsize(qh, facet->neighbors);- if (facet->simplicial) {- numsimplicial++;- if (facet->keepcentrum && facet->tricoplanar)- numtricoplanars++;- }else- numridges += qh_setsize(qh, facet->ridges);- if (facet->coplanarset)- numcoplanars += qh_setsize(qh, facet->coplanarset);- }- }-- FOREACHfacet_(facets) {- if ((facet->visible && qh->NEWfacets)- || (!printall && qh_skipfacet(qh, facet)))- facet->visitid= 0;- else {- facet->visitid= ++numfacets;- totneighbors += qh_setsize(qh, facet->neighbors);- if (facet->simplicial){- numsimplicial++;- if (facet->keepcentrum && facet->tricoplanar)- numtricoplanars++;- }else- numridges += qh_setsize(qh, facet->ridges);- if (facet->coplanarset)- numcoplanars += qh_setsize(qh, facet->coplanarset);- }- }- qh->visit_id += numfacets+1;- *numfacetsp= numfacets;- *numsimplicialp= numsimplicial;- *totneighborsp= totneighbors;- *numridgesp= numridges;- *numcoplanarsp= numcoplanars;- *numtricoplanarsp= numtricoplanars;-} /* countfacets */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="detvnorm">-</a>-- qh_detvnorm(qh, vertex, vertexA, centers, offset )- compute separating plane of the Voronoi diagram for a pair of input sites- centers= set of facets (i.e., Voronoi vertices)- facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)-- assumes:- qh_ASvoronoi and qh_vertexneighbors() already set-- returns:- norm- a pointer into qh.gm_matrix to qh.hull_dim-1 reals- copy the data before reusing qh.gm_matrix- offset- if 'QVn'- sign adjusted so that qh.GOODvertexp is inside- else- sign adjusted so that vertex is inside-- qh.gm_matrix= simplex of points from centers relative to first center-- notes:- in io_r.c so that code for 'v Tv' can be removed by removing io_r.c- returns pointer into qh.gm_matrix to avoid tracking of temporary memory-- design:- determine midpoint of input sites- build points as the set of Voronoi vertices- select a simplex from points (if necessary)- include midpoint if the Voronoi region is unbounded- relocate the first vertex of the simplex to the origin- compute the normalized hyperplane through the simplex- orient the hyperplane toward 'QVn' or 'vertex'- if 'Tv' or 'Ts'- if bounded- test that hyperplane is the perpendicular bisector of the input sites- test that Voronoi vertices not in the simplex are still on the hyperplane- free up temporary memory-*/-pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {- facetT *facet, **facetp;- int i, k, pointid, pointidA, point_i, point_n;- setT *simplex= NULL;- pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;- coordT *coord, *gmcoord, *normalp;- setT *points= qh_settemp(qh, qh->TEMPsize);- boolT nearzero= False;- boolT unbounded= False;- int numcenters= 0;- int dim= qh->hull_dim - 1;- realT dist, offset, angle, zero= 0.0;-- midpoint= qh->gm_matrix + qh->hull_dim * qh->hull_dim; /* last row */- for (k=0; k < dim; k++)- midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;- FOREACHfacet_(centers) {- numcenters++;- if (!facet->visitid)- unbounded= True;- else {- if (!facet->center)- facet->center= qh_facetcenter(qh, facet->vertices);- qh_setappend(qh, &points, facet->center);- }- }- if (numcenters > dim) {- simplex= qh_settemp(qh, qh->TEMPsize);- qh_setappend(qh, &simplex, vertex->point);- if (unbounded)- qh_setappend(qh, &simplex, midpoint);- qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);- qh_setdelnth(qh, simplex, 0);- }else if (numcenters == dim) {- if (unbounded)- qh_setappend(qh, &points, midpoint);- simplex= points;- }else {- qh_fprintf(qh, qh->ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- i= 0;- gmcoord= qh->gm_matrix;- point0= SETfirstt_(simplex, pointT);- FOREACHpoint_(simplex) {- if (qh->IStracing >= 4)- qh_printmatrix(qh, qh->ferr, "qh_detvnorm: Voronoi vertex or midpoint",- &point, 1, dim);- if (point != point0) {- qh->gm_row[i++]= gmcoord;- coord= point0;- for (k=dim; k--; )- *(gmcoord++)= *point++ - *coord++;- }- }- qh->gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */- normal= gmcoord;- qh_sethyperplane_gauss(qh, dim, qh->gm_row, point0, True,- normal, &offset, &nearzero);- if (qh->GOODvertexp == vertexA->point)- inpoint= vertexA->point;- else- inpoint= vertex->point;- zinc_(Zdistio);- dist= qh_distnorm(dim, inpoint, normal, &offset);- if (dist > 0) {- offset= -offset;- normalp= normal;- for (k=dim; k--; ) {- *normalp= -(*normalp);- normalp++;- }- }- if (qh->VERIFYoutput || qh->PRINTstatistics) {- pointid= qh_pointid(qh, vertex->point);- pointidA= qh_pointid(qh, vertexA->point);- if (!unbounded) {- zinc_(Zdiststat);- dist= qh_distnorm(dim, midpoint, normal, &offset);- if (dist < 0)- dist= -dist;- zzinc_(Zridgemid);- wwmax_(Wridgemidmax, dist);- wwadd_(Wridgemid, dist);- trace4((qh, qh->ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",- pointid, pointidA, dist));- for (k=0; k < dim; k++)- midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */- qh_normalize(qh, midpoint, dim, False);- angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */- if (angle < 0.0)- angle= angle + 1.0;- else- angle= angle - 1.0;- if (angle < 0.0)- angle -= angle;- trace4((qh, qh->ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",- pointid, pointidA, angle, nearzero));- if (nearzero) {- zzinc_(Zridge0);- wwmax_(Wridge0max, angle);- wwadd_(Wridge0, angle);- }else {- zzinc_(Zridgeok)- wwmax_(Wridgeokmax, angle);- wwadd_(Wridgeok, angle);- }- }- if (simplex != points) {- FOREACHpoint_i_(qh, points) {- if (!qh_setin(simplex, point)) {- facet= SETelemt_(centers, point_i, facetT);- zinc_(Zdiststat);- dist= qh_distnorm(dim, point, normal, &offset);- if (dist < 0)- dist= -dist;- zzinc_(Zridge);- wwmax_(Wridgemax, dist);- wwadd_(Wridge, dist);- trace4((qh, qh->ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",- pointid, pointidA, facet->visitid, dist));- }- }- }- }- *offsetp= offset;- if (simplex != points)- qh_settempfree(qh, &simplex);- qh_settempfree(qh, &points);- return normal;-} /* detvnorm */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="detvridge">-</a>-- qh_detvridge(qh, vertexA )- determine Voronoi ridge from 'seen' neighbors of vertexA- include one vertex-at-infinite if an !neighbor->visitid-- returns:- temporary set of centers (facets, i.e., Voronoi vertices)- sorted by center id-*/-setT *qh_detvridge(qhT *qh, vertexT *vertex) {- setT *centers= qh_settemp(qh, qh->TEMPsize);- setT *tricenters= qh_settemp(qh, qh->TEMPsize);- facetT *neighbor, **neighborp;- boolT firstinf= True;-- FOREACHneighbor_(vertex) {- if (neighbor->seen) {- if (neighbor->visitid) {- if (!neighbor->tricoplanar || qh_setunique(qh, &tricenters, neighbor->center))- qh_setappend(qh, ¢ers, neighbor);- }else if (firstinf) {- firstinf= False;- qh_setappend(qh, ¢ers, neighbor);- }- }- }- qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(qh, centers),- sizeof(facetT *), qh_compare_facetvisit);- qh_settempfree(qh, &tricenters);- return centers;-} /* detvridge */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="detvridge3">-</a>-- qh_detvridge3(qh, atvertex, vertex )- determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex- include one vertex-at-infinite for !neighbor->visitid- assumes all facet->seen2= True-- returns:- temporary set of centers (facets, i.e., Voronoi vertices)- listed in adjacency order (!oriented)- all facet->seen2= True-- design:- mark all neighbors of atvertex- for each adjacent neighbor of both atvertex and vertex- if neighbor selected- add neighbor to set of Voronoi vertices-*/-setT *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex) {- setT *centers= qh_settemp(qh, qh->TEMPsize);- setT *tricenters= qh_settemp(qh, qh->TEMPsize);- facetT *neighbor, **neighborp, *facet= NULL;- boolT firstinf= True;-- FOREACHneighbor_(atvertex)- neighbor->seen2= False;- FOREACHneighbor_(vertex) {- if (!neighbor->seen2) {- facet= neighbor;- break;- }- }- while (facet) {- facet->seen2= True;- if (neighbor->seen) {- if (facet->visitid) {- if (!facet->tricoplanar || qh_setunique(qh, &tricenters, facet->center))- qh_setappend(qh, ¢ers, facet);- }else if (firstinf) {- firstinf= False;- qh_setappend(qh, ¢ers, facet);- }- }- FOREACHneighbor_(facet) {- if (!neighbor->seen2) {- if (qh_setin(vertex->neighbors, neighbor))- break;- else- neighbor->seen2= True;- }- }- facet= neighbor;- }- if (qh->CHECKfrequently) {- FOREACHneighbor_(vertex) {- if (!neighbor->seen2) {- qh_fprintf(qh, qh->ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",- qh_pointid(qh, vertex->point), neighbor->id);- qh_errexit(qh, qh_ERRqhull, neighbor, NULL);- }- }- }- FOREACHneighbor_(atvertex)- neighbor->seen2= True;- qh_settempfree(qh, &tricenters);- return centers;-} /* detvridge3 */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="eachvoronoi">-</a>-- qh_eachvoronoi(qh, fp, printvridge, vertex, visitall, innerouter, inorder )- if visitall,- visit all Voronoi ridges for vertex (i.e., an input site)- else- visit all unvisited Voronoi ridges for vertex- all vertex->seen= False if unvisited- assumes- all facet->seen= False- all facet->seen2= True (for qh_detvridge3)- all facet->visitid == 0 if vertex_at_infinity- == index of Voronoi vertex- >= qh.num_facets if ignored- innerouter:- qh_RIDGEall-- both inner (bounded) and outer(unbounded) ridges- qh_RIDGEinner- only inner- qh_RIDGEouter- only outer-- if inorder- orders vertices for 3-d Voronoi diagrams-- returns:- number of visited ridges (does not include previously visited ridges)-- if printvridge,- calls printvridge( fp, vertex, vertexA, centers)- fp== any pointer (assumes FILE*)- vertex,vertexA= pair of input sites that define a Voronoi ridge- centers= set of facets (i.e., Voronoi vertices)- ->visitid == index or 0 if vertex_at_infinity- ordered for 3-d Voronoi diagram- notes:- uses qh.vertex_visit-- see:- qh_eachvoronoi_all()-- design:- mark selected neighbors of atvertex- for each selected neighbor (either Voronoi vertex or vertex-at-infinity)- for each unvisited vertex- if atvertex and vertex share more than d-1 neighbors- bump totalcount- if printvridge defined- build the set of shared neighbors (i.e., Voronoi vertices)- call printvridge-*/-int qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {- boolT unbounded;- int count;- facetT *neighbor, **neighborp, *neighborA, **neighborAp;- setT *centers;- setT *tricenters= qh_settemp(qh, qh->TEMPsize);-- vertexT *vertex, **vertexp;- boolT firstinf;- unsigned int numfacets= (unsigned int)qh->num_facets;- int totridges= 0;-- qh->vertex_visit++;- atvertex->seen= True;- if (visitall) {- FORALLvertices- vertex->seen= False;- }- FOREACHneighbor_(atvertex) {- if (neighbor->visitid < numfacets)- neighbor->seen= True;- }- FOREACHneighbor_(atvertex) {- if (neighbor->seen) {- FOREACHvertex_(neighbor->vertices) {- if (vertex->visitid != qh->vertex_visit && !vertex->seen) {- vertex->visitid= qh->vertex_visit;- count= 0;- firstinf= True;- qh_settruncate(qh, tricenters, 0);- FOREACHneighborA_(vertex) {- if (neighborA->seen) {- if (neighborA->visitid) {- if (!neighborA->tricoplanar || qh_setunique(qh, &tricenters, neighborA->center))- count++;- }else if (firstinf) {- count++;- firstinf= False;- }- }- }- if (count >= qh->hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */- if (firstinf) {- if (innerouter == qh_RIDGEouter)- continue;- unbounded= False;- }else {- if (innerouter == qh_RIDGEinner)- continue;- unbounded= True;- }- totridges++;- trace4((qh, qh->ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",- count, qh_pointid(qh, atvertex->point), qh_pointid(qh, vertex->point)));- if (printvridge && fp) {- if (inorder && qh->hull_dim == 3+1) /* 3-d Voronoi diagram */- centers= qh_detvridge3(qh, atvertex, vertex);- else- centers= qh_detvridge(qh, vertex);- (*printvridge)(qh, fp, atvertex, vertex, centers, unbounded);- qh_settempfree(qh, ¢ers);- }- }- }- }- }- }- FOREACHneighbor_(atvertex)- neighbor->seen= False;- qh_settempfree(qh, &tricenters);- return totridges;-} /* eachvoronoi */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="eachvoronoi_all">-</a>-- qh_eachvoronoi_all(qh, fp, printvridge, isUpper, innerouter, inorder )- visit all Voronoi ridges-- innerouter:- see qh_eachvoronoi()-- if inorder- orders vertices for 3-d Voronoi diagrams-- returns- total number of ridges-- if isUpper == facet->upperdelaunay (i.e., a Vornoi vertex)- facet->visitid= Voronoi vertex index(same as 'o' format)- else- facet->visitid= 0-- if printvridge,- calls printvridge( fp, vertex, vertexA, centers)- [see qh_eachvoronoi]-- notes:- Not used for qhull.exe- same effect as qh_printvdiagram but ridges not sorted by point id-*/-int qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {- facetT *facet;- vertexT *vertex;- int numcenters= 1; /* vertex 0 is vertex-at-infinity */- int totridges= 0;-- qh_clearcenters(qh, qh_ASvoronoi);- qh_vertexneighbors(qh);- maximize_(qh->visit_id, (unsigned) qh->num_facets);- FORALLfacets {- facet->visitid= 0;- facet->seen= False;- facet->seen2= True;- }- FORALLfacets {- if (facet->upperdelaunay == isUpper)- facet->visitid= numcenters++;- }- FORALLvertices- vertex->seen= False;- FORALLvertices {- if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)- continue;- totridges += qh_eachvoronoi(qh, fp, printvridge, vertex,- !qh_ALL, innerouter, inorder);- }- return totridges;-} /* eachvoronoi_all */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="facet2point">-</a>-- qh_facet2point(qh, facet, point0, point1, mindist )- return two projected temporary vertices for a 2-d facet- may be non-simplicial-- returns:- point0 and point1 oriented and projected to the facet- returns mindist (maximum distance below plane)-*/-void qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist) {- vertexT *vertex0, *vertex1;- realT dist;-- if (facet->toporient ^ qh_ORIENTclock) {- vertex0= SETfirstt_(facet->vertices, vertexT);- vertex1= SETsecondt_(facet->vertices, vertexT);- }else {- vertex1= SETfirstt_(facet->vertices, vertexT);- vertex0= SETsecondt_(facet->vertices, vertexT);- }- zadd_(Zdistio, 2);- qh_distplane(qh, vertex0->point, facet, &dist);- *mindist= dist;- *point0= qh_projectpoint(qh, vertex0->point, facet, dist);- qh_distplane(qh, vertex1->point, facet, &dist);- minimize_(*mindist, dist);- *point1= qh_projectpoint(qh, vertex1->point, facet, dist);-} /* facet2point */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="facetvertices">-</a>-- qh_facetvertices(qh, facetlist, facets, allfacets )- returns temporary set of vertices in a set and/or list of facets- if allfacets, ignores qh_skipfacet()-- returns:- vertices with qh.vertex_visit-- notes:- optimized for allfacets of facet_list-- design:- if allfacets of facet_list- create vertex set from vertex_list- else- for each selected facet in facets or facetlist- append unvisited vertices to vertex set-*/-setT *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets) {- setT *vertices;- facetT *facet, **facetp;- vertexT *vertex, **vertexp;-- qh->vertex_visit++;- if (facetlist == qh->facet_list && allfacets && !facets) {- vertices= qh_settemp(qh, qh->num_vertices);- FORALLvertices {- vertex->visitid= qh->vertex_visit;- qh_setappend(qh, &vertices, vertex);- }- }else {- vertices= qh_settemp(qh, qh->TEMPsize);- FORALLfacet_(facetlist) {- if (!allfacets && qh_skipfacet(qh, facet))- continue;- FOREACHvertex_(facet->vertices) {- if (vertex->visitid != qh->vertex_visit) {- vertex->visitid= qh->vertex_visit;- qh_setappend(qh, &vertices, vertex);- }- }- }- }- FOREACHfacet_(facets) {- if (!allfacets && qh_skipfacet(qh, facet))- continue;- FOREACHvertex_(facet->vertices) {- if (vertex->visitid != qh->vertex_visit) {- vertex->visitid= qh->vertex_visit;- qh_setappend(qh, &vertices, vertex);- }- }- }- return vertices;-} /* facetvertices */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="geomplanes">-</a>-- qh_geomplanes(qh, facet, outerplane, innerplane )- return outer and inner planes for Geomview- qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)-- notes:- assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon-*/-void qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {- realT radius;-- if (qh->MERGING || qh->JOGGLEmax < REALmax/2) {- qh_outerinner(qh, facet, outerplane, innerplane);- radius= qh->PRINTradius;- if (qh->JOGGLEmax < REALmax/2)- radius -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim); /* already accounted for in qh_outerinner() */- *outerplane += radius;- *innerplane -= radius;- if (qh->PRINTcoplanar || qh->PRINTspheres) {- *outerplane += qh->MAXabs_coord * qh_GEOMepsilon;- *innerplane -= qh->MAXabs_coord * qh_GEOMepsilon;- }- }else- *innerplane= *outerplane= 0;-} /* geomplanes */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="markkeep">-</a>-- qh_markkeep(qh, facetlist )- mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea- ignores visible facets (!part of convex hull)-- returns:- may clear facet->good- recomputes qh.num_good-- design:- get set of good facets- if qh.KEEParea- sort facets by area- clear facet->good for all but n largest facets- if qh.KEEPmerge- sort facets by merge count- clear facet->good for all but n most merged facets- if qh.KEEPminarea- clear facet->good if area too small- update qh.num_good-*/-void qh_markkeep(qhT *qh, facetT *facetlist) {- facetT *facet, **facetp;- setT *facets= qh_settemp(qh, qh->num_facets);- int size, count;-- trace2((qh, qh->ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",- qh->KEEParea, qh->KEEPmerge, qh->KEEPminArea));- FORALLfacet_(facetlist) {- if (!facet->visible && facet->good)- qh_setappend(qh, &facets, facet);- }- size= qh_setsize(qh, facets);- if (qh->KEEParea) {- qsort(SETaddr_(facets, facetT), (size_t)size,- sizeof(facetT *), qh_compare_facetarea);- if ((count= size - qh->KEEParea) > 0) {- FOREACHfacet_(facets) {- facet->good= False;- if (--count == 0)- break;- }- }- }- if (qh->KEEPmerge) {- qsort(SETaddr_(facets, facetT), (size_t)size,- sizeof(facetT *), qh_compare_facetmerge);- if ((count= size - qh->KEEPmerge) > 0) {- FOREACHfacet_(facets) {- facet->good= False;- if (--count == 0)- break;- }- }- }- if (qh->KEEPminArea < REALmax/2) {- FOREACHfacet_(facets) {- if (!facet->isarea || facet->f.area < qh->KEEPminArea)- facet->good= False;- }- }- qh_settempfree(qh, &facets);- count= 0;- FORALLfacet_(facetlist) {- if (facet->good)- count++;- }- qh->num_good= count;-} /* markkeep */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="markvoronoi">-</a>-- qh_markvoronoi(qh, facetlist, facets, printall, isLower, numcenters )- mark voronoi vertices for printing by site pairs-- returns:- temporary set of vertices indexed by pointid- isLower set if printing lower hull (i.e., at least one facet is lower hull)- numcenters= total number of Voronoi vertices- bumps qh.printoutnum for vertex-at-infinity- clears all facet->seen and sets facet->seen2-- if selected- facet->visitid= Voronoi vertex id- else if upper hull (or 'Qu' and lower hull)- facet->visitid= 0- else- facet->visitid >= qh->num_facets-- notes:- ignores qh.ATinfinity, if defined-*/-setT *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {- int numcenters=0;- facetT *facet, **facetp;- setT *vertices;- boolT isLower= False;-- qh->printoutnum++;- qh_clearcenters(qh, qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */- qh_vertexneighbors(qh);- vertices= qh_pointvertex(qh);- if (qh->ATinfinity)- SETelem_(vertices, qh->num_points-1)= NULL;- qh->visit_id++;- maximize_(qh->visit_id, (unsigned) qh->num_facets);- FORALLfacet_(facetlist) {- if (printall || !qh_skipfacet(qh, facet)) {- if (!facet->upperdelaunay) {- isLower= True;- break;- }- }- }- FOREACHfacet_(facets) {- if (printall || !qh_skipfacet(qh, facet)) {- if (!facet->upperdelaunay) {- isLower= True;- break;- }- }- }- FORALLfacets {- if (facet->normal && (facet->upperdelaunay == isLower))- facet->visitid= 0; /* facetlist or facets may overwrite */- else- facet->visitid= qh->visit_id;- facet->seen= False;- facet->seen2= True;- }- numcenters++; /* qh_INFINITE */- FORALLfacet_(facetlist) {- if (printall || !qh_skipfacet(qh, facet))- facet->visitid= numcenters++;- }- FOREACHfacet_(facets) {- if (printall || !qh_skipfacet(qh, facet))- facet->visitid= numcenters++;- }- *isLowerp= isLower;- *numcentersp= numcenters;- trace2((qh, qh->ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));- return vertices;-} /* markvoronoi */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="order_vertexneighbors">-</a>-- qh_order_vertexneighbors(qh, vertex )- order facet neighbors of a 2-d or 3-d vertex by adjacency-- notes:- does not orient the neighbors-- design:- initialize a new neighbor set with the first facet in vertex->neighbors- while vertex->neighbors non-empty- select next neighbor in the previous facet's neighbor set- set vertex->neighbors to the new neighbor set-*/-void qh_order_vertexneighbors(qhT *qh, vertexT *vertex) {- setT *newset;- facetT *facet, *neighbor, **neighborp;-- trace4((qh, qh->ferr, 4018, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));- newset= qh_settemp(qh, qh_setsize(qh, vertex->neighbors));- facet= (facetT*)qh_setdellast(vertex->neighbors);- qh_setappend(qh, &newset, facet);- while (qh_setsize(qh, vertex->neighbors)) {- FOREACHneighbor_(vertex) {- if (qh_setin(facet->neighbors, neighbor)) {- qh_setdel(vertex->neighbors, neighbor);- qh_setappend(qh, &newset, neighbor);- facet= neighbor;- break;- }- }- if (!neighbor) {- qh_fprintf(qh, qh->ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",- vertex->id, facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- }- qh_setfree(qh, &vertex->neighbors);- qh_settemppop(qh);- vertex->neighbors= newset;-} /* order_vertexneighbors */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="prepare_output">-</a>-- qh_prepare_output(qh, )- prepare for qh_produce_output2(qh) according to- qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds- does not reset facet->good-- notes- except for PRINTstatistics, no-op if previously called with same options-*/-void qh_prepare_output(qhT *qh) {- if (qh->VORONOI) {- qh_clearcenters(qh, qh_ASvoronoi); /* must be before qh_triangulate */- qh_vertexneighbors(qh);- }- if (qh->TRIangulate && !qh->hasTriangulation) {- qh_triangulate(qh);- if (qh->VERIFYoutput && !qh->CHECKfrequently)- qh_checkpolygon(qh, qh->facet_list);- }- qh_findgood_all(qh, qh->facet_list);- if (qh->GETarea)- qh_getarea(qh, qh->facet_list);- if (qh->KEEParea || qh->KEEPmerge || qh->KEEPminArea < REALmax/2)- qh_markkeep(qh, qh->facet_list);- if (qh->PRINTstatistics)- qh_collectstatistics(qh);-}--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printafacet">-</a>-- qh_printafacet(qh, fp, format, facet, printall )- print facet to fp in given output format (see qh.PRINTout)-- returns:- nop if !printall and qh_skipfacet()- nop if visible facet and NEWfacets and format != PRINTfacets- must match qh_countfacets-- notes- preserves qh.visit_id- facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge-- see- qh_printbegin() and qh_printend()-- design:- test for printing facet- call appropriate routine for format- or output results directly-*/-void qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {- realT color[4], offset, dist, outerplane, innerplane;- boolT zerodiv;- coordT *point, *normp, *coordp, **pointp, *feasiblep;- int k;- vertexT *vertex, **vertexp;- facetT *neighbor, **neighborp;-- if (!printall && qh_skipfacet(qh, facet))- return;- if (facet->visible && qh->NEWfacets && format != qh_PRINTfacets)- return;- qh->printoutnum++;- switch (format) {- case qh_PRINTarea:- if (facet->isarea) {- qh_fprintf(qh, fp, 9009, qh_REAL_1, facet->f.area);- qh_fprintf(qh, fp, 9010, "\n");- }else- qh_fprintf(qh, fp, 9011, "0\n");- break;- case qh_PRINTcoplanars:- qh_fprintf(qh, fp, 9012, "%d", qh_setsize(qh, facet->coplanarset));- FOREACHpoint_(facet->coplanarset)- qh_fprintf(qh, fp, 9013, " %d", qh_pointid(qh, point));- qh_fprintf(qh, fp, 9014, "\n");- break;- case qh_PRINTcentrums:- qh_printcenter(qh, fp, format, NULL, facet);- break;- case qh_PRINTfacets:- qh_printfacet(qh, fp, facet);- break;- case qh_PRINTfacets_xridge:- qh_printfacetheader(qh, fp, facet);- break;- case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */- if (!facet->normal)- break;- for (k=qh->hull_dim; k--; ) {- color[k]= (facet->normal[k]+1.0)/2.0;- maximize_(color[k], -1.0);- minimize_(color[k], +1.0);- }- qh_projectdim3(qh, color, color);- if (qh->PRINTdim != qh->hull_dim)- qh_normalize2(qh, color, 3, True, NULL, NULL);- if (qh->hull_dim <= 2)- qh_printfacet2geom(qh, fp, facet, color);- else if (qh->hull_dim == 3) {- if (facet->simplicial)- qh_printfacet3geom_simplicial(qh, fp, facet, color);- else- qh_printfacet3geom_nonsimplicial(qh, fp, facet, color);- }else {- if (facet->simplicial)- qh_printfacet4geom_simplicial(qh, fp, facet, color);- else- qh_printfacet4geom_nonsimplicial(qh, fp, facet, color);- }- break;- case qh_PRINTids:- qh_fprintf(qh, fp, 9015, "%d\n", facet->id);- break;- case qh_PRINTincidences:- case qh_PRINToff:- case qh_PRINTtriangles:- if (qh->hull_dim == 3 && format != qh_PRINTtriangles)- qh_printfacet3vertex(qh, fp, facet, format);- else if (facet->simplicial || qh->hull_dim == 2 || format == qh_PRINToff)- qh_printfacetNvertex_simplicial(qh, fp, facet, format);- else- qh_printfacetNvertex_nonsimplicial(qh, fp, facet, qh->printoutvar++, format);- break;- case qh_PRINTinner:- qh_outerinner(qh, facet, NULL, &innerplane);- offset= facet->offset - innerplane;- goto LABELprintnorm;- break; /* prevent warning */- case qh_PRINTmerges:- qh_fprintf(qh, fp, 9016, "%d\n", facet->nummerge);- break;- case qh_PRINTnormals:- offset= facet->offset;- goto LABELprintnorm;- break; /* prevent warning */- case qh_PRINTouter:- qh_outerinner(qh, facet, &outerplane, NULL);- offset= facet->offset - outerplane;- LABELprintnorm:- if (!facet->normal) {- qh_fprintf(qh, fp, 9017, "no normal for facet f%d\n", facet->id);- break;- }- if (qh->CDDoutput) {- qh_fprintf(qh, fp, 9018, qh_REAL_1, -offset);- for (k=0; k < qh->hull_dim; k++)- qh_fprintf(qh, fp, 9019, qh_REAL_1, -facet->normal[k]);- }else {- for (k=0; k < qh->hull_dim; k++)- qh_fprintf(qh, fp, 9020, qh_REAL_1, facet->normal[k]);- qh_fprintf(qh, fp, 9021, qh_REAL_1, offset);- }- qh_fprintf(qh, fp, 9022, "\n");- break;- case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */- case qh_PRINTmaple:- if (qh->hull_dim == 2)- qh_printfacet2math(qh, fp, facet, format, qh->printoutvar++);- else- qh_printfacet3math(qh, fp, facet, format, qh->printoutvar++);- break;- case qh_PRINTneighbors:- qh_fprintf(qh, fp, 9023, "%d", qh_setsize(qh, facet->neighbors));- FOREACHneighbor_(facet)- qh_fprintf(qh, fp, 9024, " %d",- neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);- qh_fprintf(qh, fp, 9025, "\n");- break;- case qh_PRINTpointintersect:- if (!qh->feasible_point) {- qh_fprintf(qh, qh->ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (facet->offset > 0)- goto LABELprintinfinite;- point= coordp= (coordT*)qh_memalloc(qh, qh->normal_size);- normp= facet->normal;- feasiblep= qh->feasible_point;- if (facet->offset < -qh->MINdenom) {- for (k=qh->hull_dim; k--; )- *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);- }else {- for (k=qh->hull_dim; k--; ) {- *(coordp++)= qh_divzero(*(normp++), facet->offset, qh->MINdenom_1,- &zerodiv) + *(feasiblep++);- if (zerodiv) {- qh_memfree(qh, point, qh->normal_size);- goto LABELprintinfinite;- }- }- }- qh_printpoint(qh, fp, NULL, point);- qh_memfree(qh, point, qh->normal_size);- break;- LABELprintinfinite:- for (k=qh->hull_dim; k--; )- qh_fprintf(qh, fp, 9026, qh_REAL_1, qh_INFINITE);- qh_fprintf(qh, fp, 9027, "\n");- break;- case qh_PRINTpointnearest:- FOREACHpoint_(facet->coplanarset) {- int id, id2;- vertex= qh_nearvertex(qh, facet, point, &dist);- id= qh_pointid(qh, vertex->point);- id2= qh_pointid(qh, point);- qh_fprintf(qh, fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);- }- break;- case qh_PRINTpoints: /* VORONOI only by qh_printbegin */- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9029, "1 ");- qh_printcenter(qh, fp, format, NULL, facet);- break;- case qh_PRINTvertices:- qh_fprintf(qh, fp, 9030, "%d", qh_setsize(qh, facet->vertices));- FOREACHvertex_(facet->vertices)- qh_fprintf(qh, fp, 9031, " %d", qh_pointid(qh, vertex->point));- qh_fprintf(qh, fp, 9032, "\n");- break;- default:- break;- }-} /* printafacet */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printbegin">-</a>-- qh_printbegin(qh, )- prints header for all output formats-- returns:- checks for valid format-- notes:- uses qh.visit_id for 3/4off- changes qh.interior_point if printing centrums- qh_countfacets clears facet->visitid for non-good facets-- see- qh_printend() and qh_printafacet()-- design:- count facets and related statistics- print header for format-*/-void qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {- int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;- int i, num;- facetT *facet, **facetp;- vertexT *vertex, **vertexp;- setT *vertices;- pointT *point, **pointp, *pointtemp;-- qh->printoutnum= 0;- qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,- &totneighbors, &numridges, &numcoplanars, &numtricoplanars);- switch (format) {- case qh_PRINTnone:- break;- case qh_PRINTarea:- qh_fprintf(qh, fp, 9033, "%d\n", numfacets);- break;- case qh_PRINTcoplanars:- qh_fprintf(qh, fp, 9034, "%d\n", numfacets);- break;- case qh_PRINTcentrums:- if (qh->CENTERtype == qh_ASnone)- qh_clearcenters(qh, qh_AScentrum);- qh_fprintf(qh, fp, 9035, "%d\n%d\n", qh->hull_dim, numfacets);- break;- case qh_PRINTfacets:- case qh_PRINTfacets_xridge:- if (facetlist)- qh_printvertexlist(qh, fp, "Vertices and facets:\n", facetlist, facets, printall);- break;- case qh_PRINTgeom:- if (qh->hull_dim > 4) /* qh_initqhull_globals also checks */- goto LABELnoformat;- if (qh->VORONOI && qh->hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */- goto LABELnoformat;- if (qh->hull_dim == 2 && (qh->PRINTridges || qh->DOintersections))- qh_fprintf(qh, qh->ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");- if (qh->hull_dim == 4 && (qh->PRINTinner || qh->PRINTouter ||- (qh->PRINTdim == 4 && qh->PRINTcentrums)))- qh_fprintf(qh, qh->ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");- if (qh->PRINTdim == 4 && (qh->PRINTspheres))- qh_fprintf(qh, qh->ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");- if (qh->PRINTdim == 4 && qh->DOintersections && qh->PRINTnoplanes)- qh_fprintf(qh, qh->ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");- if (qh->PRINTdim == 2) {- qh_fprintf(qh, fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",- qh->rbox_command, qh->qhull_command);- }else if (qh->PRINTdim == 3) {- qh_fprintf(qh, fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",- qh->rbox_command, qh->qhull_command);- }else if (qh->PRINTdim == 4) {- qh->visit_id++;- num= 0;- FORALLfacet_(facetlist) /* get number of ridges to be printed */- qh_printend4geom(qh, NULL, facet, &num, printall);- FOREACHfacet_(facets)- qh_printend4geom(qh, NULL, facet, &num, printall);- qh->ridgeoutnum= num;- qh->printoutvar= 0; /* counts number of ridges in output */- qh_fprintf(qh, fp, 9038, "LIST # %s | %s\n", qh->rbox_command, qh->qhull_command);- }-- if (qh->PRINTdots) {- qh->printoutnum++;- num= qh->num_points + qh_setsize(qh, qh->other_points);- if (qh->DELAUNAY && qh->ATinfinity)- num--;- if (qh->PRINTdim == 4)- qh_fprintf(qh, fp, 9039, "4VECT %d %d 1\n", num, num);- else- qh_fprintf(qh, fp, 9040, "VECT %d %d 1\n", num, num);-- for (i=num; i--; ) {- if (i % 20 == 0)- qh_fprintf(qh, fp, 9041, "\n");- qh_fprintf(qh, fp, 9042, "1 ");- }- qh_fprintf(qh, fp, 9043, "# 1 point per line\n1 ");- for (i=num-1; i--; ) { /* num at least 3 for D2 */- if (i % 20 == 0)- qh_fprintf(qh, fp, 9044, "\n");- qh_fprintf(qh, fp, 9045, "0 ");- }- qh_fprintf(qh, fp, 9046, "# 1 color for all\n");- FORALLpoints {- if (!qh->DELAUNAY || !qh->ATinfinity || qh_pointid(qh, point) != qh->num_points-1) {- if (qh->PRINTdim == 4)- qh_printpoint(qh, fp, NULL, point);- else- qh_printpoint3(qh, fp, point);- }- }- FOREACHpoint_(qh->other_points) {- if (qh->PRINTdim == 4)- qh_printpoint(qh, fp, NULL, point);- else- qh_printpoint3(qh, fp, point);- }- qh_fprintf(qh, fp, 9047, "0 1 1 1 # color of points\n");- }-- if (qh->PRINTdim == 4 && !qh->PRINTnoplanes)- /* 4dview loads up multiple 4OFF objects slowly */- qh_fprintf(qh, fp, 9048, "4OFF %d %d 1\n", 3*qh->ridgeoutnum, qh->ridgeoutnum);- qh->PRINTcradius= 2 * qh->DISTround; /* include test DISTround */- if (qh->PREmerge) {- maximize_(qh->PRINTcradius, qh->premerge_centrum + qh->DISTround);- }else if (qh->POSTmerge)- maximize_(qh->PRINTcradius, qh->postmerge_centrum + qh->DISTround);- qh->PRINTradius= qh->PRINTcradius;- if (qh->PRINTspheres + qh->PRINTcoplanar)- maximize_(qh->PRINTradius, qh->MAXabs_coord * qh_MINradius);- if (qh->premerge_cos < REALmax/2) {- maximize_(qh->PRINTradius, (1- qh->premerge_cos) * qh->MAXabs_coord);- }else if (!qh->PREmerge && qh->POSTmerge && qh->postmerge_cos < REALmax/2) {- maximize_(qh->PRINTradius, (1- qh->postmerge_cos) * qh->MAXabs_coord);- }- maximize_(qh->PRINTradius, qh->MINvisible);- if (qh->JOGGLEmax < REALmax/2)- qh->PRINTradius += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);- if (qh->PRINTdim != 4 &&- (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {- vertices= qh_facetvertices(qh, facetlist, facets, printall);- if (qh->PRINTspheres && qh->PRINTdim <= 3)- qh_printspheres(qh, fp, vertices, qh->PRINTradius);- if (qh->PRINTcoplanar || qh->PRINTcentrums) {- qh->firstcentrum= True;- if (qh->PRINTcoplanar&& !qh->PRINTspheres) {- FOREACHvertex_(vertices)- qh_printpointvect2(qh, fp, vertex->point, NULL, qh->interior_point, qh->PRINTradius);- }- FORALLfacet_(facetlist) {- if (!printall && qh_skipfacet(qh, facet))- continue;- if (!facet->normal)- continue;- if (qh->PRINTcentrums && qh->PRINTdim <= 3)- qh_printcentrum(qh, fp, facet, qh->PRINTcradius);- if (!qh->PRINTcoplanar)- continue;- FOREACHpoint_(facet->coplanarset)- qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);- FOREACHpoint_(facet->outsideset)- qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);- }- FOREACHfacet_(facets) {- if (!printall && qh_skipfacet(qh, facet))- continue;- if (!facet->normal)- continue;- if (qh->PRINTcentrums && qh->PRINTdim <= 3)- qh_printcentrum(qh, fp, facet, qh->PRINTcradius);- if (!qh->PRINTcoplanar)- continue;- FOREACHpoint_(facet->coplanarset)- qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);- FOREACHpoint_(facet->outsideset)- qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);- }- }- qh_settempfree(qh, &vertices);- }- qh->visit_id++; /* for printing hyperplane intersections */- break;- case qh_PRINTids:- qh_fprintf(qh, fp, 9049, "%d\n", numfacets);- break;- case qh_PRINTincidences:- if (qh->VORONOI && qh->PRINTprecision)- qh_fprintf(qh, qh->ferr, 7053, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");- qh->printoutvar= qh->vertex_id; /* centrum id for non-simplicial facets */- if (qh->hull_dim <= 3)- qh_fprintf(qh, fp, 9050, "%d\n", numfacets);- else- qh_fprintf(qh, fp, 9051, "%d\n", numsimplicial+numridges);- break;- case qh_PRINTinner:- case qh_PRINTnormals:- case qh_PRINTouter:- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9052, "%s | %s\nbegin\n %d %d real\n", qh->rbox_command,- qh->qhull_command, numfacets, qh->hull_dim+1);- else- qh_fprintf(qh, fp, 9053, "%d\n%d\n", qh->hull_dim+1, numfacets);- break;- case qh_PRINTmathematica:- case qh_PRINTmaple:- if (qh->hull_dim > 3) /* qh_initbuffers also checks */- goto LABELnoformat;- if (qh->VORONOI)- qh_fprintf(qh, qh->ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");- if (format == qh_PRINTmaple) {- if (qh->hull_dim == 2)- qh_fprintf(qh, fp, 9054, "PLOT(CURVES(\n");- else- qh_fprintf(qh, fp, 9055, "PLOT3D(POLYGONS(\n");- }else- qh_fprintf(qh, fp, 9056, "{\n");- qh->printoutvar= 0; /* counts number of facets for notfirst */- break;- case qh_PRINTmerges:- qh_fprintf(qh, fp, 9057, "%d\n", numfacets);- break;- case qh_PRINTpointintersect:- qh_fprintf(qh, fp, 9058, "%d\n%d\n", qh->hull_dim, numfacets);- break;- case qh_PRINTneighbors:- qh_fprintf(qh, fp, 9059, "%d\n", numfacets);- break;- case qh_PRINToff:- case qh_PRINTtriangles:- if (qh->VORONOI)- goto LABELnoformat;- num = qh->hull_dim;- if (format == qh_PRINToff || qh->hull_dim == 2)- qh_fprintf(qh, fp, 9060, "%d\n%d %d %d\n", num,- qh->num_points+qh_setsize(qh, qh->other_points), numfacets, totneighbors/2);- else { /* qh_PRINTtriangles */- qh->printoutvar= qh->num_points+qh_setsize(qh, qh->other_points); /* first centrum */- if (qh->DELAUNAY)- num--; /* drop last dimension */- qh_fprintf(qh, fp, 9061, "%d\n%d %d %d\n", num, qh->printoutvar- + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);- }- FORALLpoints- qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);- FOREACHpoint_(qh->other_points)- qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);- if (format == qh_PRINTtriangles && qh->hull_dim > 2) {- FORALLfacets {- if (!facet->simplicial && facet->visitid)- qh_printcenter(qh, qh->fout, format, NULL, facet);- }- }- break;- case qh_PRINTpointnearest:- qh_fprintf(qh, fp, 9062, "%d\n", numcoplanars);- break;- case qh_PRINTpoints:- if (!qh->VORONOI)- goto LABELnoformat;- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,- qh->qhull_command, numfacets, qh->hull_dim);- else- qh_fprintf(qh, fp, 9064, "%d\n%d\n", qh->hull_dim-1, numfacets);- break;- case qh_PRINTvertices:- qh_fprintf(qh, fp, 9065, "%d\n", numfacets);- break;- case qh_PRINTsummary:- default:- LABELnoformat:- qh_fprintf(qh, qh->ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",- qh->hull_dim);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }-} /* printbegin */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printcenter">-</a>-- qh_printcenter(qh, fp, string, facet )- print facet->center as centrum or Voronoi center- string may be NULL. Don't include '%' codes.- nop if qh->CENTERtype neither CENTERvoronoi nor CENTERcentrum- if upper envelope of Delaunay triangulation and point at-infinity- prints qh_INFINITE instead;-- notes:- defines facet->center if needed- if format=PRINTgeom, adds a 0 if would otherwise be 2-d- Same as QhullFacet::printCenter-*/-void qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet) {- int k, num;-- if (qh->CENTERtype != qh_ASvoronoi && qh->CENTERtype != qh_AScentrum)- return;- if (string)- qh_fprintf(qh, fp, 9066, string);- if (qh->CENTERtype == qh_ASvoronoi) {- num= qh->hull_dim-1;- if (!facet->normal || !facet->upperdelaunay || !qh->ATinfinity) {- if (!facet->center)- facet->center= qh_facetcenter(qh, facet->vertices);- for (k=0; k < num; k++)- qh_fprintf(qh, fp, 9067, qh_REAL_1, facet->center[k]);- }else {- for (k=0; k < num; k++)- qh_fprintf(qh, fp, 9068, qh_REAL_1, qh_INFINITE);- }- }else /* qh->CENTERtype == qh_AScentrum */ {- num= qh->hull_dim;- if (format == qh_PRINTtriangles && qh->DELAUNAY)- num--;- if (!facet->center)- facet->center= qh_getcentrum(qh, facet);- for (k=0; k < num; k++)- qh_fprintf(qh, fp, 9069, qh_REAL_1, facet->center[k]);- }- if (format == qh_PRINTgeom && num == 2)- qh_fprintf(qh, fp, 9070, " 0\n");- else- qh_fprintf(qh, fp, 9071, "\n");-} /* printcenter */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printcentrum">-</a>-- qh_printcentrum(qh, fp, facet, radius )- print centrum for a facet in OOGL format- radius defines size of centrum- 2-d or 3-d only-- returns:- defines facet->center if needed-*/-void qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius) {- pointT *centrum, *projpt;- boolT tempcentrum= False;- realT xaxis[4], yaxis[4], normal[4], dist;- realT green[3]={0, 1, 0};- vertexT *apex;- int k;-- if (qh->CENTERtype == qh_AScentrum) {- if (!facet->center)- facet->center= qh_getcentrum(qh, facet);- centrum= facet->center;- }else {- centrum= qh_getcentrum(qh, facet);- tempcentrum= True;- }- qh_fprintf(qh, fp, 9072, "{appearance {-normal -edge normscale 0} ");- if (qh->firstcentrum) {- qh->firstcentrum= False;- qh_fprintf(qh, fp, 9073, "{INST geom { define centrum CQUAD # f%d\n\--0.3 -0.3 0.0001 0 0 1 1\n\- 0.3 -0.3 0.0001 0 0 1 1\n\- 0.3 0.3 0.0001 0 0 1 1\n\--0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);- }else- qh_fprintf(qh, fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);- apex= SETfirstt_(facet->vertices, vertexT);- qh_distplane(qh, apex->point, facet, &dist);- projpt= qh_projectpoint(qh, apex->point, facet, dist);- for (k=qh->hull_dim; k--; ) {- xaxis[k]= projpt[k] - centrum[k];- normal[k]= facet->normal[k];- }- if (qh->hull_dim == 2) {- xaxis[2]= 0;- normal[2]= 0;- }else if (qh->hull_dim == 4) {- qh_projectdim3(qh, xaxis, xaxis);- qh_projectdim3(qh, normal, normal);- qh_normalize2(qh, normal, qh->PRINTdim, True, NULL, NULL);- }- qh_crossproduct(3, xaxis, normal, yaxis);- qh_fprintf(qh, fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);- qh_fprintf(qh, fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);- qh_fprintf(qh, fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);- qh_printpoint3(qh, fp, centrum);- qh_fprintf(qh, fp, 9078, "1 }}}\n");- qh_memfree(qh, projpt, qh->normal_size);- qh_printpointvect(qh, fp, centrum, facet->normal, NULL, radius, green);- if (tempcentrum)- qh_memfree(qh, centrum, qh->normal_size);-} /* printcentrum */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printend">-</a>-- qh_printend(qh, fp, format )- prints trailer for all output formats-- see:- qh_printbegin() and qh_printafacet()--*/-void qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {- int num;- facetT *facet, **facetp;-- if (!qh->printoutnum)- qh_fprintf(qh, qh->ferr, 7055, "qhull warning: no facets printed\n");- switch (format) {- case qh_PRINTgeom:- if (qh->hull_dim == 4 && qh->DROPdim < 0 && !qh->PRINTnoplanes) {- qh->visit_id++;- num= 0;- FORALLfacet_(facetlist)- qh_printend4geom(qh, fp, facet,&num, printall);- FOREACHfacet_(facets)- qh_printend4geom(qh, fp, facet, &num, printall);- if (num != qh->ridgeoutnum || qh->printoutvar != qh->ridgeoutnum) {- qh_fprintf(qh, qh->ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh->ridgeoutnum, qh->printoutvar, num);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- }else- qh_fprintf(qh, fp, 9079, "}\n");- break;- case qh_PRINTinner:- case qh_PRINTnormals:- case qh_PRINTouter:- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9080, "end\n");- break;- case qh_PRINTmaple:- qh_fprintf(qh, fp, 9081, "));\n");- break;- case qh_PRINTmathematica:- qh_fprintf(qh, fp, 9082, "}\n");- break;- case qh_PRINTpoints:- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9083, "end\n");- break;- default:- break;- }-} /* printend */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printend4geom">-</a>-- qh_printend4geom(qh, fp, facet, numridges, printall )- helper function for qh_printbegin/printend-- returns:- number of printed ridges-- notes:- just counts printed ridges if fp=NULL- uses facet->visitid- must agree with qh_printfacet4geom...-- design:- computes color for facet from its normal- prints each ridge of facet-*/-void qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *nump, boolT printall) {- realT color[3];- int i, num= *nump;- facetT *neighbor, **neighborp;- ridgeT *ridge, **ridgep;-- if (!printall && qh_skipfacet(qh, facet))- return;- if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))- return;- if (!facet->normal)- return;- if (fp) {- for (i=0; i < 3; i++) {- color[i]= (facet->normal[i]+1.0)/2.0;- maximize_(color[i], -1.0);- minimize_(color[i], +1.0);- }- }- facet->visitid= qh->visit_id;- if (facet->simplicial) {- FOREACHneighbor_(facet) {- if (neighbor->visitid != qh->visit_id) {- if (fp)- qh_fprintf(qh, fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",- 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],- facet->id, neighbor->id);- num++;- }- }- }else {- FOREACHridge_(facet->ridges) {- neighbor= otherfacet_(ridge, facet);- if (neighbor->visitid != qh->visit_id) {- if (fp)- qh_fprintf(qh, fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",- 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],- ridge->id, facet->id, neighbor->id);- num++;- }- }- }- *nump= num;-} /* printend4geom */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printextremes">-</a>-- qh_printextremes(qh, fp, facetlist, facets, printall )- print extreme points for convex hulls or halfspace intersections-- notes:- #points, followed by ids, one per line-- sorted by id- same order as qh_printpoints_out if no coplanar/interior points-*/-void qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {- setT *vertices, *points;- pointT *point;- vertexT *vertex, **vertexp;- int id;- int numpoints=0, point_i, point_n;- int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);-- points= qh_settemp(qh, allpoints);- qh_setzero(qh, points, 0, allpoints);- vertices= qh_facetvertices(qh, facetlist, facets, printall);- FOREACHvertex_(vertices) {- id= qh_pointid(qh, vertex->point);- if (id >= 0) {- SETelem_(points, id)= vertex->point;- numpoints++;- }- }- qh_settempfree(qh, &vertices);- qh_fprintf(qh, fp, 9086, "%d\n", numpoints);- FOREACHpoint_i_(qh, points) {- if (point)- qh_fprintf(qh, fp, 9087, "%d\n", point_i);- }- qh_settempfree(qh, &points);-} /* printextremes */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printextremes_2d">-</a>-- qh_printextremes_2d(qh, fp, facetlist, facets, printall )- prints point ids for facets in qh_ORIENTclock order-- notes:- #points, followed by ids, one per line- if facetlist/facets are disjoint than the output includes skips- errors if facets form a loop- does not print coplanar points-*/-void qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {- int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;- setT *vertices;- facetT *facet, *startfacet, *nextfacet;- vertexT *vertexA, *vertexB;-- qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,- &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh->visit_id */- vertices= qh_facetvertices(qh, facetlist, facets, printall);- qh_fprintf(qh, fp, 9088, "%d\n", qh_setsize(qh, vertices));- qh_settempfree(qh, &vertices);- if (!numfacets)- return;- facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);- qh->vertex_visit++;- qh->visit_id++;- do {- if (facet->toporient ^ qh_ORIENTclock) {- vertexA= SETfirstt_(facet->vertices, vertexT);- vertexB= SETsecondt_(facet->vertices, vertexT);- nextfacet= SETfirstt_(facet->neighbors, facetT);- }else {- vertexA= SETsecondt_(facet->vertices, vertexT);- vertexB= SETfirstt_(facet->vertices, vertexT);- nextfacet= SETsecondt_(facet->neighbors, facetT);- }- if (facet->visitid == qh->visit_id) {- qh_fprintf(qh, qh->ferr, 6218, "Qhull internal error (qh_printextremes_2d): loop in facet list. facet %d nextfacet %d\n",- facet->id, nextfacet->id);- qh_errexit2(qh, qh_ERRqhull, facet, nextfacet);- }- if (facet->visitid) {- if (vertexA->visitid != qh->vertex_visit) {- vertexA->visitid= qh->vertex_visit;- qh_fprintf(qh, fp, 9089, "%d\n", qh_pointid(qh, vertexA->point));- }- if (vertexB->visitid != qh->vertex_visit) {- vertexB->visitid= qh->vertex_visit;- qh_fprintf(qh, fp, 9090, "%d\n", qh_pointid(qh, vertexB->point));- }- }- facet->visitid= qh->visit_id;- facet= nextfacet;- }while (facet && facet != startfacet);-} /* printextremes_2d */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printextremes_d">-</a>-- qh_printextremes_d(qh, fp, facetlist, facets, printall )- print extreme points of input sites for Delaunay triangulations-- notes:- #points, followed by ids, one per line-- unordered-*/-void qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {- setT *vertices;- vertexT *vertex, **vertexp;- boolT upperseen, lowerseen;- facetT *neighbor, **neighborp;- int numpoints=0;-- vertices= qh_facetvertices(qh, facetlist, facets, printall);- qh_vertexneighbors(qh);- FOREACHvertex_(vertices) {- upperseen= lowerseen= False;- FOREACHneighbor_(vertex) {- if (neighbor->upperdelaunay)- upperseen= True;- else- lowerseen= True;- }- if (upperseen && lowerseen) {- vertex->seen= True;- numpoints++;- }else- vertex->seen= False;- }- qh_fprintf(qh, fp, 9091, "%d\n", numpoints);- FOREACHvertex_(vertices) {- if (vertex->seen)- qh_fprintf(qh, fp, 9092, "%d\n", qh_pointid(qh, vertex->point));- }- qh_settempfree(qh, &vertices);-} /* printextremes_d */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet">-</a>-- qh_printfacet(qh, fp, facet )- prints all fields of a facet to fp-- notes:- ridges printed in neighbor order-*/-void qh_printfacet(qhT *qh, FILE *fp, facetT *facet) {-- qh_printfacetheader(qh, fp, facet);- if (facet->ridges)- qh_printfacetridges(qh, fp, facet);-} /* printfacet */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet2geom">-</a>-- qh_printfacet2geom(qh, fp, facet, color )- print facet as part of a 2-d VECT for Geomview-- notes:- assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon- mindist is calculated within io_r.c. maxoutside is calculated elsewhere- so a DISTround error may have occurred.-*/-void qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {- pointT *point0, *point1;- realT mindist, innerplane, outerplane;- int k;-- qh_facet2point(qh, facet, &point0, &point1, &mindist);- qh_geomplanes(qh, facet, &outerplane, &innerplane);- if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))- qh_printfacet2geom_points(qh, fp, point0, point1, facet, outerplane, color);- if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&- outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {- for (k=3; k--; )- color[k]= 1.0 - color[k];- qh_printfacet2geom_points(qh, fp, point0, point1, facet, innerplane, color);- }- qh_memfree(qh, point1, qh->normal_size);- qh_memfree(qh, point0, qh->normal_size);-} /* printfacet2geom */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet2geom_points">-</a>-- qh_printfacet2geom_points(qh, fp, point1, point2, facet, offset, color )- prints a 2-d facet as a VECT with 2 points at some offset.- The points are on the facet's plane.-*/-void qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,- facetT *facet, realT offset, realT color[3]) {- pointT *p1= point1, *p2= point2;-- qh_fprintf(qh, fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);- if (offset != 0.0) {- p1= qh_projectpoint(qh, p1, facet, -offset);- p2= qh_projectpoint(qh, p2, facet, -offset);- }- qh_fprintf(qh, fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",- p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);- if (offset != 0.0) {- qh_memfree(qh, p1, qh->normal_size);- qh_memfree(qh, p2, qh->normal_size);- }- qh_fprintf(qh, fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);-} /* printfacet2geom_points */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet2math">-</a>-- qh_printfacet2math(qh, fp, facet, format, notfirst )- print 2-d Maple or Mathematica output for a facet- may be non-simplicial-- notes:- use %16.8f since Mathematica 2.2 does not handle exponential format- see qh_printfacet3math-*/-void qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {- pointT *point0, *point1;- realT mindist;- const char *pointfmt;-- qh_facet2point(qh, facet, &point0, &point1, &mindist);- if (notfirst)- qh_fprintf(qh, fp, 9096, ",");- if (format == qh_PRINTmaple)- pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";- else- pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";- qh_fprintf(qh, fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);- qh_memfree(qh, point1, qh->normal_size);- qh_memfree(qh, point0, qh->normal_size);-} /* printfacet2math */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>-- qh_printfacet3geom_nonsimplicial(qh, fp, facet, color )- print Geomview OFF for a 3-d nonsimplicial facet.- if DOintersections, prints ridges to unvisited neighbors(qh->visit_id)-- notes- uses facet->visitid for intersections and ridges-*/-void qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {- ridgeT *ridge, **ridgep;- setT *projectedpoints, *vertices;- vertexT *vertex, **vertexp, *vertexA, *vertexB;- pointT *projpt, *point, **pointp;- facetT *neighbor;- realT dist, outerplane, innerplane;- int cntvertices, k;- realT black[3]={0, 0, 0}, green[3]={0, 1, 0};-- qh_geomplanes(qh, facet, &outerplane, &innerplane);- vertices= qh_facet3vertex(qh, facet); /* oriented */- cntvertices= qh_setsize(qh, vertices);- projectedpoints= qh_settemp(qh, cntvertices);- FOREACHvertex_(vertices) {- zinc_(Zdistio);- qh_distplane(qh, vertex->point, facet, &dist);- projpt= qh_projectpoint(qh, vertex->point, facet, dist);- qh_setappend(qh, &projectedpoints, projpt);- }- if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))- qh_printfacet3geom_points(qh, fp, projectedpoints, facet, outerplane, color);- if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&- outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {- for (k=3; k--; )- color[k]= 1.0 - color[k];- qh_printfacet3geom_points(qh, fp, projectedpoints, facet, innerplane, color);- }- FOREACHpoint_(projectedpoints)- qh_memfree(qh, point, qh->normal_size);- qh_settempfree(qh, &projectedpoints);- qh_settempfree(qh, &vertices);- if ((qh->DOintersections || qh->PRINTridges)- && (!facet->visible || !qh->NEWfacets)) {- facet->visitid= qh->visit_id;- FOREACHridge_(facet->ridges) {- neighbor= otherfacet_(ridge, facet);- if (neighbor->visitid != qh->visit_id) {- if (qh->DOintersections)- qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, black);- if (qh->PRINTridges) {- vertexA= SETfirstt_(ridge->vertices, vertexT);- vertexB= SETsecondt_(ridge->vertices, vertexT);- qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);- }- }- }- }-} /* printfacet3geom_nonsimplicial */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet3geom_points">-</a>-- qh_printfacet3geom_points(qh, fp, points, facet, offset )- prints a 3-d facet as OFF Geomview object.- offset is relative to the facet's hyperplane- Facet is determined as a list of points-*/-void qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {- int k, n= qh_setsize(qh, points), i;- pointT *point, **pointp;- setT *printpoints;-- qh_fprintf(qh, fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);- if (offset != 0.0) {- printpoints= qh_settemp(qh, n);- FOREACHpoint_(points)- qh_setappend(qh, &printpoints, qh_projectpoint(qh, point, facet, -offset));- }else- printpoints= points;- FOREACHpoint_(printpoints) {- for (k=0; k < qh->hull_dim; k++) {- if (k == qh->DROPdim)- qh_fprintf(qh, fp, 9099, "0 ");- else- qh_fprintf(qh, fp, 9100, "%8.4g ", point[k]);- }- if (printpoints != points)- qh_memfree(qh, point, qh->normal_size);- qh_fprintf(qh, fp, 9101, "\n");- }- if (printpoints != points)- qh_settempfree(qh, &printpoints);- qh_fprintf(qh, fp, 9102, "%d ", n);- for (i=0; i < n; i++)- qh_fprintf(qh, fp, 9103, "%d ", i);- qh_fprintf(qh, fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);-} /* printfacet3geom_points */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>-- qh_printfacet3geom_simplicial(qh, )- print Geomview OFF for a 3-d simplicial facet.-- notes:- may flip color- uses facet->visitid for intersections and ridges-- assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon- innerplane may be off by qh->DISTround. Maxoutside is calculated elsewhere- so a DISTround error may have occurred.-*/-void qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {- setT *points, *vertices;- vertexT *vertex, **vertexp, *vertexA, *vertexB;- facetT *neighbor, **neighborp;- realT outerplane, innerplane;- realT black[3]={0, 0, 0}, green[3]={0, 1, 0};- int k;-- qh_geomplanes(qh, facet, &outerplane, &innerplane);- vertices= qh_facet3vertex(qh, facet);- points= qh_settemp(qh, qh->TEMPsize);- FOREACHvertex_(vertices)- qh_setappend(qh, &points, vertex->point);- if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))- qh_printfacet3geom_points(qh, fp, points, facet, outerplane, color);- if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&- outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {- for (k=3; k--; )- color[k]= 1.0 - color[k];- qh_printfacet3geom_points(qh, fp, points, facet, innerplane, color);- }- qh_settempfree(qh, &points);- qh_settempfree(qh, &vertices);- if ((qh->DOintersections || qh->PRINTridges)- && (!facet->visible || !qh->NEWfacets)) {- facet->visitid= qh->visit_id;- FOREACHneighbor_(facet) {- if (neighbor->visitid != qh->visit_id) {- vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,- SETindex_(facet->neighbors, neighbor), 0);- if (qh->DOintersections)- qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, black);- if (qh->PRINTridges) {- vertexA= SETfirstt_(vertices, vertexT);- vertexB= SETsecondt_(vertices, vertexT);- qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);- }- qh_setfree(qh, &vertices);- }- }- }-} /* printfacet3geom_simplicial */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet3math">-</a>-- qh_printfacet3math(qh, fp, facet, notfirst )- print 3-d Maple or Mathematica output for a facet-- notes:- may be non-simplicial- use %16.8f since Mathematica 2.2 does not handle exponential format- see qh_printfacet2math-*/-void qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {- vertexT *vertex, **vertexp;- setT *points, *vertices;- pointT *point, **pointp;- boolT firstpoint= True;- realT dist;- const char *pointfmt, *endfmt;-- if (notfirst)- qh_fprintf(qh, fp, 9105, ",\n");- vertices= qh_facet3vertex(qh, facet);- points= qh_settemp(qh, qh_setsize(qh, vertices));- FOREACHvertex_(vertices) {- zinc_(Zdistio);- qh_distplane(qh, vertex->point, facet, &dist);- point= qh_projectpoint(qh, vertex->point, facet, dist);- qh_setappend(qh, &points, point);- }- if (format == qh_PRINTmaple) {- qh_fprintf(qh, fp, 9106, "[");- pointfmt= "[%16.8f, %16.8f, %16.8f]";- endfmt= "]";- }else {- qh_fprintf(qh, fp, 9107, "Polygon[{");- pointfmt= "{%16.8f, %16.8f, %16.8f}";- endfmt= "}]";- }- FOREACHpoint_(points) {- if (firstpoint)- firstpoint= False;- else- qh_fprintf(qh, fp, 9108, ",\n");- qh_fprintf(qh, fp, 9109, pointfmt, point[0], point[1], point[2]);- }- FOREACHpoint_(points)- qh_memfree(qh, point, qh->normal_size);- qh_settempfree(qh, &points);- qh_settempfree(qh, &vertices);- qh_fprintf(qh, fp, 9110, "%s", endfmt);-} /* printfacet3math */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet3vertex">-</a>-- qh_printfacet3vertex(qh, fp, facet, format )- print vertices in a 3-d facet as point ids-- notes:- prints number of vertices first if format == qh_PRINToff- the facet may be non-simplicial-*/-void qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {- vertexT *vertex, **vertexp;- setT *vertices;-- vertices= qh_facet3vertex(qh, facet);- if (format == qh_PRINToff)- qh_fprintf(qh, fp, 9111, "%d ", qh_setsize(qh, vertices));- FOREACHvertex_(vertices)- qh_fprintf(qh, fp, 9112, "%d ", qh_pointid(qh, vertex->point));- qh_fprintf(qh, fp, 9113, "\n");- qh_settempfree(qh, &vertices);-} /* printfacet3vertex */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>-- qh_printfacet4geom_nonsimplicial(qh, )- print Geomview 4OFF file for a 4d nonsimplicial facet- prints all ridges to unvisited neighbors (qh.visit_id)- if qh.DROPdim- prints in OFF format-- notes:- must agree with printend4geom()-*/-void qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {- facetT *neighbor;- ridgeT *ridge, **ridgep;- vertexT *vertex, **vertexp;- pointT *point;- int k;- realT dist;-- facet->visitid= qh->visit_id;- if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))- return;- FOREACHridge_(facet->ridges) {- neighbor= otherfacet_(ridge, facet);- if (neighbor->visitid == qh->visit_id)- continue;- if (qh->PRINTtransparent && !neighbor->good)- continue;- if (qh->DOintersections)- qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, color);- else {- if (qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);- else {- qh->printoutvar++;- qh_fprintf(qh, fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);- }- FOREACHvertex_(ridge->vertices) {- zinc_(Zdistio);- qh_distplane(qh, vertex->point,facet, &dist);- point=qh_projectpoint(qh, vertex->point,facet, dist);- for (k=0; k < qh->hull_dim; k++) {- if (k != qh->DROPdim)- qh_fprintf(qh, fp, 9116, "%8.4g ", point[k]);- }- qh_fprintf(qh, fp, 9117, "\n");- qh_memfree(qh, point, qh->normal_size);- }- if (qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);- }- }-} /* printfacet4geom_nonsimplicial */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>-- qh_printfacet4geom_simplicial(qh, fp, facet, color )- print Geomview 4OFF file for a 4d simplicial facet- prints triangles for unvisited neighbors (qh.visit_id)-- notes:- must agree with printend4geom()-*/-void qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {- setT *vertices;- facetT *neighbor, **neighborp;- vertexT *vertex, **vertexp;- int k;-- facet->visitid= qh->visit_id;- if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))- return;- FOREACHneighbor_(facet) {- if (neighbor->visitid == qh->visit_id)- continue;- if (qh->PRINTtransparent && !neighbor->good)- continue;- vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,- SETindex_(facet->neighbors, neighbor), 0);- if (qh->DOintersections)- qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, color);- else {- if (qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",- facet->id, neighbor->id);- else {- qh->printoutvar++;- qh_fprintf(qh, fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);- }- FOREACHvertex_(vertices) {- for (k=0; k < qh->hull_dim; k++) {- if (k != qh->DROPdim)- qh_fprintf(qh, fp, 9121, "%8.4g ", vertex->point[k]);- }- qh_fprintf(qh, fp, 9122, "\n");- }- if (qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);- }- qh_setfree(qh, &vertices);- }-} /* printfacet4geom_simplicial */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>-- qh_printfacetNvertex_nonsimplicial(qh, fp, facet, id, format )- print vertices for an N-d non-simplicial facet- triangulates each ridge to the id-*/-void qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format) {- vertexT *vertex, **vertexp;- ridgeT *ridge, **ridgep;-- if (facet->visible && qh->NEWfacets)- return;- FOREACHridge_(facet->ridges) {- if (format == qh_PRINTtriangles)- qh_fprintf(qh, fp, 9124, "%d ", qh->hull_dim);- qh_fprintf(qh, fp, 9125, "%d ", id);- if ((ridge->top == facet) ^ qh_ORIENTclock) {- FOREACHvertex_(ridge->vertices)- qh_fprintf(qh, fp, 9126, "%d ", qh_pointid(qh, vertex->point));- }else {- FOREACHvertexreverse12_(ridge->vertices)- qh_fprintf(qh, fp, 9127, "%d ", qh_pointid(qh, vertex->point));- }- qh_fprintf(qh, fp, 9128, "\n");- }-} /* printfacetNvertex_nonsimplicial */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>-- qh_printfacetNvertex_simplicial(qh, fp, facet, format )- print vertices for an N-d simplicial facet- prints vertices for non-simplicial facets- 2-d facets (orientation preserved by qh_mergefacet2d)- PRINToff ('o') for 4-d and higher-*/-void qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {- vertexT *vertex, **vertexp;-- if (format == qh_PRINToff || format == qh_PRINTtriangles)- qh_fprintf(qh, fp, 9129, "%d ", qh_setsize(qh, facet->vertices));- if ((facet->toporient ^ qh_ORIENTclock)- || (qh->hull_dim > 2 && !facet->simplicial)) {- FOREACHvertex_(facet->vertices)- qh_fprintf(qh, fp, 9130, "%d ", qh_pointid(qh, vertex->point));- }else {- FOREACHvertexreverse12_(facet->vertices)- qh_fprintf(qh, fp, 9131, "%d ", qh_pointid(qh, vertex->point));- }- qh_fprintf(qh, fp, 9132, "\n");-} /* printfacetNvertex_simplicial */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacetheader">-</a>-- qh_printfacetheader(qh, fp, facet )- prints header fields of a facet to fp-- notes:- for 'f' output and debugging- Same as QhullFacet::printHeader()-*/-void qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet) {- pointT *point, **pointp, *furthest;- facetT *neighbor, **neighborp;- realT dist;-- if (facet == qh_MERGEridge) {- qh_fprintf(qh, fp, 9133, " MERGEridge\n");- return;- }else if (facet == qh_DUPLICATEridge) {- qh_fprintf(qh, fp, 9134, " DUPLICATEridge\n");- return;- }else if (!facet) {- qh_fprintf(qh, fp, 9135, " NULLfacet\n");- return;- }- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- qh_fprintf(qh, fp, 9136, "- f%d\n", facet->id);- qh_fprintf(qh, fp, 9137, " - flags:");- if (facet->toporient)- qh_fprintf(qh, fp, 9138, " top");- else- qh_fprintf(qh, fp, 9139, " bottom");- if (facet->simplicial)- qh_fprintf(qh, fp, 9140, " simplicial");- if (facet->tricoplanar)- qh_fprintf(qh, fp, 9141, " tricoplanar");- if (facet->upperdelaunay)- qh_fprintf(qh, fp, 9142, " upperDelaunay");- if (facet->visible)- qh_fprintf(qh, fp, 9143, " visible");- if (facet->newfacet)- qh_fprintf(qh, fp, 9144, " new");- if (facet->tested)- qh_fprintf(qh, fp, 9145, " tested");- if (!facet->good)- qh_fprintf(qh, fp, 9146, " notG");- if (facet->seen)- qh_fprintf(qh, fp, 9147, " seen");- if (facet->coplanar)- qh_fprintf(qh, fp, 9148, " coplanar");- if (facet->mergehorizon)- qh_fprintf(qh, fp, 9149, " mergehorizon");- if (facet->keepcentrum)- qh_fprintf(qh, fp, 9150, " keepcentrum");- if (facet->dupridge)- qh_fprintf(qh, fp, 9151, " dupridge");- if (facet->mergeridge && !facet->mergeridge2)- qh_fprintf(qh, fp, 9152, " mergeridge1");- if (facet->mergeridge2)- qh_fprintf(qh, fp, 9153, " mergeridge2");- if (facet->newmerge)- qh_fprintf(qh, fp, 9154, " newmerge");- if (facet->flipped)- qh_fprintf(qh, fp, 9155, " flipped");- if (facet->notfurthest)- qh_fprintf(qh, fp, 9156, " notfurthest");- if (facet->degenerate)- qh_fprintf(qh, fp, 9157, " degenerate");- if (facet->redundant)- qh_fprintf(qh, fp, 9158, " redundant");- qh_fprintf(qh, fp, 9159, "\n");- if (facet->isarea)- qh_fprintf(qh, fp, 9160, " - area: %2.2g\n", facet->f.area);- else if (qh->NEWfacets && facet->visible && facet->f.replace)- qh_fprintf(qh, fp, 9161, " - replacement: f%d\n", facet->f.replace->id);- else if (facet->newfacet) {- if (facet->f.samecycle && facet->f.samecycle != facet)- qh_fprintf(qh, fp, 9162, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);- }else if (facet->tricoplanar /* !isarea */) {- if (facet->f.triowner)- qh_fprintf(qh, fp, 9163, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);- }else if (facet->f.newcycle)- qh_fprintf(qh, fp, 9164, " - was horizon to f%d\n", facet->f.newcycle->id);- if (facet->nummerge)- qh_fprintf(qh, fp, 9165, " - merges: %d\n", facet->nummerge);- qh_printpointid(qh, fp, " - normal: ", qh->hull_dim, facet->normal, qh_IDunknown);- qh_fprintf(qh, fp, 9166, " - offset: %10.7g\n", facet->offset);- if (qh->CENTERtype == qh_ASvoronoi || facet->center)- qh_printcenter(qh, fp, qh_PRINTfacets, " - center: ", facet);-#if qh_MAXoutside- if (facet->maxoutside > qh->DISTround)- qh_fprintf(qh, fp, 9167, " - maxoutside: %10.7g\n", facet->maxoutside);-#endif- if (!SETempty_(facet->outsideset)) {- furthest= (pointT*)qh_setlast(facet->outsideset);- if (qh_setsize(qh, facet->outsideset) < 6) {- qh_fprintf(qh, fp, 9168, " - outside set(furthest p%d):\n", qh_pointid(qh, furthest));- FOREACHpoint_(facet->outsideset)- qh_printpoint(qh, fp, " ", point);- }else if (qh_setsize(qh, facet->outsideset) < 21) {- qh_printpoints(qh, fp, " - outside set:", facet->outsideset);- }else {- qh_fprintf(qh, fp, 9169, " - outside set: %d points.", qh_setsize(qh, facet->outsideset));- qh_printpoint(qh, fp, " Furthest", furthest);- }-#if !qh_COMPUTEfurthest- qh_fprintf(qh, fp, 9170, " - furthest distance= %2.2g\n", facet->furthestdist);-#endif- }- if (!SETempty_(facet->coplanarset)) {- furthest= (pointT*)qh_setlast(facet->coplanarset);- if (qh_setsize(qh, facet->coplanarset) < 6) {- qh_fprintf(qh, fp, 9171, " - coplanar set(furthest p%d):\n", qh_pointid(qh, furthest));- FOREACHpoint_(facet->coplanarset)- qh_printpoint(qh, fp, " ", point);- }else if (qh_setsize(qh, facet->coplanarset) < 21) {- qh_printpoints(qh, fp, " - coplanar set:", facet->coplanarset);- }else {- qh_fprintf(qh, fp, 9172, " - coplanar set: %d points.", qh_setsize(qh, facet->coplanarset));- qh_printpoint(qh, fp, " Furthest", furthest);- }- zinc_(Zdistio);- qh_distplane(qh, furthest, facet, &dist);- qh_fprintf(qh, fp, 9173, " furthest distance= %2.2g\n", dist);- }- qh_printvertices(qh, fp, " - vertices:", facet->vertices);- qh_fprintf(qh, fp, 9174, " - neighboring facets:");- FOREACHneighbor_(facet) {- if (neighbor == qh_MERGEridge)- qh_fprintf(qh, fp, 9175, " MERGE");- else if (neighbor == qh_DUPLICATEridge)- qh_fprintf(qh, fp, 9176, " DUP");- else- qh_fprintf(qh, fp, 9177, " f%d", neighbor->id);- }- qh_fprintf(qh, fp, 9178, "\n");- qh->RANDOMdist= qh->old_randomdist;-} /* printfacetheader */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacetridges">-</a>-- qh_printfacetridges(qh, fp, facet )- prints ridges of a facet to fp-- notes:- ridges printed in neighbor order- assumes the ridges exist- for 'f' output- same as QhullFacet::printRidges-*/-void qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet) {- facetT *neighbor, **neighborp;- ridgeT *ridge, **ridgep;- int numridges= 0;--- if (facet->visible && qh->NEWfacets) {- qh_fprintf(qh, fp, 9179, " - ridges(ids may be garbage):");- FOREACHridge_(facet->ridges)- qh_fprintf(qh, fp, 9180, " r%d", ridge->id);- qh_fprintf(qh, fp, 9181, "\n");- }else {- qh_fprintf(qh, fp, 9182, " - ridges:\n");- FOREACHridge_(facet->ridges)- ridge->seen= False;- if (qh->hull_dim == 3) {- ridge= SETfirstt_(facet->ridges, ridgeT);- while (ridge && !ridge->seen) {- ridge->seen= True;- qh_printridge(qh, fp, ridge);- numridges++;- ridge= qh_nextridge3d(ridge, facet, NULL);- }- }else {- FOREACHneighbor_(facet) {- FOREACHridge_(facet->ridges) {- if (otherfacet_(ridge,facet) == neighbor) {- ridge->seen= True;- qh_printridge(qh, fp, ridge);- numridges++;- }- }- }- }- if (numridges != qh_setsize(qh, facet->ridges)) {- qh_fprintf(qh, fp, 9183, " - all ridges:");- FOREACHridge_(facet->ridges)- qh_fprintf(qh, fp, 9184, " r%d", ridge->id);- qh_fprintf(qh, fp, 9185, "\n");- }- FOREACHridge_(facet->ridges) {- if (!ridge->seen)- qh_printridge(qh, fp, ridge);- }- }-} /* printfacetridges */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printfacets">-</a>-- qh_printfacets(qh, fp, format, facetlist, facets, printall )- prints facetlist and/or facet set in output format-- notes:- also used for specialized formats ('FO' and summary)- turns off 'Rn' option since want actual numbers-*/-void qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {- int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;- facetT *facet, **facetp;- setT *vertices;- coordT *center;- realT outerplane, innerplane;-- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- if (qh->CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))- qh_fprintf(qh, qh->ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");- if (format == qh_PRINTnone)- ; /* print nothing */- else if (format == qh_PRINTaverage) {- vertices= qh_facetvertices(qh, facetlist, facets, printall);- center= qh_getcenter(qh, vertices);- qh_fprintf(qh, fp, 9186, "%d 1\n", qh->hull_dim);- qh_printpointid(qh, fp, NULL, qh->hull_dim, center, qh_IDunknown);- qh_memfree(qh, center, qh->normal_size);- qh_settempfree(qh, &vertices);- }else if (format == qh_PRINTextremes) {- if (qh->DELAUNAY)- qh_printextremes_d(qh, fp, facetlist, facets, printall);- else if (qh->hull_dim == 2)- qh_printextremes_2d(qh, fp, facetlist, facets, printall);- else- qh_printextremes(qh, fp, facetlist, facets, printall);- }else if (format == qh_PRINToptions)- qh_fprintf(qh, fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);- else if (format == qh_PRINTpoints && !qh->VORONOI)- qh_printpoints_out(qh, fp, facetlist, facets, printall);- else if (format == qh_PRINTqhull)- qh_fprintf(qh, fp, 9188, "%s | %s\n", qh->rbox_command, qh->qhull_command);- else if (format == qh_PRINTsize) {- qh_fprintf(qh, fp, 9189, "0\n2 ");- qh_fprintf(qh, fp, 9190, qh_REAL_1, qh->totarea);- qh_fprintf(qh, fp, 9191, qh_REAL_1, qh->totvol);- qh_fprintf(qh, fp, 9192, "\n");- }else if (format == qh_PRINTsummary) {- qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,- &totneighbors, &numridges, &numcoplanars, &numtricoplanars);- vertices= qh_facetvertices(qh, facetlist, facets, printall);- qh_fprintf(qh, fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh->hull_dim,- qh->num_points + qh_setsize(qh, qh->other_points),- qh->num_vertices, qh->num_facets - qh->num_visible,- qh_setsize(qh, vertices), numfacets, numcoplanars,- numfacets - numsimplicial, zzval_(Zdelvertextot),- numtricoplanars);- qh_settempfree(qh, &vertices);- qh_outerinner(qh, NULL, &outerplane, &innerplane);- qh_fprintf(qh, fp, 9194, qh_REAL_2n, outerplane, innerplane);- }else if (format == qh_PRINTvneighbors)- qh_printvneighbors(qh, fp, facetlist, facets, printall);- else if (qh->VORONOI && format == qh_PRINToff)- qh_printvoronoi(qh, fp, format, facetlist, facets, printall);- else if (qh->VORONOI && format == qh_PRINTgeom) {- qh_printbegin(qh, fp, format, facetlist, facets, printall);- qh_printvoronoi(qh, fp, format, facetlist, facets, printall);- qh_printend(qh, fp, format, facetlist, facets, printall);- }else if (qh->VORONOI- && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))- qh_printvdiagram(qh, fp, format, facetlist, facets, printall);- else {- qh_printbegin(qh, fp, format, facetlist, facets, printall);- FORALLfacet_(facetlist)- qh_printafacet(qh, fp, format, facet, printall);- FOREACHfacet_(facets)- qh_printafacet(qh, fp, format, facet, printall);- qh_printend(qh, fp, format, facetlist, facets, printall);- }- qh->RANDOMdist= qh->old_randomdist;-} /* printfacets */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printhyperplaneintersection">-</a>-- qh_printhyperplaneintersection(qh, fp, facet1, facet2, vertices, color )- print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d-*/-void qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,- setT *vertices, realT color[3]) {- realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];- vertexT *vertex, **vertexp;- int i, k;- boolT nearzero1, nearzero2;-- costheta= qh_getangle(qh, facet1->normal, facet2->normal);- denominator= 1 - costheta * costheta;- i= qh_setsize(qh, vertices);- if (qh->hull_dim == 3)- qh_fprintf(qh, fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);- else if (qh->hull_dim == 4 && qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9196, "OFF 3 1 1 ");- else- qh->printoutvar++;- qh_fprintf(qh, fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);- mindenom= 1 / (10.0 * qh->MAXabs_coord);- FOREACHvertex_(vertices) {- zadd_(Zdistio, 2);- qh_distplane(qh, vertex->point, facet1, &dist1);- qh_distplane(qh, vertex->point, facet2, &dist2);- s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);- t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);- if (nearzero1 || nearzero2)- s= t= 0.0;- for (k=qh->hull_dim; k--; )- p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;- if (qh->PRINTdim <= 3) {- qh_projectdim3(qh, p, p);- qh_fprintf(qh, fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);- }else- qh_fprintf(qh, fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);- if (nearzero1+nearzero2)- qh_fprintf(qh, fp, 9200, "p%d(coplanar facets)\n", qh_pointid(qh, vertex->point));- else- qh_fprintf(qh, fp, 9201, "projected p%d\n", qh_pointid(qh, vertex->point));- }- if (qh->hull_dim == 3)- qh_fprintf(qh, fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);- else if (qh->hull_dim == 4 && qh->DROPdim >= 0)- qh_fprintf(qh, fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);-} /* printhyperplaneintersection */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printline3geom">-</a>-- qh_printline3geom(qh, fp, pointA, pointB, color )- prints a line as a VECT- prints 0's for qh.DROPdim-- notes:- if pointA == pointB,- it's a 1 point VECT-*/-void qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {- int k;- realT pA[4], pB[4];-- qh_projectdim3(qh, pointA, pA);- qh_projectdim3(qh, pointB, pB);- if ((fabs(pA[0] - pB[0]) > 1e-3) ||- (fabs(pA[1] - pB[1]) > 1e-3) ||- (fabs(pA[2] - pB[2]) > 1e-3)) {- qh_fprintf(qh, fp, 9204, "VECT 1 2 1 2 1\n");- for (k=0; k < 3; k++)- qh_fprintf(qh, fp, 9205, "%8.4g ", pB[k]);- qh_fprintf(qh, fp, 9206, " # p%d\n", qh_pointid(qh, pointB));- }else- qh_fprintf(qh, fp, 9207, "VECT 1 1 1 1 1\n");- for (k=0; k < 3; k++)- qh_fprintf(qh, fp, 9208, "%8.4g ", pA[k]);- qh_fprintf(qh, fp, 9209, " # p%d\n", qh_pointid(qh, pointA));- qh_fprintf(qh, fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);-}--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printneighborhood">-</a>-- qh_printneighborhood(qh, fp, format, facetA, facetB, printall )- print neighborhood of one or two facets-- notes:- calls qh_findgood_all()- bumps qh.visit_id-*/-void qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {- facetT *neighbor, **neighborp, *facet;- setT *facets;-- if (format == qh_PRINTnone)- return;- qh_findgood_all(qh, qh->facet_list);- if (facetA == facetB)- facetB= NULL;- facets= qh_settemp(qh, 2*(qh_setsize(qh, facetA->neighbors)+1));- qh->visit_id++;- for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {- if (facet->visitid != qh->visit_id) {- facet->visitid= qh->visit_id;- qh_setappend(qh, &facets, facet);- }- FOREACHneighbor_(facet) {- if (neighbor->visitid == qh->visit_id)- continue;- neighbor->visitid= qh->visit_id;- if (printall || !qh_skipfacet(qh, neighbor))- qh_setappend(qh, &facets, neighbor);- }- }- qh_printfacets(qh, fp, format, NULL, facets, printall);- qh_settempfree(qh, &facets);-} /* printneighborhood */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printpoint">-</a>-- qh_printpoint(qh, fp, string, point )- qh_printpointid(qh, fp, string, dim, point, id )- prints the coordinates of a point-- returns:- if string is defined- prints 'string p%d'. Skips p%d if id=qh_IDunknown(-1) or qh_IDnone(-3)-- notes:- nop if point is NULL- Same as QhullPoint's printPoint-*/-void qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point) {- int id= qh_pointid(qh, point);-- qh_printpointid(qh, fp, string, qh->hull_dim, point, id);-} /* printpoint */--void qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id) {- int k;- realT r; /*bug fix*/-- if (!point)- return;- if (string) {- qh_fprintf(qh, fp, 9211, "%s", string);- if (id != qh_IDunknown && id != qh_IDnone)- qh_fprintf(qh, fp, 9212, " p%d: ", id);- }- for (k=dim; k--; ) {- r= *point++;- if (string)- qh_fprintf(qh, fp, 9213, " %8.4g", r);- else- qh_fprintf(qh, fp, 9214, qh_REAL_1, r);- }- qh_fprintf(qh, fp, 9215, "\n");-} /* printpointid */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printpoint3">-</a>-- qh_printpoint3(qh, fp, point )- prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates-*/-void qh_printpoint3(qhT *qh, FILE *fp, pointT *point) {- int k;- realT p[4];-- qh_projectdim3(qh, point, p);- for (k=0; k < 3; k++)- qh_fprintf(qh, fp, 9216, "%8.4g ", p[k]);- qh_fprintf(qh, fp, 9217, " # p%d\n", qh_pointid(qh, point));-} /* printpoint3 */--/*------------------------------------------printpoints- print pointids for a set of points starting at index- see geom_r.c-*/--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printpoints_out">-</a>-- qh_printpoints_out(qh, fp, facetlist, facets, printall )- prints vertices, coplanar/inside points, for facets by their point coordinates- allows qh.CDDoutput-- notes:- same format as qhull input- if no coplanar/interior points,- same order as qh_printextremes-*/-void qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {- int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);- int numpoints=0, point_i, point_n;- setT *vertices, *points;- facetT *facet, **facetp;- pointT *point, **pointp;- vertexT *vertex, **vertexp;- int id;-- points= qh_settemp(qh, allpoints);- qh_setzero(qh, points, 0, allpoints);- vertices= qh_facetvertices(qh, facetlist, facets, printall);- FOREACHvertex_(vertices) {- id= qh_pointid(qh, vertex->point);- if (id >= 0)- SETelem_(points, id)= vertex->point;- }- if (qh->KEEPinside || qh->KEEPcoplanar || qh->KEEPnearinside) {- FORALLfacet_(facetlist) {- if (!printall && qh_skipfacet(qh, facet))- continue;- FOREACHpoint_(facet->coplanarset) {- id= qh_pointid(qh, point);- if (id >= 0)- SETelem_(points, id)= point;- }- }- FOREACHfacet_(facets) {- if (!printall && qh_skipfacet(qh, facet))- continue;- FOREACHpoint_(facet->coplanarset) {- id= qh_pointid(qh, point);- if (id >= 0)- SETelem_(points, id)= point;- }- }- }- qh_settempfree(qh, &vertices);- FOREACHpoint_i_(qh, points) {- if (point)- numpoints++;- }- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,- qh->qhull_command, numpoints, qh->hull_dim + 1);- else- qh_fprintf(qh, fp, 9219, "%d\n%d\n", qh->hull_dim, numpoints);- FOREACHpoint_i_(qh, points) {- if (point) {- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9220, "1 ");- qh_printpoint(qh, fp, NULL, point);- }- }- if (qh->CDDoutput)- qh_fprintf(qh, fp, 9221, "end\n");- qh_settempfree(qh, &points);-} /* printpoints_out */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printpointvect">-</a>-- qh_printpointvect(qh, fp, point, normal, center, radius, color )- prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point-*/-void qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {- realT diff[4], pointA[4];- int k;-- for (k=qh->hull_dim; k--; ) {- if (center)- diff[k]= point[k]-center[k];- else if (normal)- diff[k]= normal[k];- else- diff[k]= 0;- }- if (center)- qh_normalize2(qh, diff, qh->hull_dim, True, NULL, NULL);- for (k=qh->hull_dim; k--; )- pointA[k]= point[k]+diff[k] * radius;- qh_printline3geom(qh, fp, point, pointA, color);-} /* printpointvect */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printpointvect2">-</a>-- qh_printpointvect2(qh, fp, point, normal, center, radius )- prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point-*/-void qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {- realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};-- qh_printpointvect(qh, fp, point, normal, center, radius, red);- qh_printpointvect(qh, fp, point, normal, center, -radius, yellow);-} /* printpointvect2 */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printridge">-</a>-- qh_printridge(qh, fp, ridge )- prints the information in a ridge-- notes:- for qh_printfacetridges()- same as operator<< [QhullRidge.cpp]-*/-void qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge) {-- qh_fprintf(qh, fp, 9222, " - r%d", ridge->id);- if (ridge->tested)- qh_fprintf(qh, fp, 9223, " tested");- if (ridge->nonconvex)- qh_fprintf(qh, fp, 9224, " nonconvex");- qh_fprintf(qh, fp, 9225, "\n");- qh_printvertices(qh, fp, " vertices:", ridge->vertices);- if (ridge->top && ridge->bottom)- qh_fprintf(qh, fp, 9226, " between f%d and f%d\n",- ridge->top->id, ridge->bottom->id);-} /* printridge */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printspheres">-</a>-- qh_printspheres(qh, fp, vertices, radius )- prints 3-d vertices as OFF spheres-- notes:- inflated octahedron from Stuart Levy earth/mksphere2-*/-void qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius) {- vertexT *vertex, **vertexp;-- qh->printoutnum++;- qh_fprintf(qh, fp, 9227, "{appearance {-edge -normal normscale 0} {\n\-INST geom {define vsphere OFF\n\-18 32 48\n\-\n\-0 0 1\n\-1 0 0\n\-0 1 0\n\--1 0 0\n\-0 -1 0\n\-0 0 -1\n\-0.707107 0 0.707107\n\-0 -0.707107 0.707107\n\-0.707107 -0.707107 0\n\--0.707107 0 0.707107\n\--0.707107 -0.707107 0\n\-0 0.707107 0.707107\n\--0.707107 0.707107 0\n\-0.707107 0.707107 0\n\-0.707107 0 -0.707107\n\-0 0.707107 -0.707107\n\--0.707107 0 -0.707107\n\-0 -0.707107 -0.707107\n\-\n\-3 0 6 11\n\-3 0 7 6 \n\-3 0 9 7 \n\-3 0 11 9\n\-3 1 6 8 \n\-3 1 8 14\n\-3 1 13 6\n\-3 1 14 13\n\-3 2 11 13\n\-3 2 12 11\n\-3 2 13 15\n\-3 2 15 12\n\-3 3 9 12\n\-3 3 10 9\n\-3 3 12 16\n\-3 3 16 10\n\-3 4 7 10\n\-3 4 8 7\n\-3 4 10 17\n\-3 4 17 8\n\-3 5 14 17\n\-3 5 15 14\n\-3 5 16 15\n\-3 5 17 16\n\-3 6 13 11\n\-3 7 8 6\n\-3 9 10 7\n\-3 11 12 9\n\-3 14 8 17\n\-3 15 13 14\n\-3 16 12 15\n\-3 17 10 16\n} transforms { TLIST\n");- FOREACHvertex_(vertices) {- qh_fprintf(qh, fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",- radius, vertex->id, radius, radius);- qh_printpoint3(qh, fp, vertex->point);- qh_fprintf(qh, fp, 9229, "1\n");- }- qh_fprintf(qh, fp, 9230, "}}}\n");-} /* printspheres */---/*------------------------------------------------printsummary-- see libqhull_r.c-*/--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvdiagram">-</a>-- qh_printvdiagram(qh, fp, format, facetlist, facets, printall )- print voronoi diagram- # of pairs of input sites- #indices site1 site2 vertex1 ...-- sites indexed by input point id- point 0 is the first input point- vertices indexed by 'o' and 'p' order- vertex 0 is the 'vertex-at-infinity'- vertex 1 is the first Voronoi vertex-- see:- qh_printvoronoi()- qh_eachvoronoi_all()-- notes:- if all facets are upperdelaunay,- prints upper hull (furthest-site Voronoi diagram)-*/-void qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {- setT *vertices;- int totcount, numcenters;- boolT isLower;- qh_RIDGE innerouter= qh_RIDGEall;- printvridgeT printvridge= NULL;-- if (format == qh_PRINTvertices) {- innerouter= qh_RIDGEall;- printvridge= qh_printvridge;- }else if (format == qh_PRINTinner) {- innerouter= qh_RIDGEinner;- printvridge= qh_printvnorm;- }else if (format == qh_PRINTouter) {- innerouter= qh_RIDGEouter;- printvridge= qh_printvnorm;- }else {- qh_fprintf(qh, qh->ferr, 6219, "Qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);- totcount= qh_printvdiagram2(qh, NULL, NULL, vertices, innerouter, False);- qh_fprintf(qh, fp, 9231, "%d\n", totcount);- totcount= qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, True /* inorder*/);- qh_settempfree(qh, &vertices);-#if 0 /* for testing qh_eachvoronoi_all */- qh_fprintf(qh, fp, 9232, "\n");- totcount= qh_eachvoronoi_all(qh, fp, printvridge, qh->UPPERdelaunay, innerouter, True /* inorder*/);- qh_fprintf(qh, fp, 9233, "%d\n", totcount);-#endif-} /* printvdiagram */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvdiagram2">-</a>-- qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, inorder )- visit all pairs of input sites (vertices) for selected Voronoi vertices- vertices may include NULLs-- innerouter:- qh_RIDGEall print inner ridges(bounded) and outer ridges(unbounded)- qh_RIDGEinner print only inner ridges- qh_RIDGEouter print only outer ridges-- inorder:- print 3-d Voronoi vertices in order-- assumes:- qh_markvoronoi marked facet->visitid for Voronoi vertices- all facet->seen= False- all facet->seen2= True-- returns:- total number of Voronoi ridges- if printvridge,- calls printvridge( fp, vertex, vertexA, centers) for each ridge- [see qh_eachvoronoi()]-- see:- qh_eachvoronoi_all()-*/-int qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {- int totcount= 0;- int vertex_i, vertex_n;- vertexT *vertex;-- FORALLvertices- vertex->seen= False;- FOREACHvertex_i_(qh, vertices) {- if (vertex) {- if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)- continue;- totcount += qh_eachvoronoi(qh, fp, printvridge, vertex, !qh_ALL, innerouter, inorder);- }- }- return totcount;-} /* printvdiagram2 */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvertex">-</a>-- qh_printvertex(qh, fp, vertex )- prints the information in a vertex- Duplicated as operator<< [QhullVertex.cpp]-*/-void qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex) {- pointT *point;- int k, count= 0;- facetT *neighbor, **neighborp;- realT r; /*bug fix*/-- if (!vertex) {- qh_fprintf(qh, fp, 9234, " NULLvertex\n");- return;- }- qh_fprintf(qh, fp, 9235, "- p%d(v%d):", qh_pointid(qh, vertex->point), vertex->id);- point= vertex->point;- if (point) {- for (k=qh->hull_dim; k--; ) {- r= *point++;- qh_fprintf(qh, fp, 9236, " %5.2g", r);- }- }- if (vertex->deleted)- qh_fprintf(qh, fp, 9237, " deleted");- if (vertex->delridge)- qh_fprintf(qh, fp, 9238, " ridgedeleted");- qh_fprintf(qh, fp, 9239, "\n");- if (vertex->neighbors) {- qh_fprintf(qh, fp, 9240, " neighbors:");- FOREACHneighbor_(vertex) {- if (++count % 100 == 0)- qh_fprintf(qh, fp, 9241, "\n ");- qh_fprintf(qh, fp, 9242, " f%d", neighbor->id);- }- qh_fprintf(qh, fp, 9243, "\n");- }-} /* printvertex */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvertexlist">-</a>-- qh_printvertexlist(qh, fp, string, facetlist, facets, printall )- prints vertices used by a facetlist or facet set- tests qh_skipfacet() if !printall-*/-void qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,- setT *facets, boolT printall) {- vertexT *vertex, **vertexp;- setT *vertices;-- vertices= qh_facetvertices(qh, facetlist, facets, printall);- qh_fprintf(qh, fp, 9244, "%s", string);- FOREACHvertex_(vertices)- qh_printvertex(qh, fp, vertex);- qh_settempfree(qh, &vertices);-} /* printvertexlist */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvertices">-</a>-- qh_printvertices(qh, fp, string, vertices )- prints vertices in a set- duplicated as printVertexSet [QhullVertex.cpp]-*/-void qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices) {- vertexT *vertex, **vertexp;-- qh_fprintf(qh, fp, 9245, "%s", string);- FOREACHvertex_(vertices)- qh_fprintf(qh, fp, 9246, " p%d(v%d)", qh_pointid(qh, vertex->point), vertex->id);- qh_fprintf(qh, fp, 9247, "\n");-} /* printvertices */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvneighbors">-</a>-- qh_printvneighbors(qh, fp, facetlist, facets, printall )- print vertex neighbors of vertices in facetlist and facets ('FN')-- notes:- qh_countfacets clears facet->visitid for non-printed facets-- design:- collect facet count and related statistics- if necessary, build neighbor sets for each vertex- collect vertices in facetlist and facets- build a point array for point->vertex and point->coplanar facet- for each point- list vertex neighbors or coplanar facet-*/-void qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall) {- int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;- setT *vertices, *vertex_points, *coplanar_points;- int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);- vertexT *vertex, **vertexp;- int vertex_i, vertex_n;- facetT *facet, **facetp, *neighbor, **neighborp;- pointT *point, **pointp;-- qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,- &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */- qh_fprintf(qh, fp, 9248, "%d\n", numpoints);- qh_vertexneighbors(qh);- vertices= qh_facetvertices(qh, facetlist, facets, printall);- vertex_points= qh_settemp(qh, numpoints);- coplanar_points= qh_settemp(qh, numpoints);- qh_setzero(qh, vertex_points, 0, numpoints);- qh_setzero(qh, coplanar_points, 0, numpoints);- FOREACHvertex_(vertices)- qh_point_add(qh, vertex_points, vertex->point, vertex);- FORALLfacet_(facetlist) {- FOREACHpoint_(facet->coplanarset)- qh_point_add(qh, coplanar_points, point, facet);- }- FOREACHfacet_(facets) {- FOREACHpoint_(facet->coplanarset)- qh_point_add(qh, coplanar_points, point, facet);- }- FOREACHvertex_i_(qh, vertex_points) {- if (vertex) {- numneighbors= qh_setsize(qh, vertex->neighbors);- qh_fprintf(qh, fp, 9249, "%d", numneighbors);- if (qh->hull_dim == 3)- qh_order_vertexneighbors(qh, vertex);- else if (qh->hull_dim >= 4)- qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,- sizeof(facetT *), qh_compare_facetvisit);- FOREACHneighbor_(vertex)- qh_fprintf(qh, fp, 9250, " %d",- neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);- qh_fprintf(qh, fp, 9251, "\n");- }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))- qh_fprintf(qh, fp, 9252, "1 %d\n",- facet->visitid ? facet->visitid - 1 : 0 - facet->id);- else- qh_fprintf(qh, fp, 9253, "0\n");- }- qh_settempfree(qh, &coplanar_points);- qh_settempfree(qh, &vertex_points);- qh_settempfree(qh, &vertices);-} /* printvneighbors */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvoronoi">-</a>-- qh_printvoronoi(qh, fp, format, facetlist, facets, printall )- print voronoi diagram in 'o' or 'G' format- for 'o' format- prints voronoi centers for each facet and for infinity- for each vertex, lists ids of printed facets or infinity- assumes facetlist and facets are disjoint- for 'G' format- prints an OFF object- adds a 0 coordinate to center- prints infinity but does not list in vertices-- see:- qh_printvdiagram()-- notes:- if 'o',- prints a line for each point except "at-infinity"- if all facets are upperdelaunay,- reverses lower and upper hull-*/-void qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {- int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;- facetT *facet, **facetp, *neighbor, **neighborp;- setT *vertices;- vertexT *vertex;- boolT isLower;- unsigned int numfacets= (unsigned int) qh->num_facets;-- vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);- FOREACHvertex_i_(qh, vertices) {- if (vertex) {- numvertices++;- numneighbors = numinf = 0;- FOREACHneighbor_(vertex) {- if (neighbor->visitid == 0)- numinf= 1;- else if (neighbor->visitid < numfacets)- numneighbors++;- }- if (numinf && !numneighbors) {- SETelem_(vertices, vertex_i)= NULL;- numvertices--;- }- }- }- if (format == qh_PRINTgeom)- qh_fprintf(qh, fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",- numcenters, numvertices);- else- qh_fprintf(qh, fp, 9255, "%d\n%d %d 1\n", qh->hull_dim-1, numcenters, qh_setsize(qh, vertices));- if (format == qh_PRINTgeom) {- for (k=qh->hull_dim-1; k--; )- qh_fprintf(qh, fp, 9256, qh_REAL_1, 0.0);- qh_fprintf(qh, fp, 9257, " 0 # infinity not used\n");- }else {- for (k=qh->hull_dim-1; k--; )- qh_fprintf(qh, fp, 9258, qh_REAL_1, qh_INFINITE);- qh_fprintf(qh, fp, 9259, "\n");- }- FORALLfacet_(facetlist) {- if (facet->visitid && facet->visitid < numfacets) {- if (format == qh_PRINTgeom)- qh_fprintf(qh, fp, 9260, "# %d f%d\n", vid++, facet->id);- qh_printcenter(qh, fp, format, NULL, facet);- }- }- FOREACHfacet_(facets) {- if (facet->visitid && facet->visitid < numfacets) {- if (format == qh_PRINTgeom)- qh_fprintf(qh, fp, 9261, "# %d f%d\n", vid++, facet->id);- qh_printcenter(qh, fp, format, NULL, facet);- }- }- FOREACHvertex_i_(qh, vertices) {- numneighbors= 0;- numinf=0;- if (vertex) {- if (qh->hull_dim == 3)- qh_order_vertexneighbors(qh, vertex);- else if (qh->hull_dim >= 4)- qsort(SETaddr_(vertex->neighbors, facetT),- (size_t)qh_setsize(qh, vertex->neighbors),- sizeof(facetT *), qh_compare_facetvisit);- FOREACHneighbor_(vertex) {- if (neighbor->visitid == 0)- numinf= 1;- else if (neighbor->visitid < numfacets)- numneighbors++;- }- }- if (format == qh_PRINTgeom) {- if (vertex) {- qh_fprintf(qh, fp, 9262, "%d", numneighbors);- FOREACHneighbor_(vertex) {- if (neighbor->visitid && neighbor->visitid < numfacets)- qh_fprintf(qh, fp, 9263, " %d", neighbor->visitid);- }- qh_fprintf(qh, fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);- }else- qh_fprintf(qh, fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);- }else {- if (numinf)- numneighbors++;- qh_fprintf(qh, fp, 9266, "%d", numneighbors);- if (vertex) {- FOREACHneighbor_(vertex) {- if (neighbor->visitid == 0) {- if (numinf) {- numinf= 0;- qh_fprintf(qh, fp, 9267, " %d", neighbor->visitid);- }- }else if (neighbor->visitid < numfacets)- qh_fprintf(qh, fp, 9268, " %d", neighbor->visitid);- }- }- qh_fprintf(qh, fp, 9269, "\n");- }- }- if (format == qh_PRINTgeom)- qh_fprintf(qh, fp, 9270, "}\n");- qh_settempfree(qh, &vertices);-} /* printvoronoi */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvnorm">-</a>-- qh_printvnorm(qh, fp, vertex, vertexA, centers, unbounded )- print one separating plane of the Voronoi diagram for a pair of input sites- unbounded==True if centers includes vertex-at-infinity-- assumes:- qh_ASvoronoi and qh_vertexneighbors() already set-- note:- parameter unbounded is UNUSED by this callback-- see:- qh_printvdiagram()- qh_eachvoronoi()-*/-void qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {- pointT *normal;- realT offset;- int k;- QHULL_UNUSED(unbounded);-- normal= qh_detvnorm(qh, vertex, vertexA, centers, &offset);- qh_fprintf(qh, fp, 9271, "%d %d %d ",- 2+qh->hull_dim, qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));- for (k=0; k< qh->hull_dim-1; k++)- qh_fprintf(qh, fp, 9272, qh_REAL_1, normal[k]);- qh_fprintf(qh, fp, 9273, qh_REAL_1, offset);- qh_fprintf(qh, fp, 9274, "\n");-} /* printvnorm */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printvridge">-</a>-- qh_printvridge(qh, fp, vertex, vertexA, centers, unbounded )- print one ridge of the Voronoi diagram for a pair of input sites- unbounded==True if centers includes vertex-at-infinity-- see:- qh_printvdiagram()-- notes:- the user may use a different function- parameter unbounded is UNUSED-*/-void qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {- facetT *facet, **facetp;- QHULL_UNUSED(unbounded);-- qh_fprintf(qh, fp, 9275, "%d %d %d", qh_setsize(qh, centers)+2,- qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));- FOREACHfacet_(centers)- qh_fprintf(qh, fp, 9276, " %d", facet->visitid);- qh_fprintf(qh, fp, 9277, "\n");-} /* printvridge */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="projectdim3">-</a>-- qh_projectdim3(qh, source, destination )- project 2-d 3-d or 4-d point to a 3-d point- uses qh.DROPdim and qh.hull_dim- source and destination may be the same-- notes:- allocate 4 elements to destination just in case-*/-void qh_projectdim3(qhT *qh, pointT *source, pointT *destination) {- int i,k;-- for (k=0, i=0; k < qh->hull_dim; k++) {- if (qh->hull_dim == 4) {- if (k != qh->DROPdim)- destination[i++]= source[k];- }else if (k == qh->DROPdim)- destination[i++]= 0;- else- destination[i++]= source[k];- }- while (i < 3)- destination[i++]= 0.0;-} /* projectdim3 */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="readfeasible">-</a>-- qh_readfeasible(qh, dim, curline )- read feasible point from current line and qh.fin-- returns:- number of lines read from qh.fin- sets qh.feasible_point with malloc'd coordinates-- notes:- checks for qh.HALFspace- assumes dim > 1-- see:- qh_setfeasible-*/-int qh_readfeasible(qhT *qh, int dim, const char *curline) {- boolT isfirst= True;- int linecount= 0, tokcount= 0;- const char *s;- char *t, firstline[qh_MAXfirst+1];- coordT *coords, value;-- if (!qh->HALFspace) {- qh_fprintf(qh, qh->ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->feasible_string)- qh_fprintf(qh, qh->ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");- if (!(qh->feasible_point= (coordT*)qh_malloc(dim* sizeof(coordT)))) {- qh_fprintf(qh, qh->ferr, 6071, "qhull error: insufficient memory for feasible point\n");- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- coords= qh->feasible_point;- while ((s= (isfirst ? curline : fgets(firstline, qh_MAXfirst, qh->fin)))) {- if (isfirst)- isfirst= False;- else- linecount++;- while (*s) {- while (isspace(*s))- s++;- value= qh_strtod(s, &t);- if (s == t)- break;- s= t;- *(coords++)= value;- if (++tokcount == dim) {- while (isspace(*s))- s++;- qh_strtod(s, &t);- if (s != t) {- qh_fprintf(qh, qh->ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",- s);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- return linecount;- }- }- }- qh_fprintf(qh, qh->ferr, 6073, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",- tokcount, dim);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- return 0;-} /* readfeasible */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="readpoints">-</a>-- qh_readpoints(qh, numpoints, dimension, ismalloc )- read points from qh.fin into qh.first_point, qh.num_points- qh.fin is lines of coordinates, one per vertex, first line number of points- if 'rbox D4',- gives message- if qh.ATinfinity,- adds point-at-infinity for Delaunay triangulations-- returns:- number of points, array of point coordinates, dimension, ismalloc True- if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid- and clears qh.PROJECTdelaunay- if qh.HALFspace, reads optional feasible point, reads halfspaces,- converts to dual.-- for feasible point in "cdd format" in 3-d:- 3 1- coordinates- comments- begin- n 4 real/integer- ...- end-- notes:- dimension will change in qh_initqhull_globals if qh.PROJECTinput- uses malloc() since qh_mem not initialized- FIXUP QH11012: qh_readpoints needs rewriting, too long-*/-coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc) {- coordT *points, *coords, *infinity= NULL;- realT paraboloid, maxboloid= -REALmax, value;- realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;- char *s= 0, *t, firstline[qh_MAXfirst+1];- int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;- int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;- int tokcount= 0, linecount=0, maxcount, coordcount=0;- boolT islong, isfirst= True, wasbegin= False;- boolT isdelaunay= qh->DELAUNAY && !qh->PROJECTinput;-- if (qh->CDDinput) {- while ((s= fgets(firstline, qh_MAXfirst, qh->fin))) {- linecount++;- if (qh->HALFspace && linecount == 1 && isdigit(*s)) {- dimfeasible= qh_strtol(s, &s);- while (isspace(*s))- s++;- if (qh_strtol(s, &s) == 1)- linecount += qh_readfeasible(qh, dimfeasible, s);- else- dimfeasible= 0;- }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))- break;- else if (!*qh->rbox_command)- strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);- }- if (!s) {- qh_fprintf(qh, qh->ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- }- while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh->fin))) {- linecount++;- if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))- wasbegin= True;- while (*s) {- while (isspace(*s))- s++;- if (!*s)- break;- if (!isdigit(*s)) {- if (!*qh->rbox_command) {- strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);- firsttext= linecount;- }- break;- }- if (!diminput)- diminput= qh_strtol(s, &s);- else {- numinput= qh_strtol(s, &s);- if (numinput == 1 && diminput >= 2 && qh->HALFspace && !qh->CDDinput) {- linecount += qh_readfeasible(qh, diminput, s); /* checks if ok */- dimfeasible= diminput;- diminput= numinput= 0;- }else- break;- }- }- }- if (!s) {- qh_fprintf(qh, qh->ferr, 6075, "qhull input error: short input file. Did not find dimension and number of points\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (diminput > numinput) {- tempi= diminput; /* exchange dim and n, e.g., for cdd input format */- diminput= numinput;- numinput= tempi;- }- if (diminput < 2) {- qh_fprintf(qh, qh->ferr, 6220,"qhull input error: dimension %d(first number) should be at least 2\n",- diminput);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (isdelaunay) {- qh->PROJECTdelaunay= False;- if (qh->CDDinput)- *dimension= diminput;- else- *dimension= diminput+1;- *numpoints= numinput;- if (qh->ATinfinity)- (*numpoints)++;- }else if (qh->HALFspace) {- *dimension= diminput - 1;- *numpoints= numinput;- if (diminput < 3) {- qh_fprintf(qh, qh->ferr, 6221,"qhull input error: dimension %d(first number, includes offset) should be at least 3 for halfspaces\n",- diminput);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (dimfeasible) {- if (dimfeasible != *dimension) {- qh_fprintf(qh, qh->ferr, 6222,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",- dimfeasible, diminput);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- }else- qh_setfeasible(qh, *dimension);- }else {- if (qh->CDDinput)- *dimension= diminput-1;- else- *dimension= diminput;- *numpoints= numinput;- }- qh->normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */- if (qh->HALFspace) {- qh->half_space= coordp= (coordT*)qh_malloc(qh->normal_size + sizeof(coordT));- if (qh->CDDinput) {- offsetp= qh->half_space;- normalp= offsetp + 1;- }else {- normalp= qh->half_space;- offsetp= normalp + *dimension;- }- }- qh->maxline= diminput * (qh_REALdigits + 5);- maximize_(qh->maxline, 500);- qh->line= (char*)qh_malloc((qh->maxline+1) * sizeof(char));- *ismalloc= True; /* use malloc since memory not setup */- coords= points= qh->temp_malloc= /* numinput and diminput >=2 by QH6220 */- (coordT*)qh_malloc((*numpoints)*(*dimension)*sizeof(coordT));- if (!coords || !qh->line || (qh->HALFspace && !qh->half_space)) {- qh_fprintf(qh, qh->ferr, 6076, "qhull error: insufficient memory to read %d points\n",- numinput);- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- if (isdelaunay && qh->ATinfinity) {- infinity= points + numinput * (*dimension);- for (k= (*dimension) - 1; k--; )- infinity[k]= 0.0;- }- maxcount= numinput * diminput;- paraboloid= 0.0;- while ((s= (isfirst ? s : fgets(qh->line, qh->maxline, qh->fin)))) {- if (!isfirst) {- linecount++;- if (*s == 'e' || *s == 'E') {- if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {- if (qh->CDDinput )- break;- else if (wasbegin)- qh_fprintf(qh, qh->ferr, 7058, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");- }- }- }- islong= False;- while (*s) {- while (isspace(*s))- s++;- value= qh_strtod(s, &t);- if (s == t) {- if (!*qh->rbox_command)- strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);- if (*s && !firsttext)- firsttext= linecount;- if (!islong && !firstshort && coordcount)- firstshort= linecount;- break;- }- if (!firstpoint)- firstpoint= linecount;- s= t;- if (++tokcount > maxcount)- continue;- if (qh->HALFspace) {- if (qh->CDDinput)- *(coordp++)= -value; /* both coefficients and offset */- else- *(coordp++)= value;- }else {- *(coords++)= value;- if (qh->CDDinput && !coordcount) {- if (value != 1.0) {- qh_fprintf(qh, qh->ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",- linecount);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- coords--;- }else if (isdelaunay) {- paraboloid += value * value;- if (qh->ATinfinity) {- if (qh->CDDinput)- infinity[coordcount-1] += value;- else- infinity[coordcount] += value;- }- }- }- if (++coordcount == diminput) {- coordcount= 0;- if (isdelaunay) {- *(coords++)= paraboloid;- maximize_(maxboloid, paraboloid);- paraboloid= 0.0;- }else if (qh->HALFspace) {- if (!qh_sethalfspace(qh, *dimension, coords, &coords, normalp, offsetp, qh->feasible_point)) {- qh_fprintf(qh, qh->ferr, 8048, "The halfspace was on line %d\n", linecount);- if (wasbegin)- qh_fprintf(qh, qh->ferr, 8049, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- coordp= qh->half_space;- }- while (isspace(*s))- s++;- if (*s) {- islong= True;- if (!firstlong)- firstlong= linecount;- }- }- }- if (!islong && !firstshort && coordcount)- firstshort= linecount;- if (!isfirst && s - qh->line >= qh->maxline) {- qh_fprintf(qh, qh->ferr, 6078, "qhull input error: line %d contained more than %d characters\n",- linecount, (int) (s - qh->line)); /* WARN64 */- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- isfirst= False;- }- if (tokcount != maxcount) {- newnum= fmin_(numinput, tokcount/diminput);- qh_fprintf(qh, qh->ferr, 7073,"\-qhull warning: instead of %d %d-dimensional points, input contains\n\-%d points and %d extra coordinates. Line %d is the first\npoint",- numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);- if (firsttext)- qh_fprintf(qh, qh->ferr, 8051, ", line %d is the first comment", firsttext);- if (firstshort)- qh_fprintf(qh, qh->ferr, 8052, ", line %d is the first short\nline", firstshort);- if (firstlong)- qh_fprintf(qh, qh->ferr, 8053, ", line %d is the first long line", firstlong);- qh_fprintf(qh, qh->ferr, 8054, ". Continue with %d points.\n", newnum);- numinput= newnum;- if (isdelaunay && qh->ATinfinity) {- for (k= tokcount % diminput; k--; )- infinity[k] -= *(--coords);- *numpoints= newnum+1;- }else {- coords -= tokcount % diminput;- *numpoints= newnum;- }- }- if (isdelaunay && qh->ATinfinity) {- for (k= (*dimension) -1; k--; )- infinity[k] /= numinput;- if (coords == infinity)- coords += (*dimension) -1;- else {- for (k=0; k < (*dimension) -1; k++)- *(coords++)= infinity[k];- }- *(coords++)= maxboloid * 1.1;- }- if (qh->rbox_command[0]) {- qh->rbox_command[strlen(qh->rbox_command)-1]= '\0';- if (!strcmp(qh->rbox_command, "./rbox D4"))- qh_fprintf(qh, qh->ferr, 8055, "\n\-This is the qhull test case. If any errors or core dumps occur,\n\-recompile qhull with 'make new'. If errors still occur, there is\n\-an incompatibility. You should try a different compiler. You can also\n\-change the choices in user.h. If you discover the source of the problem,\n\-please send mail to qhull_bug@qhull.org.\n\-\n\-Type 'qhull' for a short list of options.\n");- }- qh_free(qh->line);- qh->line= NULL;- if (qh->half_space) {- qh_free(qh->half_space);- qh->half_space= NULL;- }- qh->temp_malloc= NULL;- trace1((qh, qh->ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",- numinput, diminput));- return(points);-} /* readpoints */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="setfeasible">-</a>-- qh_setfeasible(qh, dim )- set qh.feasible_point from qh.feasible_string in "n,n,n" or "n n n" format-- notes:- "n,n,n" already checked by qh_initflags()- see qh_readfeasible()- called only once from qh_new_qhull, otherwise leaks memory-*/-void qh_setfeasible(qhT *qh, int dim) {- int tokcount= 0;- char *s;- coordT *coords, value;-- if (!(s= qh->feasible_string)) {- qh_fprintf(qh, qh->ferr, 6223, "\-qhull input error: halfspace intersection needs a feasible point.\n\-Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (!(qh->feasible_point= (pointT*)qh_malloc(dim * sizeof(coordT)))) {- qh_fprintf(qh, qh->ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");- qh_errexit(qh, qh_ERRmem, NULL, NULL);- }- coords= qh->feasible_point;- while (*s) {- value= qh_strtod(s, &s);- if (++tokcount > dim) {- qh_fprintf(qh, qh->ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",- qh->feasible_string, dim);- break;- }- *(coords++)= value;- if (*s)- s++;- }- while (++tokcount <= dim)- *(coords++)= 0.0;-} /* setfeasible */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="skipfacet">-</a>-- qh_skipfacet(qh, facet )- returns 'True' if this facet is not to be printed-- notes:- based on the user provided slice thresholds and 'good' specifications-*/-boolT qh_skipfacet(qhT *qh, facetT *facet) {- facetT *neighbor, **neighborp;-- if (qh->PRINTneighbors) {- if (facet->good)- return !qh->PRINTgood;- FOREACHneighbor_(facet) {- if (neighbor->good)- return False;- }- return True;- }else if (qh->PRINTgood)- return !facet->good;- else if (!facet->normal)- return True;- return(!qh_inthresholds(qh, facet->normal, NULL));-} /* skipfacet */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="skipfilename">-</a>-- qh_skipfilename(qh, string )- returns pointer to character after filename-- notes:- skips leading spaces- ends with spacing or eol- if starts with ' or " ends with the same, skipping \' or \"- For qhull, qh_argv_to_command() only uses double quotes-*/-char *qh_skipfilename(qhT *qh, char *filename) {- char *s= filename; /* non-const due to return */- char c;-- while (*s && isspace(*s))- s++;- c= *s++;- if (c == '\0') {- qh_fprintf(qh, qh->ferr, 6204, "qhull input error: filename expected, none found.\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (c == '\'' || c == '"') {- while (*s !=c || s[-1] == '\\') {- if (!*s) {- qh_fprintf(qh, qh->ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- s++;- }- s++;- }- else while (*s && !isspace(*s))- s++;- return s;-} /* skipfilename */-
− C/libqhull_r.c
@@ -1,1403 +0,0 @@-/*<html><pre> -<a href="qh-qhull_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- libqhull_r.c- Quickhull algorithm for convex hulls-- qhull() and top-level routines-- see qh-qhull_r.htm, libqhull.h, unix_r.c-- see qhull_ra.h for internal functions-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/libqhull_r.c#2 $$Change: 2047 $- $DateTime: 2016/01/04 22:03:18 $$Author: bbarber $-*/--#include "qhull_ra.h"--/*============= functions in alphabetic order after qhull() =======*/--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="qhull">-</a>-- qh_qhull(qh)- compute DIM3 convex hull of qh.num_points starting at qh.first_point- qh->contains all global options and variables-- returns:- returns polyhedron- qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,-- returns global variables- qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex-- returns precision constants- qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge-- notes:- unless needed for output- qh.max_vertex and qh.min_vertex are max/min due to merges-- see:- to add individual points to either qh.num_points- use qh_addpoint()-- if qh.GETarea- qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()-- design:- record starting time- initialize hull and partition points- build convex hull- unless early termination- update facet->maxoutside for vertices, coplanar, and near-inside points- error if temporary sets exist- record end time-*/--void qh_qhull(qhT *qh) {- int numoutside;-- qh->hulltime= qh_CPUclock;- if (qh->RERUN || qh->JOGGLEmax < REALmax/2)- qh_build_withrestart(qh);- else {- qh_initbuild(qh);- qh_buildhull(qh);- }- if (!qh->STOPpoint && !qh->STOPcone) {- if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)- qh_checkzero(qh, qh_ALL);- if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {- trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points. Post-merging and check of maxout not needed.\n"));- qh->DOcheckmax= False;- }else {- if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))- qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,- (qh->POSTmerge ? False : qh->TESTvneighbors));- else if (!qh->POSTmerge && qh->TESTvneighbors)- qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,- qh->premerge_cos, True);- if (qh->POSTmerge)- qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,- qh->postmerge_cos, qh->TESTvneighbors);- if (qh->visible_list == qh->facet_list) { /* i.e., merging done */- qh->findbestnew= True;- qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numoutside);- qh->findbestnew= False;- qh_deletevisible(qh /*qh.visible_list*/);- qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);- }- }- if (qh->DOcheckmax){- if (qh->REPORTfreq) {- qh_buildtracing(qh, NULL, NULL);- qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");- }- qh_check_maxout(qh);- }- if (qh->KEEPnearinside && !qh->maxoutdone)- qh_nearcoplanar(qh);- }- if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {- qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d)\n",- qh_setsize(qh, qh->qhmem.tempstack));- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- qh->hulltime= qh_CPUclock - qh->hulltime;- qh->QHULLfinished= True;- trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));-} /* qhull */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="addpoint">-</a>-- qh_addpoint(qh, furthest, facet, checkdist )- add point (usually furthest point) above facet to hull- if checkdist,- check that point is above facet.- if point is not outside of the hull, uses qh_partitioncoplanar()- assumes that facet is defined by qh_findbestfacet()- else if facet specified,- assumes that point is above facet (major damage if below)- for Delaunay triangulations,- Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed- Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.-- returns:- returns False if user requested an early termination- qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined- updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices- clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)- if unknown point, adds a pointer to qh.other_points- do not deallocate the point's coordinates-- notes:- assumes point is near its best facet and not at a local minimum of a lens- distributions. Use qh_findbestfacet to avoid this case.- uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets-- see also:- qh_triangulate() -- triangulate non-simplicial facets-- design:- add point to other_points if needed- if checkdist- if point not above facet- partition coplanar point- exit- exit if pre STOPpoint requested- find horizon and visible facets for point- make new facets for point to horizon- make hyperplanes for point- compute balance statistics- match neighboring new facets- update vertex neighbors and delete interior vertices- exit if STOPcone requested- merge non-convex new facets- if merge found, many merges, or 'Qf'- use qh_findbestnew() instead of qh_findbest()- partition outside points from visible facets- delete visible facets- check polyhedron if requested- exit if post STOPpoint requested- reset working lists of facets and vertices-*/-boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {- int goodvisible, goodhorizon;- vertexT *vertex;- facetT *newfacet;- realT dist, newbalance, pbalance;- boolT isoutside= False;- int numpart, numpoints, numnew, firstnew;-- qh->maxoutdone= False;- if (qh_pointid(qh, furthest) == qh_IDunknown)- qh_setappend(qh, &qh->other_points, furthest);- if (!facet) {- qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet. Need to call qh_findbestfacet first\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- if (checkdist) {- facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,- &dist, &isoutside, &numpart);- zzadd_(Zpartition, numpart);- if (!isoutside) {- zinc_(Znotmax); /* last point of outsideset is no longer furthest. */- facet->notfurthest= True;- qh_partitioncoplanar(qh, furthest, facet, &dist);- return True;- }- }- qh_buildtracing(qh, furthest, facet);- if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {- facet->notfurthest= True;- return False;- }- qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);- if (qh->ONLYgood && !(goodvisible+goodhorizon) && !qh->GOODclosest) {- zinc_(Znotgood);- facet->notfurthest= True;- /* last point of outsideset is no longer furthest. This is ok- since all points of the outside are likely to be bad */- qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);- return True;- }- zzinc_(Zprocessed);- firstnew= qh->facet_id;- vertex= qh_makenewfacets(qh, furthest /*visible_list, attaches if !ONLYgood */);- qh_makenewplanes(qh /* newfacet_list */);- numnew= qh->facet_id - firstnew;- newbalance= numnew - (realT) (qh->num_facets-qh->num_visible)- * qh->hull_dim/qh->num_vertices;- wadd_(Wnewbalance, newbalance);- wadd_(Wnewbalance2, newbalance * newbalance);- if (qh->ONLYgood- && !qh_findgood(qh, qh->newfacet_list, goodhorizon) && !qh->GOODclosest) {- FORALLnew_facets- qh_delfacet(qh, newfacet);- qh_delvertex(qh, vertex);- qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);- zinc_(Znotgoodnew);- facet->notfurthest= True;- return True;- }- if (qh->ONLYgood)- qh_attachnewfacets(qh /*visible_list*/);- qh_matchnewfacets(qh);- qh_updatevertices(qh);- if (qh->STOPcone && qh->furthest_id == qh->STOPcone-1) {- facet->notfurthest= True;- return False; /* visible_list etc. still defined */- }- qh->findbestnew= False;- if (qh->PREmerge || qh->MERGEexact) {- qh_premerge(qh, vertex, qh->premerge_centrum, qh->premerge_cos);- if (qh_USEfindbestnew)- qh->findbestnew= True;- else {- FORALLnew_facets {- if (!newfacet->simplicial) {- qh->findbestnew= True; /* use qh_findbestnew instead of qh_findbest*/- break;- }- }- }- }else if (qh->BESToutside)- qh->findbestnew= True;- qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numpoints);- qh->findbestnew= False;- qh->findbest_notsharp= False;- zinc_(Zpbalance);- pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */- * (qh->num_points - qh->num_vertices)/qh->num_vertices;- wadd_(Wpbalance, pbalance);- wadd_(Wpbalance2, pbalance * pbalance);- qh_deletevisible(qh /*qh.visible_list*/);- zmax_(Zmaxvertex, qh->num_vertices);- qh->NEWfacets= False;- if (qh->IStracing >= 4) {- if (qh->num_facets < 2000)- qh_printlists(qh);- qh_printfacetlist(qh, qh->newfacet_list, NULL, True);- qh_checkpolygon(qh, qh->facet_list);- }else if (qh->CHECKfrequently) {- if (qh->num_facets < 50)- qh_checkpolygon(qh, qh->facet_list);- else- qh_checkpolygon(qh, qh->newfacet_list);- }- if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)- return False;- qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);- /* qh_triangulate(qh); to test qh.TRInormals */- trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",- qh_pointid(qh, furthest), numnew, newbalance, pbalance));- return True;-} /* addpoint */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="build_withrestart">-</a>-- qh_build_withrestart(qh)- allow restarts due to qh.JOGGLEmax while calling qh_buildhull()- qh_errexit always undoes qh_build_withrestart()- qh.FIRSTpoint/qh.NUMpoints is point array- it may be moved by qh_joggleinput(qh)-*/-void qh_build_withrestart(qhT *qh) {- int restart;-- qh->ALLOWrestart= True;- while (True) {- restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */- if (restart) { /* only from qh_precision() */- zzinc_(Zretry);- wmax_(Wretrymax, qh->JOGGLEmax);- /* QH7078 warns about using 'TCn' with 'QJn' */- qh->STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */- }- if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {- if (qh->build_cnt > qh_JOGGLEmaxretry) {- qh_fprintf(qh, qh->ferr, 6229, "qhull precision error: %d attempts to construct a convex hull\n\- with joggled input. Increase joggle above 'QJ%2.2g'\n\- or modify qh_JOGGLE... parameters in user.h\n",- qh->build_cnt, qh->JOGGLEmax);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- if (qh->build_cnt && !restart)- break;- }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)- break;- qh->STOPcone= 0;- qh_freebuild(qh, True); /* first call is a nop */- qh->build_cnt++;- if (!qh->qhull_optionsiz)- qh->qhull_optionsiz= (int)strlen(qh->qhull_options); /* WARN64 */- else {- qh->qhull_options [qh->qhull_optionsiz]= '\0';- qh->qhull_optionlen= qh_OPTIONline; /* starts a new line */- }- qh_option(qh, "_run", &qh->build_cnt, NULL);- if (qh->build_cnt == qh->RERUN) {- qh->IStracing= qh->TRACElastrun; /* duplicated from qh_initqhull_globals */- if (qh->TRACEpoint != qh_IDunknown || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {- qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);- qh->IStracing= 0;- }- qh->qhmem.IStracing= qh->IStracing;- }- if (qh->JOGGLEmax < REALmax/2)- qh_joggleinput(qh);- qh_initbuild(qh);- qh_buildhull(qh);- if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)- qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);- }- qh->ALLOWrestart= False;-} /* qh_build_withrestart */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="buildhull">-</a>-- qh_buildhull(qh)- construct a convex hull by adding outside points one at a time-- returns:-- notes:- may be called multiple times- checks facet and vertex lists for incorrect flags- to recover from STOPcone, call qh_deletevisible and qh_resetlists-- design:- check visible facet and newfacet flags- check newlist vertex flags and qh.STOPcone/STOPpoint- for each facet with a furthest outside point- add point to facet- exit if qh.STOPcone or qh.STOPpoint requested- if qh.NARROWhull for initial simplex- partition remaining outside points to coplanar sets-*/-void qh_buildhull(qhT *qh) {- facetT *facet;- pointT *furthest;- vertexT *vertex;- int id;-- trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));- FORALLfacets {- if (facet->visible || facet->newfacet) {- qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",- facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- }- FORALLvertices {- if (vertex->newlist) {- qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",- vertex->id);- qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- id= qh_pointid(qh, vertex->point);- if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||- (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||- (qh->STOPcone>0 && id == qh->STOPcone-1)) {- trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));- return;- }- }- qh->facet_next= qh->facet_list; /* advance facet when processed */- while ((furthest= qh_nextfurthest(qh, &facet))) {- qh->num_outside--; /* if ONLYmax, furthest may not be outside */- if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))- break;- }- if (qh->NARROWhull) /* move points from outsideset to coplanarset */- qh_outcoplanar(qh /* facet_list */ );- if (qh->num_outside && !furthest) {- qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));-} /* buildhull */---/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="buildtracing">-</a>-- qh_buildtracing(qh, furthest, facet )- trace an iteration of qh_buildhull() for furthest point and facet- if !furthest, prints progress message-- returns:- tracks progress with qh.lastreport- updates qh.furthest_id (-3 if furthest is NULL)- also resets visit_id, vertext_visit on wrap around-- see:- qh_tracemerging()-- design:- if !furthest- print progress message- exit- if 'TFn' iteration- print progress message- else if tracing- trace furthest point and facet- reset qh.visit_id and qh.vertex_visit if overflow may occur- set qh.furthest_id for tracing-*/-void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {- realT dist= 0;- float cpu;- int total, furthestid;- time_t timedata;- struct tm *tp;- vertexT *vertex;-- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- if (!furthest) {- time(&timedata);- tp= localtime(&timedata);- cpu= (float)qh_CPUclock - (float)qh->hulltime;- cpu /= (float)qh_SECticks;- total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);- qh_fprintf(qh, qh->ferr, 8118, "\n\-At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\- The current hull contains %d facets and %d vertices. Last point was p%d\n",- tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,- total, qh->num_facets, qh->num_vertices, qh->furthest_id);- return;- }- furthestid= qh_pointid(qh, furthest);- if (qh->TRACEpoint == furthestid) {- qh->IStracing= qh->TRACElevel;- qh->qhmem.IStracing= qh->TRACElevel;- }else if (qh->TRACEpoint != qh_IDunknown && qh->TRACEdist < REALmax/2) {- qh->IStracing= 0;- qh->qhmem.IStracing= 0;- }- if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport+qh->REPORTfreq)) {- qh->lastreport= qh->facet_id-1;- time(&timedata);- tp= localtime(&timedata);- cpu= (float)qh_CPUclock - (float)qh->hulltime;- cpu /= (float)qh_SECticks;- total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);- zinc_(Zdistio);- qh_distplane(qh, furthest, facet, &dist);- qh_fprintf(qh, qh->ferr, 8119, "\n\-At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\- The current hull contains %d facets and %d vertices. There are %d\n\- outside points. Next is point p%d(v%d), %2.2g above f%d.\n",- tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,- total, qh->num_facets, qh->num_vertices, qh->num_outside+1,- furthestid, qh->vertex_id, dist, getid_(facet));- }else if (qh->IStracing >=1) {- cpu= (float)qh_CPUclock - (float)qh->hulltime;- cpu /= (float)qh_SECticks;- qh_distplane(qh, furthest, facet, &dist);- qh_fprintf(qh, qh->ferr, 8120, "qh_addpoint: add p%d(v%d) to hull of %d facets(%2.2g above f%d) and %d outside at %4.4g CPU secs. Previous was p%d.\n",- furthestid, qh->vertex_id, qh->num_facets, dist,- getid_(facet), qh->num_outside+1, cpu, qh->furthest_id);- }- zmax_(Zvisit2max, (int)qh->visit_id/2);- if (qh->visit_id > (unsigned) INT_MAX) { /* 31 bits */- zinc_(Zvisit);- qh->visit_id= 0;- FORALLfacets- facet->visitid= 0;- }- zmax_(Zvvisit2max, (int)qh->vertex_visit/2);- if (qh->vertex_visit > (unsigned) INT_MAX) { /* 31 bits */ - zinc_(Zvvisit);- qh->vertex_visit= 0;- FORALLvertices- vertex->visitid= 0;- }- qh->furthest_id= furthestid;- qh->RANDOMdist= qh->old_randomdist;-} /* buildtracing */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="errexit2">-</a>-- qh_errexit2(qh, exitcode, facet, otherfacet )- return exitcode to system after an error- report two facets-- returns:- assumes exitcode non-zero-- see:- normally use qh_errexit() in user.c(reports a facet and a ridge)-*/-void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {-- qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);- qh_errexit(qh, exitcode, NULL, NULL);-} /* errexit2 */---/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="findhorizon">-</a>-- qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )- given a visible facet, find the point's horizon and visible facets- for all facets, !facet-visible-- returns:- returns qh.visible_list/num_visible with all visible facets- marks visible facets with ->visible- updates count of good visible and good horizon facets- updates qh.max_outside, qh.max_vertex, facet->maxoutside-- see:- similar to qh_delpoint()-- design:- move facet to qh.visible_list at end of qh.facet_list- for all visible facets- for each unvisited neighbor of a visible facet- compute distance of point to neighbor- if point above neighbor- move neighbor to end of qh.visible_list- else if point is coplanar with neighbor- update qh.max_outside, qh.max_vertex, neighbor->maxoutside- mark neighbor coplanar (will create a samecycle later)- update horizon statistics-*/-void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {- facetT *neighbor, **neighborp, *visible;- int numhorizon= 0, coplanar= 0;- realT dist;-- trace1((qh, qh->ferr, 1040,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));- *goodvisible= *goodhorizon= 0;- zinc_(Ztotvisible);- qh_removefacet(qh, facet); /* visible_list at end of qh->facet_list */- qh_appendfacet(qh, facet);- qh->num_visible= 1;- if (facet->good)- (*goodvisible)++;- qh->visible_list= facet;- facet->visible= True;- facet->f.replace= NULL;- if (qh->IStracing >=4)- qh_errprint(qh, "visible", facet, NULL, NULL, NULL);- qh->visit_id++;- FORALLvisible_facets {- if (visible->tricoplanar && !qh->TRInormals) {- qh_fprintf(qh, qh->ferr, 6230, "Qhull internal error (qh_findhorizon): does not work for tricoplanar facets. Use option 'Q11'\n");- qh_errexit(qh, qh_ERRqhull, visible, NULL);- }- visible->visitid= qh->visit_id;- FOREACHneighbor_(visible) {- if (neighbor->visitid == qh->visit_id)- continue;- neighbor->visitid= qh->visit_id;- zzinc_(Znumvisibility);- qh_distplane(qh, point, neighbor, &dist);- if (dist > qh->MINvisible) {- zinc_(Ztotvisible);- qh_removefacet(qh, neighbor); /* append to end of qh->visible_list */- qh_appendfacet(qh, neighbor);- neighbor->visible= True;- neighbor->f.replace= NULL;- qh->num_visible++;- if (neighbor->good)- (*goodvisible)++;- if (qh->IStracing >=4)- qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);- }else {- if (dist > - qh->MAXcoplanar) {- neighbor->coplanar= True;- zzinc_(Zcoplanarhorizon);- qh_precision(qh, "coplanar horizon");- coplanar++;- if (qh->MERGING) {- if (dist > 0) {- maximize_(qh->max_outside, dist);- maximize_(qh->max_vertex, dist);-#if qh_MAXoutside- maximize_(neighbor->maxoutside, dist);-#endif- }else- minimize_(qh->min_vertex, dist); /* due to merge later */- }- trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",- qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));- }else- neighbor->coplanar= False;- zinc_(Ztothorizon);- numhorizon++;- if (neighbor->good)- (*goodhorizon)++;- if (qh->IStracing >=4)- qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);- }- }- }- if (!numhorizon) {- qh_precision(qh, "empty horizon");- qh_fprintf(qh, qh->ferr, 6168, "qhull precision error (qh_findhorizon): empty horizon\n\-QhullPoint p%d was above all facets.\n", qh_pointid(qh, point));- qh_printfacetlist(qh, qh->facet_list, NULL, True);- qh_errexit(qh, qh_ERRprec, NULL, NULL);- }- trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",- numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));- if (qh->IStracing >= 4 && qh->num_facets < 50)- qh_printlists(qh);-} /* findhorizon */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="nextfurthest">-</a>-- qh_nextfurthest(qh, visible )- returns next furthest point and visible facet for qh_addpoint()- starts search at qh.facet_next-- returns:- removes furthest point from outside set- NULL if none available- advances qh.facet_next over facets with empty outside sets-- design:- for each facet from qh.facet_next- if empty outside set- advance qh.facet_next- else if qh.NARROWhull- determine furthest outside point- if furthest point is not outside- advance qh.facet_next(point will be coplanar)- remove furthest point from outside set-*/-pointT *qh_nextfurthest(qhT *qh, facetT **visible) {- facetT *facet;- int size, idx;- realT randr, dist;- pointT *furthest;-- while ((facet= qh->facet_next) != qh->facet_tail) {- if (!facet->outsideset) {- qh->facet_next= facet->next;- continue;- }- SETreturnsize_(facet->outsideset, size);- if (!size) {- qh_setfree(qh, &facet->outsideset);- qh->facet_next= facet->next;- continue;- }- if (qh->NARROWhull) {- if (facet->notfurthest)- qh_furthestout(qh, facet);- furthest= (pointT*)qh_setlast(facet->outsideset);-#if qh_COMPUTEfurthest- qh_distplane(qh, furthest, facet, &dist);- zinc_(Zcomputefurthest);-#else- dist= facet->furthestdist;-#endif- if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */- qh->facet_next= facet->next;- continue;- }- }- if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {- if (qh->PICKfurthest) {- qh_furthestnext(qh /* qh->facet_list */);- facet= qh->facet_next;- }- *visible= facet;- return((pointT*)qh_setdellast(facet->outsideset));- }- if (qh->RANDOMoutside) {- int outcoplanar = 0;- if (qh->NARROWhull) {- FORALLfacets {- if (facet == qh->facet_next)- break;- if (facet->outsideset)- outcoplanar += qh_setsize(qh, facet->outsideset);- }- }- randr= qh_RANDOMint;- randr= randr/(qh_RANDOMmax+1);- idx= (int)floor((qh->num_outside - outcoplanar) * randr);- FORALLfacet_(qh->facet_next) {- if (facet->outsideset) {- SETreturnsize_(facet->outsideset, size);- if (!size)- qh_setfree(qh, &facet->outsideset);- else if (size > idx) {- *visible= facet;- return((pointT*)qh_setdelnth(qh, facet->outsideset, idx));- }else- idx -= size;- }- }- qh_fprintf(qh, qh->ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",- qh->num_outside, idx+1, randr);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }else { /* VIRTUALmemory */- facet= qh->facet_tail->previous;- if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {- if (facet->outsideset)- qh_setfree(qh, &facet->outsideset);- qh_removefacet(qh, facet);- qh_prependfacet(qh, facet, &qh->facet_list);- continue;- }- *visible= facet;- return furthest;- }- }- return NULL;-} /* nextfurthest */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="partitionall">-</a>-- qh_partitionall(qh, vertices, points, numpoints )- partitions all points in points/numpoints to the outsidesets of facets- vertices= vertices in qh.facet_list(!partitioned)-- returns:- builds facet->outsideset- does not partition qh.GOODpoint- if qh.ONLYgood && !qh.MERGING,- does not partition qh.GOODvertex-- notes:- faster if qh.facet_list sorted by anticipated size of outside set-- design:- initialize pointset with all points- remove vertices from pointset- remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)- for all facets- for all remaining points in pointset- compute distance from point to facet- if point is outside facet- remove point from pointset (by not reappending)- update bestpoint- append point or old bestpoint to facet's outside set- append bestpoint to facet's outside set (furthest)- for all points remaining in pointset- partition point into facets' outside sets and coplanar sets-*/-void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){- setT *pointset;- vertexT *vertex, **vertexp;- pointT *point, **pointp, *bestpoint;- int size, point_i, point_n, point_end, remaining, i, id;- facetT *facet;- realT bestdist= -REALmax, dist, distoutside;-- trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));- pointset= qh_settemp(qh, numpoints);- qh->num_outside= 0;- pointp= SETaddr_(pointset, pointT);- for (i=numpoints, point= points; i--; point += qh->hull_dim)- *(pointp++)= point;- qh_settruncate(qh, pointset, numpoints);- FOREACHvertex_(vertices) {- if ((id= qh_pointid(qh, vertex->point)) >= 0)- SETelem_(pointset, id)= NULL;- }- id= qh_pointid(qh, qh->GOODpointp);- if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)- SETelem_(pointset, id)= NULL;- if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/- if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)- SETelem_(pointset, id)= NULL;- }- if (!qh->BESToutside) { /* matches conditional for qh_partitionpoint below */- distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */- zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */- remaining= qh->num_facets;- point_end= numpoints;- FORALLfacets {- size= point_end/(remaining--) + 100;- facet->outsideset= qh_setnew(qh, size);- bestpoint= NULL;- point_end= 0;- FOREACHpoint_i_(qh, pointset) {- if (point) {- zzinc_(Zpartitionall);- qh_distplane(qh, point, facet, &dist);- if (dist < distoutside)- SETelem_(pointset, point_end++)= point;- else {- qh->num_outside++;- if (!bestpoint) {- bestpoint= point;- bestdist= dist;- }else if (dist > bestdist) {- qh_setappend(qh, &facet->outsideset, bestpoint);- bestpoint= point;- bestdist= dist;- }else- qh_setappend(qh, &facet->outsideset, point);- }- }- }- if (bestpoint) {- qh_setappend(qh, &facet->outsideset, bestpoint);-#if !qh_COMPUTEfurthest- facet->furthestdist= bestdist;-#endif- }else- qh_setfree(qh, &facet->outsideset);- qh_settruncate(qh, pointset, point_end);- }- }- /* if !qh->BESToutside, pointset contains points not assigned to outsideset */- if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside) {- qh->findbestnew= True;- FOREACHpoint_i_(qh, pointset) {- if (point)- qh_partitionpoint(qh, point, qh->facet_list);- }- qh->findbestnew= False;- }- zzadd_(Zpartitionall, zzval_(Zpartition));- zzval_(Zpartition)= 0;- qh_settempfree(qh, &pointset);- if (qh->IStracing >= 4)- qh_printfacetlist(qh, qh->facet_list, NULL, True);-} /* partitionall */---/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="partitioncoplanar">-</a>-- qh_partitioncoplanar(qh, point, facet, dist )- partition coplanar point to a facet- dist is distance from point to facet- if dist NULL,- searches for bestfacet and does nothing if inside- if qh.findbestnew set,- searches new facets instead of using qh_findbest()-- returns:- qh.max_ouside updated- if qh.KEEPcoplanar or qh.KEEPinside- point assigned to best coplanarset-- notes:- facet->maxoutside is updated at end by qh_check_maxout-- design:- if dist undefined- find best facet for point- if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)- exit- if keeping coplanar/nearinside/inside points- if point is above furthest coplanar point- append point to coplanar set (it is the new furthest)- update qh.max_outside- else- append point one before end of coplanar set- else if point is clearly outside of qh.max_outside and bestfacet->coplanarset- and bestfacet is more than perpendicular to facet- repartition the point using qh_findbest() -- it may be put on an outsideset- else- update qh.max_outside-*/-void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist) {- facetT *bestfacet;- pointT *oldfurthest;- realT bestdist, dist2= 0, angle;- int numpart= 0, oldfindbest;- boolT isoutside;-- qh->WAScoplanar= True;- if (!dist) {- if (qh->findbestnew)- bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);- else- bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,- &bestdist, &isoutside, &numpart);- zinc_(Ztotpartcoplanar);- zzadd_(Zpartcoplanar, numpart);- if (!qh->DELAUNAY && !qh->KEEPinside) { /* for 'd', bestdist skips upperDelaunay facets */- if (qh->KEEPnearinside) {- if (bestdist < -qh->NEARinside) {- zinc_(Zcoplanarinside);- trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",- qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));- return;- }- }else if (bestdist < -qh->MAXcoplanar) {- trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",- qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));- zinc_(Zcoplanarinside);- return;- }- }- }else {- bestfacet= facet;- bestdist= *dist;- }- if (bestdist > qh->max_outside) {- if (!dist && facet != bestfacet) {- zinc_(Zpartangle);- angle= qh_getangle(qh, facet->normal, bestfacet->normal);- if (angle < 0) {- /* typically due to deleted vertex and coplanar facets, e.g.,- RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */- zinc_(Zpartflip);- trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition point p%d from f%d. It is above flipped facet f%d dist %2.2g\n",- qh_pointid(qh, point), facet->id, bestfacet->id, bestdist));- oldfindbest= qh->findbestnew;- qh->findbestnew= False;- qh_partitionpoint(qh, point, bestfacet);- qh->findbestnew= oldfindbest;- return;- }- }- qh->max_outside= bestdist;- if (bestdist > qh->TRACEdist) {- qh_fprintf(qh, qh->ferr, 8122, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",- qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);- qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);- }- }- if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {- oldfurthest= (pointT*)qh_setlast(bestfacet->coplanarset);- if (oldfurthest) {- zinc_(Zcomputefurthest);- qh_distplane(qh, oldfurthest, bestfacet, &dist2);- }- if (!oldfurthest || dist2 < bestdist)- qh_setappend(qh, &bestfacet->coplanarset, point);- else- qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);- }- trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d(or inside) dist %2.2g\n",- qh_pointid(qh, point), bestfacet->id, bestdist));-} /* partitioncoplanar */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="partitionpoint">-</a>-- qh_partitionpoint(qh, point, facet )- assigns point to an outside set, coplanar set, or inside set (i.e., dropt)- if qh.findbestnew- uses qh_findbestnew() to search all new facets- else- uses qh_findbest()-- notes:- after qh_distplane(), this and qh_findbest() are most expensive in 3-d-- design:- find best facet for point- (either exhaustive search of new facets or directed search from facet)- if qh.NARROWhull- retain coplanar and nearinside points as outside points- if point is outside bestfacet- if point above furthest point for bestfacet- append point to outside set (it becomes the new furthest)- if outside set was empty- move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)- update bestfacet->furthestdist- else- append point one before end of outside set- else if point is coplanar to bestfacet- if keeping coplanar points or need to update qh.max_outside- partition coplanar point into bestfacet- else if near-inside point- partition as coplanar point into bestfacet- else is an inside point- if keeping inside points- partition as coplanar point into bestfacet-*/-void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {- realT bestdist;- boolT isoutside;- facetT *bestfacet;- int numpart;-#if qh_COMPUTEfurthest- realT dist;-#endif-- if (qh->findbestnew)- bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);- else- bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,- &bestdist, &isoutside, &numpart);- zinc_(Ztotpartition);- zzadd_(Zpartition, numpart);- if (qh->NARROWhull) {- if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)- qh_precision(qh, "nearly incident point(narrow hull)");- if (qh->KEEPnearinside) {- if (bestdist >= -qh->NEARinside)- isoutside= True;- }else if (bestdist >= -qh->MAXcoplanar)- isoutside= True;- }-- if (isoutside) {- if (!bestfacet->outsideset- || !qh_setlast(bestfacet->outsideset)) {- qh_setappend(qh, &(bestfacet->outsideset), point);- if (!bestfacet->newfacet) {- qh_removefacet(qh, bestfacet); /* make sure it's after qh->facet_next */- qh_appendfacet(qh, bestfacet);- }-#if !qh_COMPUTEfurthest- bestfacet->furthestdist= bestdist;-#endif- }else {-#if qh_COMPUTEfurthest- zinc_(Zcomputefurthest);- qh_distplane(qh, oldfurthest, bestfacet, &dist);- if (dist < bestdist)- qh_setappend(qh, &(bestfacet->outsideset), point);- else- qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);-#else- if (bestfacet->furthestdist < bestdist) {- qh_setappend(qh, &(bestfacet->outsideset), point);- bestfacet->furthestdist= bestdist;- }else- qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);-#endif- }- qh->num_outside++;- trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d new? %d (or narrowhull)\n",- qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet));- }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */- zzinc_(Zcoplanarpart);- if (qh->DELAUNAY)- qh_precision(qh, "nearly incident point");- if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)- qh_partitioncoplanar(qh, point, bestfacet, &bestdist);- else {- trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",- qh_pointid(qh, point), bestfacet->id));- }- }else if (qh->KEEPnearinside && bestdist > -qh->NEARinside) {- zinc_(Zpartnear);- qh_partitioncoplanar(qh, point, bestfacet, &bestdist);- }else {- zinc_(Zpartinside);- trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",- qh_pointid(qh, point), bestfacet->id, bestdist));- if (qh->KEEPinside)- qh_partitioncoplanar(qh, point, bestfacet, &bestdist);- }-} /* partitionpoint */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="partitionvisible">-</a>-- qh_partitionvisible(qh, allpoints, numoutside )- partitions points in visible facets to qh.newfacet_list- qh.visible_list= visible facets- for visible facets- 1st neighbor (if any) points to a horizon facet or a new facet- if allpoints(!used),- repartitions coplanar points-- returns:- updates outside sets and coplanar sets of qh.newfacet_list- updates qh.num_outside (count of outside points)-- notes:- qh.findbest_notsharp should be clear (extra work if set)-- design:- for all visible facets with outside set or coplanar set- select a newfacet for visible facet- if outside set- partition outside set into new facets- if coplanar set and keeping coplanar/near-inside/inside points- if allpoints- partition coplanar set into new facets, may be assigned outside- else- partition coplanar set into coplanar sets of new facets- for each deleted vertex- if allpoints- partition vertex into new facets, may be assigned outside- else- partition vertex into coplanar sets of new facets-*/-void qh_partitionvisible(qhT *qh /*qh.visible_list*/, boolT allpoints, int *numoutside) {- facetT *visible, *newfacet;- pointT *point, **pointp;- int coplanar=0, size;- unsigned count;- vertexT *vertex, **vertexp;-- if (qh->ONLYmax)- maximize_(qh->MINoutside, qh->max_vertex);- *numoutside= 0;- FORALLvisible_facets {- if (!visible->outsideset && !visible->coplanarset)- continue;- newfacet= visible->f.replace;- count= 0;- while (newfacet && newfacet->visible) {- newfacet= newfacet->f.replace;- if (count++ > qh->facet_id)- qh_infiniteloop(qh, visible);- }- if (!newfacet)- newfacet= qh->newfacet_list;- if (newfacet == qh->facet_tail) {- qh_fprintf(qh, qh->ferr, 6170, "qhull precision error (qh_partitionvisible): all new facets deleted as\n degenerate facets. Can not continue.\n");- qh_errexit(qh, qh_ERRprec, NULL, NULL);- }- if (visible->outsideset) {- size= qh_setsize(qh, visible->outsideset);- *numoutside += size;- qh->num_outside -= size;- FOREACHpoint_(visible->outsideset)- qh_partitionpoint(qh, point, newfacet);- }- if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {- size= qh_setsize(qh, visible->coplanarset);- coplanar += size;- FOREACHpoint_(visible->coplanarset) {- if (allpoints) /* not used */- qh_partitionpoint(qh, point, newfacet);- else- qh_partitioncoplanar(qh, point, newfacet, NULL);- }- }- }- FOREACHvertex_(qh->del_vertices) {- if (vertex->point) {- if (allpoints) /* not used */- qh_partitionpoint(qh, vertex->point, qh->newfacet_list);- else- qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL);- }- }- trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));-} /* partitionvisible */----/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="precision">-</a>-- qh_precision(qh, reason )- restart on precision errors if not merging and if 'QJn'-*/-void qh_precision(qhT *qh, const char *reason) {-- if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {- if (qh->JOGGLEmax < REALmax/2) {- trace0((qh, qh->ferr, 26, "qh_precision: qhull restart because of %s\n", reason));- /* May be called repeatedly if qh->ALLOWrestart */- longjmp(qh->restartexit, qh_ERRprec);- }- }-} /* qh_precision */--/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="printsummary">-</a>-- qh_printsummary(qh, fp )- prints summary to fp-- notes:- not in io_r.c so that user_eg.c can prevent io_r.c from loading- qh_printsummary and qh_countfacets must match counts-- design:- determine number of points, vertices, and coplanar points- print summary-*/-void qh_printsummary(qhT *qh, FILE *fp) {- realT ratio, outerplane, innerplane;- float cpu;- int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;- int goodused;- facetT *facet;- const char *s;- int numdel= zzval_(Zdelvertextot);- int numtricoplanars= 0;-- size= qh->num_points + qh_setsize(qh, qh->other_points);- numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);- id= qh_pointid(qh, qh->GOODpointp);- FORALLfacets {- if (facet->coplanarset)- numcoplanars += qh_setsize(qh, facet->coplanarset);- if (facet->good) {- if (facet->simplicial) {- if (facet->keepcentrum && facet->tricoplanar)- numtricoplanars++;- }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)- nonsimplicial++;- }- }- if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)- size--;- if (qh->STOPcone || qh->STOPpoint)- qh_fprintf(qh, fp, 9288, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");- if (qh->UPPERdelaunay)- goodused= qh->GOODvertex + qh->GOODpoint + qh->SPLITthresholds;- else if (qh->DELAUNAY)- goodused= qh->GOODvertex + qh->GOODpoint + qh->GOODthreshold;- else- goodused= qh->num_good;- nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);- if (qh->VORONOI) {- if (qh->UPPERdelaunay)- qh_fprintf(qh, fp, 9289, "\n\-Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- else- qh_fprintf(qh, fp, 9290, "\n\-Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- qh_fprintf(qh, fp, 9291, " Number of Voronoi regions%s: %d\n",- qh->ATinfinity ? " and at-infinity" : "", numvertices);- if (numdel)- qh_fprintf(qh, fp, 9292, " Total number of deleted points due to merging: %d\n", numdel);- if (numcoplanars - numdel > 0)- qh_fprintf(qh, fp, 9293, " Number of nearly incident points: %d\n", numcoplanars - numdel);- else if (size - numvertices - numdel > 0)- qh_fprintf(qh, fp, 9294, " Total number of nearly incident points: %d\n", size - numvertices - numdel);- qh_fprintf(qh, fp, 9295, " Number of%s Voronoi vertices: %d\n",- goodused ? " 'good'" : "", qh->num_good);- if (nonsimplicial)- qh_fprintf(qh, fp, 9296, " Number of%s non-simplicial Voronoi vertices: %d\n",- goodused ? " 'good'" : "", nonsimplicial);- }else if (qh->DELAUNAY) {- if (qh->UPPERdelaunay)- qh_fprintf(qh, fp, 9297, "\n\-Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- else- qh_fprintf(qh, fp, 9298, "\n\-Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- qh_fprintf(qh, fp, 9299, " Number of input sites%s: %d\n",- qh->ATinfinity ? " and at-infinity" : "", numvertices);- if (numdel)- qh_fprintf(qh, fp, 9300, " Total number of deleted points due to merging: %d\n", numdel);- if (numcoplanars - numdel > 0)- qh_fprintf(qh, fp, 9301, " Number of nearly incident points: %d\n", numcoplanars - numdel);- else if (size - numvertices - numdel > 0)- qh_fprintf(qh, fp, 9302, " Total number of nearly incident points: %d\n", size - numvertices - numdel);- qh_fprintf(qh, fp, 9303, " Number of%s Delaunay regions: %d\n",- goodused ? " 'good'" : "", qh->num_good);- if (nonsimplicial)- qh_fprintf(qh, fp, 9304, " Number of%s non-simplicial Delaunay regions: %d\n",- goodused ? " 'good'" : "", nonsimplicial);- }else if (qh->HALFspace) {- qh_fprintf(qh, fp, 9305, "\n\-Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- qh_fprintf(qh, fp, 9306, " Number of halfspaces: %d\n", size);- qh_fprintf(qh, fp, 9307, " Number of non-redundant halfspaces: %d\n", numvertices);- if (numcoplanars) {- if (qh->KEEPinside && qh->KEEPcoplanar)- s= "similar and redundant";- else if (qh->KEEPinside)- s= "redundant";- else- s= "similar";- qh_fprintf(qh, fp, 9308, " Number of %s halfspaces: %d\n", s, numcoplanars);- }- qh_fprintf(qh, fp, 9309, " Number of intersection points: %d\n", qh->num_facets - qh->num_visible);- if (goodused)- qh_fprintf(qh, fp, 9310, " Number of 'good' intersection points: %d\n", qh->num_good);- if (nonsimplicial)- qh_fprintf(qh, fp, 9311, " Number of%s non-simplicial intersection points: %d\n",- goodused ? " 'good'" : "", nonsimplicial);- }else {- qh_fprintf(qh, fp, 9312, "\n\-Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);- qh_fprintf(qh, fp, 9313, " Number of vertices: %d\n", numvertices);- if (numcoplanars) {- if (qh->KEEPinside && qh->KEEPcoplanar)- s= "coplanar and interior";- else if (qh->KEEPinside)- s= "interior";- else- s= "coplanar";- qh_fprintf(qh, fp, 9314, " Number of %s points: %d\n", s, numcoplanars);- }- qh_fprintf(qh, fp, 9315, " Number of facets: %d\n", qh->num_facets - qh->num_visible);- if (goodused)- qh_fprintf(qh, fp, 9316, " Number of 'good' facets: %d\n", qh->num_good);- if (nonsimplicial)- qh_fprintf(qh, fp, 9317, " Number of%s non-simplicial facets: %d\n",- goodused ? " 'good'" : "", nonsimplicial);- }- if (numtricoplanars)- qh_fprintf(qh, fp, 9318, " Number of triangulated facets: %d\n", numtricoplanars);- qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",- qh->rbox_command, qh->qhull_command);- if (qh->ROTATErandom != INT_MIN)- qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);- else- qh_fprintf(qh, fp, 9321, "\n\n");- qh_fprintf(qh, fp, 9322, " Number of points processed: %d\n", zzval_(Zprocessed));- qh_fprintf(qh, fp, 9323, " Number of hyperplanes created: %d\n", zzval_(Zsetplane));- if (qh->DELAUNAY)- qh_fprintf(qh, fp, 9324, " Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);- qh_fprintf(qh, fp, 9325, " Number of distance tests for qhull: %d\n", zzval_(Zpartition)+- zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));-#if 0 /* NOTE: must print before printstatistics() */- {realT stddev, ave;- qh_fprintf(qh, fp, 9326, " average new facet balance: %2.2g\n",- wval_(Wnewbalance)/zval_(Zprocessed));- stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),- wval_(Wnewbalance2), &ave);- qh_fprintf(qh, fp, 9327, " new facet standard deviation: %2.2g\n", stddev);- qh_fprintf(qh, fp, 9328, " average partition balance: %2.2g\n",- wval_(Wpbalance)/zval_(Zpbalance));- stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),- wval_(Wpbalance2), &ave);- qh_fprintf(qh, fp, 9329, " partition standard deviation: %2.2g\n", stddev);- }-#endif- if (nummerged) {- qh_fprintf(qh, fp, 9330," Number of distance tests for merging: %d\n",zzval_(Zbestdist)+- zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+- zzval_(Zdistzero));- qh_fprintf(qh, fp, 9331," Number of distance tests for checking: %d\n",zzval_(Zcheckpart));- qh_fprintf(qh, fp, 9332," Number of merged facets: %d\n", nummerged);- }- if (!qh->RANDOMoutside && qh->QHULLfinished) {- cpu= (float)qh->hulltime;- cpu /= (float)qh_SECticks;- wval_(Wcpu)= cpu;- qh_fprintf(qh, fp, 9333, " CPU seconds to compute hull (after input): %2.4g\n", cpu);- }- if (qh->RERUN) {- if (!qh->PREmerge && !qh->MERGEexact)- qh_fprintf(qh, fp, 9334, " Percentage of runs with precision errors: %4.1f\n",- zzval_(Zretry)*100.0/qh->build_cnt); /* careful of order */- }else if (qh->JOGGLEmax < REALmax/2) {- if (zzval_(Zretry))- qh_fprintf(qh, fp, 9335, " After %d retries, input joggled by: %2.2g\n",- zzval_(Zretry), qh->JOGGLEmax);- else- qh_fprintf(qh, fp, 9336, " Input joggled by: %2.2g\n", qh->JOGGLEmax);- }- if (qh->totarea != 0.0)- qh_fprintf(qh, fp, 9337, " %s facet area: %2.8g\n",- zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);- if (qh->totvol != 0.0)- qh_fprintf(qh, fp, 9338, " %s volume: %2.8g\n",- zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);- if (qh->MERGING) {- qh_outerinner(qh, NULL, &outerplane, &innerplane);- if (outerplane > 2 * qh->DISTround) {- qh_fprintf(qh, fp, 9339, " Maximum distance of %spoint above facet: %2.2g",- (qh->QHULLfinished ? "" : "merged "), outerplane);- ratio= outerplane/(qh->ONEmerge + qh->DISTround);- /* don't report ratio if MINoutside is large */- if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)- qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);- else- qh_fprintf(qh, fp, 9341, "\n");- }- if (innerplane < -2 * qh->DISTround) {- qh_fprintf(qh, fp, 9342, " Maximum distance of %svertex below facet: %2.2g",- (qh->QHULLfinished ? "" : "merged "), innerplane);- ratio= -innerplane/(qh->ONEmerge+qh->DISTround);- if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)- qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);- else- qh_fprintf(qh, fp, 9344, "\n");- }- }- qh_fprintf(qh, fp, 9345, "\n");-} /* printsummary */--
− C/mem_r.c
@@ -1,562 +0,0 @@-/*<html><pre> -<a href="qh-mem_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- mem_r.c- memory management routines for qhull-- See libqhull/mem_r.c for a standalone program.-- To initialize memory:-- qh_meminit(qh, stderr);- qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);- qh_memsize(qh, (int)sizeof(facetT));- qh_memsize(qh, (int)sizeof(facetT));- ...- qh_memsetup(qh);-- To free up all memory buffers:- qh_memfreeshort(qh, &curlong, &totlong);-- if qh_NOmem,- malloc/free is used instead of mem.c-- notes:- uses Quickfit algorithm (freelists for commonly allocated sizes)- assumes small sizes for freelists (it discards the tail of memory buffers)-- see:- qh-mem_r.htm and mem_r.h- global_r.c (qh_initbuffers) for an example of using mem_r.c-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/mem_r.c#5 $$Change: 2065 $- $DateTime: 2016/01/18 13:51:04 $$Author: bbarber $-*/--#include "libqhull_r.h" /* includes user_r.h and mem_r.h */--#include <string.h>-#include <stdio.h>-#include <stdlib.h>--#ifndef qh_NOmem--/*============= internal functions ==============*/--static int qh_intcompare(const void *i, const void *j);--/*========== functions in alphabetical order ======== */--/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="intcompare">-</a>-- qh_intcompare( i, j )- used by qsort and bsearch to compare two integers-*/-static int qh_intcompare(const void *i, const void *j) {- return(*((const int *)i) - *((const int *)j));-} /* intcompare */---/*-<a href="qh-mem_r.htm#TOC"- >--------------------------------</a><a name="memalloc">-</a>-- qh_memalloc( qh, insize )- returns object of insize bytes- qhmem is the global memory structure-- returns:- pointer to allocated memory- errors if insufficient memory-- notes:- use explicit type conversion to avoid type warnings on some compilers- actual object may be larger than insize- use qh_memalloc_() for inline code for quick allocations- logs allocations if 'T5'- caller is responsible for freeing the memory.- short memory is freed on shutdown by qh_memfreeshort unless qh_NOmem-- design:- if size < qh->qhmem.LASTsize- if qh->qhmem.freelists[size] non-empty- return first object on freelist- else- round up request to size of qh->qhmem.freelists[size]- allocate new allocation buffer if necessary- allocate object from allocation buffer- else- allocate object with qh_malloc() in user.c-*/-void *qh_memalloc(qhT *qh, int insize) {- void **freelistp, *newbuffer;- int idx, size, n;- int outsize, bufsize;- void *object;-- if (insize<0) {- qh_fprintf(qh, qh->qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d). Did int overflow due to high-D?\n", insize); /* WARN64 */- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- if (insize>=0 && insize <= qh->qhmem.LASTsize) {- idx= qh->qhmem.indextable[insize];- outsize= qh->qhmem.sizetable[idx];- qh->qhmem.totshort += outsize;- freelistp= qh->qhmem.freelists+idx;- if ((object= *freelistp)) {- qh->qhmem.cntquick++;- qh->qhmem.totfree -= outsize;- *freelistp= *((void **)*freelistp); /* replace freelist with next object */-#ifdef qh_TRACEshort- n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);-#endif- return(object);- }else {- qh->qhmem.cntshort++;- if (outsize > qh->qhmem.freesize) {- qh->qhmem.totdropped += qh->qhmem.freesize;- if (!qh->qhmem.curbuffer)- bufsize= qh->qhmem.BUFinit;- else- bufsize= qh->qhmem.BUFsize;- if (!(newbuffer= qh_malloc((size_t)bufsize))) {- qh_fprintf(qh, qh->qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- *((void **)newbuffer)= qh->qhmem.curbuffer; /* prepend newbuffer to curbuffer- list. newbuffer!=0 by QH6080 */- qh->qhmem.curbuffer= newbuffer;- size= (sizeof(void **) + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;- qh->qhmem.freemem= (void *)((char *)newbuffer+size);- qh->qhmem.freesize= bufsize - size;- qh->qhmem.totbuffer += bufsize - size; /* easier to check */- /* Periodically test totbuffer. It matches at beginning and exit of every call */- n = qh->qhmem.totshort + qh->qhmem.totfree + qh->qhmem.totdropped + qh->qhmem.freesize - outsize;- if (qh->qhmem.totbuffer != n) {- qh_fprintf(qh, qh->qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qh->qhmem.totbuffer, n);- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- }- object= qh->qhmem.freemem;- qh->qhmem.freemem= (void *)((char *)qh->qhmem.freemem + outsize);- qh->qhmem.freesize -= outsize;- qh->qhmem.totunused += outsize - insize;-#ifdef qh_TRACEshort- n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);-#endif- return object;- }- }else { /* long allocation */- if (!qh->qhmem.indextable) {- qh_fprintf(qh, qh->qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- outsize= insize;- qh->qhmem.cntlong++;- qh->qhmem.totlong += outsize;- if (qh->qhmem.maxlong < qh->qhmem.totlong)- qh->qhmem.maxlong= qh->qhmem.totlong;- if (!(object= qh_malloc((size_t)outsize))) {- qh_fprintf(qh, qh->qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, outsize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);- }- return(object);-} /* memalloc */---/*-<a href="qh-mem_r.htm#TOC"- >--------------------------------</a><a name="memcheck">-</a>-- qh_memcheck(qh)-*/-void qh_memcheck(qhT *qh) {- int i, count, totfree= 0;- void *object;-- if (!qh) {- qh_fprintf_stderr(6243, "qh_memcheck(qh) error: qh is 0. It does not point to a qhT");- qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */- }- if (qh->qhmem.ferr == 0 || qh->qhmem.IStracing < 0 || qh->qhmem.IStracing > 10 || (((qh->qhmem.ALIGNmask+1) & qh->qhmem.ALIGNmask) != 0)) {- qh_fprintf_stderr(6244, "qh_memcheck error: either qh->qhmem is overwritten or qh->qhmem is not initialized. Call qh_mem_new() or qh_new_qhull() before calling qh_mem routines. ferr 0x%x IsTracing %d ALIGNmask 0x%x", qh->qhmem.ferr, qh->qhmem.IStracing, qh->qhmem.ALIGNmask);- qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */- return;- }- if (qh->qhmem.IStracing != 0)- qh_fprintf(qh, qh->qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qh->qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qh->qhmem\n");- for (i=0; i < qh->qhmem.TABLEsize; i++) {- count=0;- for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))- count++;- totfree += qh->qhmem.sizetable[i] * count;- }- if (totfree != qh->qhmem.totfree) {- qh_fprintf(qh, qh->qhmem.ferr, 6211, "Qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qh->qhmem.totfree, totfree);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- if (qh->qhmem.IStracing != 0)- qh_fprintf(qh, qh->qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree is the same as qh->qhmem.totfree\n", totfree);-} /* memcheck */--/*-<a href="qh-mem_r.htm#TOC"- >--------------------------------</a><a name="memfree">-</a>-- qh_memfree(qh, object, insize )- free up an object of size bytes- size is insize from qh_memalloc-- notes:- object may be NULL- type checking warns if using (void **)object- use qh_memfree_() for quick free's of small objects-- design:- if size <= qh->qhmem.LASTsize- append object to corresponding freelist- else- call qh_free(object)-*/-void qh_memfree(qhT *qh, void *object, int insize) {- void **freelistp;- int idx, outsize;-- if (!object)- return;- if (insize <= qh->qhmem.LASTsize) {- qh->qhmem.freeshort++;- idx= qh->qhmem.indextable[insize];- outsize= qh->qhmem.sizetable[idx];- qh->qhmem.totfree += outsize;- qh->qhmem.totshort -= outsize;- freelistp= qh->qhmem.freelists + idx;- *((void **)object)= *freelistp;- *freelistp= object;-#ifdef qh_TRACEshort- idx= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);-#endif- }else {- qh->qhmem.freelong++;- qh->qhmem.totlong -= insize;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);- qh_free(object);- }-} /* memfree */---/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="memfreeshort">-</a>-- qh_memfreeshort(qh, curlong, totlong )- frees up all short and qhmem memory allocations-- returns:- number and size of current long allocations-- notes:- if qh_NOmem (qh_malloc() for all allocations),- short objects (e.g., facetT) are not recovered.- use qh_freeqhull(qh, qh_ALL) instead.-- see:- qh_freeqhull(qh, allMem)- qh_memtotal(qh, curlong, totlong, curshort, totshort, maxlong, totbuffer);-*/-void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {- void *buffer, *nextbuffer;- FILE *ferr;-- *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;- *totlong= qh->qhmem.totlong;- for (buffer= qh->qhmem.curbuffer; buffer; buffer= nextbuffer) {- nextbuffer= *((void **) buffer);- qh_free(buffer);- }- qh->qhmem.curbuffer= NULL;- if (qh->qhmem.LASTsize) {- qh_free(qh->qhmem.indextable);- qh_free(qh->qhmem.freelists);- qh_free(qh->qhmem.sizetable);- }- ferr= qh->qhmem.ferr;- memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */- qh->qhmem.ferr= ferr;-} /* memfreeshort */---/*-<a href="qh-mem_r.htm#TOC"- >--------------------------------</a><a name="meminit">-</a>-- qh_meminit(qh, ferr )- initialize qhmem and test sizeof( void*)- Does not throw errors. qh_exit on failure-*/-void qh_meminit(qhT *qh, FILE *ferr) {-- memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */- if (ferr)- qh->qhmem.ferr= ferr;- else- qh->qhmem.ferr= stderr;- if (sizeof(void*) < sizeof(int)) {- qh_fprintf(qh, qh->qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));- qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */- }- if (sizeof(void*) > sizeof(ptr_intT)) {- qh_fprintf(qh, qh->qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));- qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */- }- qh_memcheck(qh);-} /* meminit */--/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="meminitbuffers">-</a>-- qh_meminitbuffers(qh, tracelevel, alignment, numsizes, bufsize, bufinit )- initialize qhmem- if tracelevel >= 5, trace memory allocations- alignment= desired address alignment for memory allocations- numsizes= number of freelists- bufsize= size of additional memory buffers for short allocations- bufinit= size of initial memory buffer for short allocations-*/-void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {-- qh->qhmem.IStracing= tracelevel;- qh->qhmem.NUMsizes= numsizes;- qh->qhmem.BUFsize= bufsize;- qh->qhmem.BUFinit= bufinit;- qh->qhmem.ALIGNmask= alignment-1;- if (qh->qhmem.ALIGNmask & ~qh->qhmem.ALIGNmask) {- qh_fprintf(qh, qh->qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- qh->qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));- qh->qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));- if (!qh->qhmem.sizetable || !qh->qhmem.freelists) {- qh_fprintf(qh, qh->qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- if (qh->qhmem.IStracing >= 1)- qh_fprintf(qh, qh->qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);-} /* meminitbuffers */--/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="memsetup">-</a>-- qh_memsetup(qh)- set up memory after running memsize()-*/-void qh_memsetup(qhT *qh) {- int k,i;-- qsort(qh->qhmem.sizetable, (size_t)qh->qhmem.TABLEsize, sizeof(int), qh_intcompare);- qh->qhmem.LASTsize= qh->qhmem.sizetable[qh->qhmem.TABLEsize-1];- if(qh->qhmem.LASTsize >= qh->qhmem.BUFsize || qh->qhmem.LASTsize >= qh->qhmem.BUFinit) {- qh_fprintf(qh, qh->qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",- qh->qhmem.LASTsize, qh->qhmem.BUFsize, qh->qhmem.BUFinit);- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- if (!(qh->qhmem.indextable= (int *)qh_malloc((qh->qhmem.LASTsize+1) * sizeof(int)))) {- qh_fprintf(qh, qh->qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- for (k=qh->qhmem.LASTsize+1; k--; )- qh->qhmem.indextable[k]= k;- i= 0;- for (k=0; k <= qh->qhmem.LASTsize; k++) {- if (qh->qhmem.indextable[k] <= qh->qhmem.sizetable[i])- qh->qhmem.indextable[k]= i;- else- qh->qhmem.indextable[k]= ++i;- }-} /* memsetup */--/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="memsize">-</a>-- qh_memsize(qh, size )- define a free list for this size-*/-void qh_memsize(qhT *qh, int size) {- int k;-- if(qh->qhmem.LASTsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- size= (size + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;- for (k=qh->qhmem.TABLEsize; k--; ) {- if (qh->qhmem.sizetable[k] == size)- return;- }- if (qh->qhmem.TABLEsize < qh->qhmem.NUMsizes)- qh->qhmem.sizetable[qh->qhmem.TABLEsize++]= size;- else- qh_fprintf(qh, qh->qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qh->qhmem.NUMsizes);-} /* memsize */---/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="memstatistics">-</a>-- qh_memstatistics(qh, fp )- print out memory statistics-- Verifies that qh->qhmem.totfree == sum of freelists-*/-void qh_memstatistics(qhT *qh, FILE *fp) {- int i;- int count;- void *object;-- qh_memcheck(qh);- qh_fprintf(qh, fp, 9278, "\nmemory statistics:\n\-%7d quick allocations\n\-%7d short allocations\n\-%7d long allocations\n\-%7d short frees\n\-%7d long frees\n\-%7d bytes of short memory in use\n\-%7d bytes of short memory in freelists\n\-%7d bytes of dropped short memory\n\-%7d bytes of unused short memory (estimated)\n\-%7d bytes of long memory allocated (max, except for input)\n\-%7d bytes of long memory in use (in %d pieces)\n\-%7d bytes of short memory buffers (minus links)\n\-%7d bytes per short memory buffer (initially %d bytes)\n",- qh->qhmem.cntquick, qh->qhmem.cntshort, qh->qhmem.cntlong,- qh->qhmem.freeshort, qh->qhmem.freelong,- qh->qhmem.totshort, qh->qhmem.totfree,- qh->qhmem.totdropped + qh->qhmem.freesize, qh->qhmem.totunused,- qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong,- qh->qhmem.totbuffer, qh->qhmem.BUFsize, qh->qhmem.BUFinit);- if (qh->qhmem.cntlarger) {- qh_fprintf(qh, fp, 9279, "%7d calls to qh_setlarger\n%7.2g average copy size\n",- qh->qhmem.cntlarger, ((float)qh->qhmem.totlarger)/(float)qh->qhmem.cntlarger);- qh_fprintf(qh, fp, 9280, " freelists(bytes->count):");- }- for (i=0; i < qh->qhmem.TABLEsize; i++) {- count=0;- for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))- count++;- qh_fprintf(qh, fp, 9281, " %d->%d", qh->qhmem.sizetable[i], count);- }- qh_fprintf(qh, fp, 9282, "\n\n");-} /* memstatistics */---/*-<a href="qh-mem_r.htm#TOC"- >-------------------------------</a><a name="NOmem">-</a>-- qh_NOmem- turn off quick-fit memory allocation-- notes:- uses qh_malloc() and qh_free() instead-*/-#else /* qh_NOmem */--void *qh_memalloc(qhT *qh, int insize) {- void *object;-- if (!(object= qh_malloc((size_t)insize))) {- qh_fprintf(qh, qh->qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- qh->qhmem.cntlong++;- qh->qhmem.totlong += insize;- if (qh->qhmem.maxlong < qh->qhmem.totlong)- qh->qhmem.maxlong= qh->qhmem.totlong;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);- return object;-}--void qh_memfree(qhT *qh, void *object, int insize) {-- if (!object)- return;- qh_free(object);- qh->qhmem.freelong++;- qh->qhmem.totlong -= insize;- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);-}--void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {- *totlong= qh->qhmem.totlong;- *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;- memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */-}--void qh_meminit(qhT *qh, FILE *ferr) {-- memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */- if (ferr)- qh->qhmem.ferr= ferr;- else- qh->qhmem.ferr= stderr;- if (sizeof(void*) < sizeof(int)) {- qh_fprintf(qh, qh->qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }-}--void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {-- qh->qhmem.IStracing= tracelevel;-}--void qh_memsetup(qhT *qh) {--}--void qh_memsize(qhT *qh, int size) {--}--void qh_memstatistics(qhT *qh, FILE *fp) {-- qh_fprintf(qh, fp, 9409, "\nmemory statistics:\n\-%7d long allocations\n\-%7d long frees\n\-%7d bytes of long memory allocated (max, except for input)\n\-%7d bytes of long memory in use (in %d pieces)\n",- qh->qhmem.cntlong,- qh->qhmem.freelong,- qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong);-}--#endif /* qh_NOmem */--/*-<a href="qh-mem_r.htm#TOC"->-------------------------------</a><a name="memtotlong">-</a>-- qh_memtotal(qh, totlong, curlong, totshort, curshort, maxlong, totbuffer )- Return the total, allocated long and short memory-- returns:- Returns the total current bytes of long and short allocations- Returns the current count of long and short allocations- Returns the maximum long memory and total short buffer (minus one link per buffer)- Does not error (for deprecated UsingLibQhull.cpp (libqhullpcpp))-*/-void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {- *totlong= qh->qhmem.totlong;- *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;- *totshort= qh->qhmem.totshort;- *curshort= qh->qhmem.cntshort + qh->qhmem.cntquick - qh->qhmem.freeshort;- *maxlong= qh->qhmem.maxlong;- *totbuffer= qh->qhmem.totbuffer;-} /* memtotlong */
− C/merge_r.c
@@ -1,3627 +0,0 @@-/*<html><pre> -<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="TOP">-</a>-- merge_r.c- merges non-convex facets-- see qh-merge_r.htm and merge_r.h-- other modules call qh_premerge() and qh_postmerge()-- the user may call qh_postmerge() to perform additional merges.-- To remove deleted facets and vertices (qhull() in libqhull_r.c):- qh_partitionvisible(qh, !qh_ALL, &numoutside); // visible_list, newfacet_list- qh_deletevisible(); // qh.visible_list- qh_resetlists(qh, False, qh_RESETvisible); // qh.visible_list newvertex_list newfacet_list-- assumes qh.CENTERtype= centrum-- merges occur in qh_mergefacet and in qh_mergecycle- vertex->neighbors not set until the first merge occurs-- Copyright (c) 1993-2015 C.B. Barber.- $Id: //main/2015/qhull/src/libqhull_r/merge_r.c#5 $$Change: 2064 $- $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $-*/--#include "qhull_ra.h"--#ifndef qh_NOmerge--/*===== functions(alphabetical after premerge and postmerge) ======*/--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="premerge">-</a>-- qh_premerge(qh, apex, maxcentrum )- pre-merge nonconvex facets in qh.newfacet_list for apex- maxcentrum defines coplanar and concave (qh_test_appendmerge)-- returns:- deleted facets added to qh.visible_list with facet->visible set-- notes:- uses globals, qh.MERGEexact, qh.PREmerge-- design:- mark duplicate ridges in qh.newfacet_list- merge facet cycles in qh.newfacet_list- merge duplicate ridges and concave facets in qh.newfacet_list- check merged facet cycles for degenerate and redundant facets- merge degenerate and redundant facets- collect coplanar and concave facets- merge concave, coplanar, degenerate, and redundant facets-*/-void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {- boolT othermerge= False;- facetT *newfacet;-- if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))- return;- trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",- maxcentrum, maxangle, apex->id, getid_(qh->newfacet_list)));- if (qh->IStracing >= 4 && qh->num_facets < 50)- qh_printlists(qh);- qh->centrum_radius= maxcentrum;- qh->cos_max= maxangle;- qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);- qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);- if (qh->hull_dim >=3) {- qh_mark_dupridges(qh, qh->newfacet_list); /* facet_mergeset */- qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);- qh_forcedmerges(qh, &othermerge /* qh->facet_mergeset */);- FORALLnew_facets { /* test samecycle merges */- if (!newfacet->simplicial && !newfacet->mergeridge)- qh_degen_redundant_neighbors(qh, newfacet, NULL);- }- if (qh_merge_degenredundant(qh))- othermerge= True;- }else /* qh->hull_dim == 2 */- qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);- qh_flippedmerges(qh, qh->newfacet_list, &othermerge);- if (!qh->MERGEexact || zzval_(Ztotmerge)) {- zinc_(Zpremergetot);- qh->POSTmerging= False;- qh_getmergeset_initial(qh, qh->newfacet_list);- qh_all_merges(qh, othermerge, False);- }- qh_settempfree(qh, &qh->facet_mergeset);- qh_settempfree(qh, &qh->degen_mergeset);-} /* premerge */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="postmerge">-</a>-- qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )- post-merge nonconvex facets as defined by maxcentrum and maxangle- 'reason' is for reporting progress- if vneighbors,- calls qh_test_vneighbors at end of qh_all_merge- if firstmerge,- calls qh_reducevertices before qh_getmergeset-- returns:- if first call (qh.visible_list != qh.facet_list),- builds qh.facet_newlist, qh.newvertex_list- deleted facets added to qh.visible_list with facet->visible- qh.visible_list == qh.facet_list-- notes:--- design:- if first call- set qh.visible_list and qh.newfacet_list to qh.facet_list- add all facets to qh.newfacet_list- mark non-simplicial facets, facet->newmerge- set qh.newvertext_list to qh.vertex_list- add all vertices to qh.newvertex_list- if a pre-merge occured- set vertex->delridge {will retest the ridge}- if qh.MERGEexact- call qh_reducevertices()- if no pre-merging- merge flipped facets- determine non-convex facets- merge all non-convex facets-*/-void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,- boolT vneighbors) {- facetT *newfacet;- boolT othermerges= False;- vertexT *vertex;-- if (qh->REPORTfreq || qh->IStracing) {- qh_buildtracing(qh, NULL, NULL);- qh_printsummary(qh, qh->ferr);- if (qh->PRINTstatistics)- qh_printallstatistics(qh, qh->ferr, "reason");- qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",- reason, maxcentrum, maxangle);- }- trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge. test vneighbors? %d\n",- vneighbors));- qh->centrum_radius= maxcentrum;- qh->cos_max= maxangle;- qh->POSTmerging= True;- qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);- qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);- if (qh->visible_list != qh->facet_list) { /* first call */- qh->NEWfacets= True;- qh->visible_list= qh->newfacet_list= qh->facet_list;- FORALLnew_facets {- newfacet->newfacet= True;- if (!newfacet->simplicial)- newfacet->newmerge= True;- zinc_(Zpostfacets);- }- qh->newvertex_list= qh->vertex_list;- FORALLvertices- vertex->newlist= True;- if (qh->VERTEXneighbors) { /* a merge has occurred */- FORALLvertices- vertex->delridge= True; /* test for redundant, needed? */- if (qh->MERGEexact) {- if (qh->hull_dim <= qh_DIMreduceBuild)- qh_reducevertices(qh); /* was skipped during pre-merging */- }- }- if (!qh->PREmerge && !qh->MERGEexact)- qh_flippedmerges(qh, qh->newfacet_list, &othermerges);- }- qh_getmergeset_initial(qh, qh->newfacet_list);- qh_all_merges(qh, False, vneighbors);- qh_settempfree(qh, &qh->facet_mergeset);- qh_settempfree(qh, &qh->degen_mergeset);-} /* post_merge */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="all_merges">-</a>-- qh_all_merges(qh, othermerge, vneighbors )- merge all non-convex facets-- set othermerge if already merged facets (for qh_reducevertices)- if vneighbors- tests vertex neighbors for convexity at end- qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list- qh.degen_mergeset is defined- if qh.MERGEexact && !qh.POSTmerging,- does not merge coplanar facets-- returns:- deleted facets added to qh.visible_list with facet->visible- deleted vertices added qh.delvertex_list with vertex->delvertex-- notes:- unless !qh.MERGEindependent,- merges facets in independent sets- uses qh.newfacet_list as argument since merges call qh_removefacet()-- design:- while merges occur- for each merge in qh.facet_mergeset- unless one of the facets was already merged in this pass- merge the facets- test merged facets for additional merges- add merges to qh.facet_mergeset- if vertices record neighboring facets- rename redundant vertices- update qh.facet_mergeset- if vneighbors ??- tests vertex neighbors for convexity at end-*/-void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {- facetT *facet1, *facet2;- mergeT *merge;- boolT wasmerge= True, isreduce;- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */- vertexT *vertex;- mergeType mergetype;- int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;-- trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge facets beginning from f%d\n",- getid_(qh->newfacet_list)));- while (True) {- wasmerge= False;- while (qh_setsize(qh, qh->facet_mergeset)) {- while ((merge= (mergeT*)qh_setdellast(qh->facet_mergeset))) {- facet1= merge->facet1;- facet2= merge->facet2;- mergetype= merge->type;- qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp);- if (facet1->visible || facet2->visible) /*deleted facet*/- continue;- if ((facet1->newfacet && !facet1->tested)- || (facet2->newfacet && !facet2->tested)) {- if (qh->MERGEindependent && mergetype <= MRGanglecoplanar)- continue; /* perform independent sets of merges */- }- qh_merge_nonconvex(qh, facet1, facet2, mergetype);- numdegenredun += qh_merge_degenredundant(qh);- numnewmerges++;- wasmerge= True;- if (mergetype == MRGconcave)- numconcave++;- else /* MRGcoplanar or MRGanglecoplanar */- numcoplanar++;- } /* while setdellast */- if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild- && numnewmerges > qh_MAXnewmerges) {- numnewmerges= 0;- qh_reducevertices(qh); /* otherwise large post merges too slow */- }- qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */- } /* while mergeset */- if (qh->VERTEXneighbors) {- isreduce= False;- if (qh->hull_dim >=4 && qh->POSTmerging) {- FORALLvertices- vertex->delridge= True;- isreduce= True;- }- if ((wasmerge || othermerge) && (!qh->MERGEexact || qh->POSTmerging)- && qh->hull_dim <= qh_DIMreduceBuild) {- othermerge= False;- isreduce= True;- }- if (isreduce) {- if (qh_reducevertices(qh)) {- qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */- continue;- }- }- }- if (vneighbors && qh_test_vneighbors(qh /* qh->newfacet_list */))- continue;- break;- } /* while (True) */- if (qh->CHECKfrequently && !qh->MERGEexact) {- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);- /* qh_checkconnect(qh); [this is slow and it changes the facet order] */- qh->RANDOMdist= qh->old_randomdist;- }- trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",- numcoplanar, numconcave, numdegenredun));- if (qh->IStracing >= 4 && qh->num_facets < 50)- qh_printlists(qh);-} /* all_merges */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="appendmergeset">-</a>-- qh_appendmergeset(qh, facet, neighbor, mergetype, angle )- appends an entry to qh.facet_mergeset or qh.degen_mergeset-- angle ignored if NULL or !qh.ANGLEmerge-- returns:- merge appended to facet_mergeset or degen_mergeset- sets ->degenerate or ->redundant if degen_mergeset-- see:- qh_test_appendmerge()-- design:- allocate merge entry- if regular merge- append to qh.facet_mergeset- else if degenerate merge and qh.facet_mergeset is all degenerate- append to qh.degen_mergeset- else if degenerate merge- prepend to qh.degen_mergeset- else if redundant merge- append to qh.degen_mergeset-*/-void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {- mergeT *merge, *lastmerge;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */-- if (facet->redundant)- return;- if (facet->degenerate && mergetype == MRGdegen)- return;- qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);- merge->facet1= facet;- merge->facet2= neighbor;- merge->type= mergetype;- if (angle && qh->ANGLEmerge)- merge->angle= *angle;- if (mergetype < MRGdegen)- qh_setappend(qh, &(qh->facet_mergeset), merge);- else if (mergetype == MRGdegen) {- facet->degenerate= True;- if (!(lastmerge= (mergeT*)qh_setlast(qh->degen_mergeset))- || lastmerge->type == MRGdegen)- qh_setappend(qh, &(qh->degen_mergeset), merge);- else- qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge);- }else if (mergetype == MRGredundant) {- facet->redundant= True;- qh_setappend(qh, &(qh->degen_mergeset), merge);- }else /* mergetype == MRGmirror */ {- if (facet->redundant || neighbor->redundant) {- qh_fprintf(qh, qh->ferr, 6092, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",- facet->id, neighbor->id);- qh_errexit2(qh, qh_ERRqhull, facet, neighbor);- }- if (!qh_setequal(facet->vertices, neighbor->vertices)) {- qh_fprintf(qh, qh->ferr, 6093, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",- facet->id, neighbor->id);- qh_errexit2(qh, qh_ERRqhull, facet, neighbor);- }- facet->redundant= True;- neighbor->redundant= True;- qh_setappend(qh, &(qh->degen_mergeset), merge);- }-} /* appendmergeset */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="basevertices">-</a>-- qh_basevertices(qh, samecycle )- return temporary set of base vertices for samecycle- samecycle is first facet in the cycle- assumes apex is SETfirst_( samecycle->vertices )-- returns:- vertices(settemp)- all ->seen are cleared-- notes:- uses qh_vertex_visit;-- design:- for each facet in samecycle- for each unseen vertex in facet->vertices- append to result-*/-setT *qh_basevertices(qhT *qh, facetT *samecycle) {- facetT *same;- vertexT *apex, *vertex, **vertexp;- setT *vertices= qh_settemp(qh, qh->TEMPsize);-- apex= SETfirstt_(samecycle->vertices, vertexT);- apex->visitid= ++qh->vertex_visit;- FORALLsame_cycle_(samecycle) {- if (same->mergeridge)- continue;- FOREACHvertex_(same->vertices) {- if (vertex->visitid != qh->vertex_visit) {- qh_setappend(qh, &vertices, vertex);- vertex->visitid= qh->vertex_visit;- vertex->seen= False;- }- }- }- trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",- qh_setsize(qh, vertices)));- return vertices;-} /* basevertices */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="checkconnect">-</a>-- qh_checkconnect(qh)- check that new facets are connected- new facets are on qh.newfacet_list-- notes:- this is slow and it changes the order of the facets- uses qh.visit_id-- design:- move first new facet to end of qh.facet_list- for all newly appended facets- append unvisited neighbors to end of qh.facet_list- for all new facets- report error if unvisited-*/-void qh_checkconnect(qhT *qh /* qh->newfacet_list */) {- facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;-- facet= qh->newfacet_list;- qh_removefacet(qh, facet);- qh_appendfacet(qh, facet);- facet->visitid= ++qh->visit_id;- FORALLfacet_(facet) {- FOREACHneighbor_(facet) {- if (neighbor->visitid != qh->visit_id) {- qh_removefacet(qh, neighbor);- qh_appendfacet(qh, neighbor);- neighbor->visitid= qh->visit_id;- }- }- }- FORALLnew_facets {- if (newfacet->visitid == qh->visit_id)- break;- qh_fprintf(qh, qh->ferr, 6094, "qhull error: f%d is not attached to the new facets\n",- newfacet->id);- errfacet= newfacet;- }- if (errfacet)- qh_errexit(qh, qh_ERRqhull, errfacet, NULL);-} /* checkconnect */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="checkzero">-</a>-- qh_checkzero(qh, testall )- check that facets are clearly convex for qh.DISTround with qh.MERGEexact-- if testall,- test all facets for qh.MERGEexact post-merging- else- test qh.newfacet_list-- if qh.MERGEexact,- allows coplanar ridges- skips convexity test while qh.ZEROall_ok-- returns:- True if all facets !flipped, !dupridge, normal- if all horizon facets are simplicial- if all vertices are clearly below neighbor- if all opposite vertices of horizon are below- clears qh.ZEROall_ok if any problems or coplanar facets-- notes:- uses qh.vertex_visit- horizon facets may define multiple new facets-- design:- for all facets in qh.newfacet_list or qh.facet_list- check for flagged faults (flipped, etc.)- for all facets in qh.newfacet_list or qh.facet_list- for each neighbor of facet- skip horizon facets for qh.newfacet_list- test the opposite vertex- if qh.newfacet_list- test the other vertices in the facet's horizon facet-*/-boolT qh_checkzero(qhT *qh, boolT testall) {- facetT *facet, *neighbor, **neighborp;- facetT *horizon, *facetlist;- int neighbor_i;- vertexT *vertex, **vertexp;- realT dist;-- if (testall)- facetlist= qh->facet_list;- else {- facetlist= qh->newfacet_list;- FORALLfacet_(facetlist) {- horizon= SETfirstt_(facet->neighbors, facetT);- if (!horizon->simplicial)- goto LABELproblem;- if (facet->flipped || facet->dupridge || !facet->normal)- goto LABELproblem;- }- if (qh->MERGEexact && qh->ZEROall_ok) {- trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));- return True;- }- }- FORALLfacet_(facetlist) {- qh->vertex_visit++;- neighbor_i= 0;- horizon= NULL;- FOREACHneighbor_(facet) {- if (!neighbor_i && !testall) {- horizon= neighbor;- neighbor_i++;- continue; /* horizon facet tested in qh_findhorizon */- }- vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);- vertex->visitid= qh->vertex_visit;- zzinc_(Zdistzero);- qh_distplane(qh, vertex->point, neighbor, &dist);- if (dist >= -qh->DISTround) {- qh->ZEROall_ok= False;- if (!qh->MERGEexact || testall || dist > qh->DISTround)- goto LABELnonconvex;- }- }- if (!testall && horizon) {- FOREACHvertex_(horizon->vertices) {- if (vertex->visitid != qh->vertex_visit) {- zzinc_(Zdistzero);- qh_distplane(qh, vertex->point, facet, &dist);- if (dist >= -qh->DISTround) {- qh->ZEROall_ok= False;- if (!qh->MERGEexact || dist > qh->DISTround)- goto LABELnonconvex;- }- break;- }- }- }- }- trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,- (qh->MERGEexact && !testall) ?- "not concave, flipped, or duplicate ridged" : "clearly convex"));- return True;-- LABELproblem:- qh->ZEROall_ok= False;- trace2((qh, qh->ferr, 2013, "qh_checkzero: facet f%d needs pre-merging\n",- facet->id));- return False;-- LABELnonconvex:- trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex. v%d dist %.2g\n",- facet->id, neighbor->id, vertex->id, dist));- return False;-} /* checkzero */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="compareangle">-</a>-- qh_compareangle(angle1, angle2 )- used by qsort() to order merges by angle-*/-int qh_compareangle(const void *p1, const void *p2) {- const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);-- return((a->angle > b->angle) ? 1 : -1);-} /* compareangle */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="comparemerge">-</a>-- qh_comparemerge(merge1, merge2 )- used by qsort() to order merges-*/-int qh_comparemerge(const void *p1, const void *p2) {- const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);-- return(a->type - b->type);-} /* comparemerge */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="comparevisit">-</a>-- qh_comparevisit(vertex1, vertex2 )- used by qsort() to order vertices by their visitid-*/-int qh_comparevisit(const void *p1, const void *p2) {- const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);-- return(a->visitid - b->visitid);-} /* comparevisit */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="copynonconvex">-</a>-- qh_copynonconvex(qh, atridge )- set non-convex flag on other ridges (if any) between same neighbors-- notes:- may be faster if use smaller ridge set-- design:- for each ridge of atridge's top facet- if ridge shares the same neighbor- set nonconvex flag-*/-void qh_copynonconvex(qhT *qh, ridgeT *atridge) {- facetT *facet, *otherfacet;- ridgeT *ridge, **ridgep;-- facet= atridge->top;- otherfacet= atridge->bottom;- FOREACHridge_(facet->ridges) {- if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {- ridge->nonconvex= True;- trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",- atridge->id, ridge->id));- break;- }- }-} /* copynonconvex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="degen_redundant_facet">-</a>-- qh_degen_redundant_facet(qh, facet )- check facet for degen. or redundancy-- notes:- bumps vertex_visit- called if a facet was redundant but no longer is (qh_merge_degenredundant)- qh_appendmergeset() only appends first reference to facet (i.e., redundant)-- see:- qh_degen_redundant_neighbors()-- design:- test for redundant neighbor- test for degenerate facet-*/-void qh_degen_redundant_facet(qhT *qh, facetT *facet) {- vertexT *vertex, **vertexp;- facetT *neighbor, **neighborp;-- trace4((qh, qh->ferr, 4021, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",- facet->id));- FOREACHneighbor_(facet) {- qh->vertex_visit++;- FOREACHvertex_(neighbor->vertices)- vertex->visitid= qh->vertex_visit;- FOREACHvertex_(facet->vertices) {- if (vertex->visitid != qh->vertex_visit)- break;- }- if (!vertex) {- qh_appendmergeset(qh, facet, neighbor, MRGredundant, NULL);- trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d. merge\n", facet->id, neighbor->id));- return;- }- }- if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {- qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);- trace2((qh, qh->ferr, 2016, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));- }-} /* degen_redundant_facet */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="degen_redundant_neighbors">-</a>-- qh_degen_redundant_neighbors(qh, facet, delfacet, )- append degenerate and redundant neighbors to facet_mergeset- if delfacet,- only checks neighbors of both delfacet and facet- also checks current facet for degeneracy-- notes:- bumps vertex_visit- called for each qh_mergefacet() and qh_mergecycle()- merge and statistics occur in merge_nonconvex- qh_appendmergeset() only appends first reference to facet (i.e., redundant)- it appends redundant facets after degenerate ones-- a degenerate facet has fewer than hull_dim neighbors- a redundant facet's vertices is a subset of its neighbor's vertices- tests for redundant merges first (appendmergeset is nop for others)- in a merge, only needs to test neighbors of merged facet-- see:- qh_merge_degenredundant() and qh_degen_redundant_facet()-- design:- test for degenerate facet- test for redundant neighbor- test for degenerate neighbor-*/-void qh_degen_redundant_neighbors(qhT *qh, facetT *facet, facetT *delfacet) {- vertexT *vertex, **vertexp;- facetT *neighbor, **neighborp;- int size;-- trace4((qh, qh->ferr, 4022, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n",- facet->id, getid_(delfacet)));- if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {- qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);- trace2((qh, qh->ferr, 2017, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));- }- if (!delfacet)- delfacet= facet;- qh->vertex_visit++;- FOREACHvertex_(facet->vertices)- vertex->visitid= qh->vertex_visit;- FOREACHneighbor_(delfacet) {- /* uses early out instead of checking vertex count */- if (neighbor == facet)- continue;- FOREACHvertex_(neighbor->vertices) {- if (vertex->visitid != qh->vertex_visit)- break;- }- if (!vertex) {- qh_appendmergeset(qh, neighbor, facet, MRGredundant, NULL);- trace2((qh, qh->ferr, 2018, "qh_degen_redundant_neighbors: f%d is contained in f%d. merge\n", neighbor->id, facet->id));- }- }- FOREACHneighbor_(delfacet) { /* redundant merges occur first */- if (neighbor == facet)- continue;- if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {- qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, NULL);- trace2((qh, qh->ferr, 2019, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors. Neighbor of f%d.\n", neighbor->id, size, facet->id));- }- }-} /* degen_redundant_neighbors */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="find_newvertex">-</a>-- qh_find_newvertex(qh, oldvertex, vertices, ridges )- locate new vertex for renaming old vertex- vertices is a set of possible new vertices- vertices sorted by number of deleted ridges-- returns:- newvertex or NULL- each ridge includes both vertex and oldvertex- vertices sorted by number of deleted ridges-- notes:- modifies vertex->visitid- new vertex is in one of the ridges- renaming will not cause a duplicate ridge- renaming will minimize the number of deleted ridges- newvertex may not be adjacent in the dual (though unlikely)-- design:- for each vertex in vertices- set vertex->visitid to number of references in ridges- remove unvisited vertices- set qh.vertex_visit above all possible values- sort vertices by number of references in ridges- add each ridge to qh.hash_table- for each vertex in vertices- look for a vertex that would not cause a duplicate ridge after a rename-*/-vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {- vertexT *vertex, **vertexp;- setT *newridges;- ridgeT *ridge, **ridgep;- int size, hashsize;- int hash;--#ifndef qh_NOtrace- if (qh->IStracing >= 4) {- qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",- oldvertex->id);- FOREACHvertex_(vertices)- qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);- FOREACHridge_(ridges)- qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);- qh_fprintf(qh, qh->ferr, 8066, "\n");- }-#endif- FOREACHvertex_(vertices)- vertex->visitid= 0;- FOREACHridge_(ridges) {- FOREACHvertex_(ridge->vertices)- vertex->visitid++;- }- FOREACHvertex_(vertices) {- if (!vertex->visitid) {- qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));- vertexp--; /* repeat since deleted this vertex */- }- }- qh->vertex_visit += (unsigned int)qh_setsize(qh, ridges);- if (!qh_setsize(qh, vertices)) {- trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",- oldvertex->id));- return NULL;- }- qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),- sizeof(vertexT *), qh_comparevisit);- /* can now use qh->vertex_visit */- if (qh->PRINTstatistics) {- size= qh_setsize(qh, vertices);- zinc_(Zintersect);- zadd_(Zintersecttot, size);- zmax_(Zintersectmax, size);- }- hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));- FOREACHridge_(ridges)- qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);- FOREACHvertex_(vertices) {- newridges= qh_vertexridges(qh, vertex);- FOREACHridge_(newridges) {- if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {- zinc_(Zdupridge);- break;- }- }- qh_settempfree(qh, &newridges);- if (!ridge)- break; /* found a rename */- }- if (vertex) {- /* counted in qh_renamevertex */- trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",- vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));- }else {- zinc_(Zfindfail);- trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d(all duplicated ridges) during p%d\n",- oldvertex->id, qh->furthest_id));- }- qh_setfree(qh, &qh->hash_table);- return vertex;-} /* find_newvertex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="findbest_test">-</a>-- qh_findbest_test(qh, testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )- test neighbor of facet for qh_findbestneighbor()- if testcentrum,- tests centrum (assumes it is defined)- else- tests vertices-- returns:- if a better facet (i.e., vertices/centrum of facet closer to neighbor)- updates bestfacet, dist, mindist, and maxdist-*/-void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,- facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {- realT dist, mindist, maxdist;-- if (testcentrum) {- zzinc_(Zbestdist);- qh_distplane(qh, facet->center, neighbor, &dist);- dist *= qh->hull_dim; /* estimate furthest vertex */- if (dist < 0) {- maxdist= 0;- mindist= dist;- dist= -dist;- }else {- mindist= 0;- maxdist= dist;- }- }else- dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);- if (dist < *distp) {- *bestfacet= neighbor;- *mindistp= mindist;- *maxdistp= maxdist;- *distp= dist;- }-} /* findbest_test */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="findbestneighbor">-</a>-- qh_findbestneighbor(qh, facet, dist, mindist, maxdist )- finds best neighbor (least dist) of a facet for merging-- returns:- returns min and max distances and their max absolute value-- notes:- error if qh_ASvoronoi- avoids merging old into new- assumes ridge->nonconvex only set on one ridge between a pair of facets- could use an early out predicate but not worth it-- design:- if a large facet- will test centrum- else- will test vertices- if a large facet- test nonconvex neighbors for best merge- else- test all neighbors for the best merge- if testing centrum- get distance information-*/-facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {- facetT *neighbor, **neighborp, *bestfacet= NULL;- ridgeT *ridge, **ridgep;- boolT nonconvex= True, testcentrum= False;- int size= qh_setsize(qh, facet->vertices);-- if(qh->CENTERtype==qh_ASvoronoi){- qh_fprintf(qh, qh->ferr, 6272, "qhull error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- *distp= REALmax;- if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {- testcentrum= True;- zinc_(Zbestcentrum);- if (!facet->center)- facet->center= qh_getcentrum(qh, facet);- }- if (size > qh->hull_dim + qh_BESTnonconvex) {- FOREACHridge_(facet->ridges) {- if (ridge->nonconvex) {- neighbor= otherfacet_(ridge, facet);- qh_findbest_test(qh, testcentrum, facet, neighbor,- &bestfacet, distp, mindistp, maxdistp);- }- }- }- if (!bestfacet) {- nonconvex= False;- FOREACHneighbor_(facet)- qh_findbest_test(qh, testcentrum, facet, neighbor,- &bestfacet, distp, mindistp, maxdistp);- }- if (!bestfacet) {- qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- if (testcentrum)- qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);- trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",- bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));- return(bestfacet);-} /* findbestneighbor */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="flippedmerges">-</a>-- qh_flippedmerges(qh, facetlist, wasmerge )- merge flipped facets into best neighbor- assumes qh.facet_mergeset at top of temporary stack-- returns:- no flipped facets on facetlist- sets wasmerge if merge occurred- degen/redundant merges passed through-- notes:- othermerges not needed since qh.facet_mergeset is empty before & after- keep it in case of change-- design:- append flipped facets to qh.facetmergeset- for each flipped merge- find best neighbor- merge facet into neighbor- merge degenerate and redundant facets- remove flipped merges from qh.facet_mergeset-*/-void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {- facetT *facet, *neighbor, *facet1;- realT dist, mindist, maxdist;- mergeT *merge, **mergep;- setT *othermerges;- int nummerge=0;-- trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));- FORALLfacet_(facetlist) {- if (facet->flipped && !facet->visible)- qh_appendmergeset(qh, facet, facet, MRGflip, NULL);- }- othermerges= qh_settemppop(qh); /* was facet_mergeset */- qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);- qh_settemppush(qh, othermerges);- FOREACHmerge_(othermerges) {- facet1= merge->facet1;- if (merge->type != MRGflip || facet1->visible)- continue;- if (qh->TRACEmerge-1 == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);- trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",- facet1->id, neighbor->id, dist, qh->furthest_id));- qh_mergefacet(qh, facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);- nummerge++;- if (qh->PRINTstatistics) {- zinc_(Zflipped);- wadd_(Wflippedtot, dist);- wmax_(Wflippedmax, dist);- }- qh_merge_degenredundant(qh);- }- FOREACHmerge_(othermerges) {- if (merge->facet1->visible || merge->facet2->visible)- qh_memfree(qh, merge, (int)sizeof(mergeT));- else- qh_setappend(qh, &qh->facet_mergeset, merge);- }- qh_settempfree(qh, &othermerges);- if (nummerge)- *wasmerge= True;- trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));-} /* flippedmerges */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="forcedmerges">-</a>-- qh_forcedmerges(qh, wasmerge )- merge duplicated ridges-- returns:- removes all duplicate ridges on facet_mergeset- wasmerge set if merge- qh.facet_mergeset may include non-forced merges(none for now)- qh.degen_mergeset includes degen/redun merges-- notes:- duplicate ridges occur when the horizon is pinched,- i.e. a subridge occurs in more than two horizon ridges.- could rename vertices that pinch the horizon- assumes qh_merge_degenredundant() has not be called- othermerges isn't needed since facet_mergeset is empty afterwards- keep it in case of change-- design:- for each duplicate ridge- find current facets by chasing f.replace links- check for wide merge due to duplicate ridge- determine best direction for facet- merge one facet into the other- remove duplicate ridges from qh.facet_mergeset-*/-void qh_forcedmerges(qhT *qh, boolT *wasmerge) {- facetT *facet1, *facet2;- mergeT *merge, **mergep;- realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;- setT *othermerges;- int nummerge=0, numflip=0;-- if (qh->TRACEmerge-1 == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- trace4((qh, qh->ferr, 4025, "qh_forcedmerges: begin\n"));- othermerges= qh_settemppop(qh); /* was facet_mergeset */- qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);- qh_settemppush(qh, othermerges);- FOREACHmerge_(othermerges) {- if (merge->type != MRGridge)- continue;- if (qh->TRACEmerge-1 == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- facet1= merge->facet1;- facet2= merge->facet2;- while (facet1->visible) /* must exist, no qh_merge_degenredunant */- facet1= facet1->f.replace; /* previously merged facet */- while (facet2->visible)- facet2= facet2->f.replace; /* previously merged facet */- if (facet1 == facet2)- continue;- if (!qh_setin(facet2->neighbors, facet1)) {- qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",- merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);- qh_errexit2(qh, qh_ERRqhull, facet1, facet2);- }- dist1= qh_getdistance(qh, facet1, facet2, &mindist1, &maxdist1);- dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);- qh_check_dupridge(qh, facet1, dist1, facet2, dist2);- if (dist1 < dist2)- qh_mergefacet(qh, facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);- else {- qh_mergefacet(qh, facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);- dist1= dist2;- facet1= facet2;- }- if (facet1->flipped) {- zinc_(Zmergeflipdup);- numflip++;- }else- nummerge++;- if (qh->PRINTstatistics) {- zinc_(Zduplicate);- wadd_(Wduplicatetot, dist1);- wmax_(Wduplicatemax, dist1);- }- }- FOREACHmerge_(othermerges) {- if (merge->type == MRGridge)- qh_memfree(qh, merge, (int)sizeof(mergeT));- else- qh_setappend(qh, &qh->facet_mergeset, merge);- }- qh_settempfree(qh, &othermerges);- if (nummerge)- *wasmerge= True;- trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n",- nummerge, numflip));-} /* forcedmerges */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="getmergeset">-</a>-- qh_getmergeset(qh, facetlist )- determines nonconvex facets on facetlist- tests !tested ridges and nonconvex ridges of !tested facets-- returns:- returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged- all ridges tested-- notes:- assumes no nonconvex ridges with both facets tested- uses facet->tested/ridge->tested to prevent duplicate tests- can not limit tests to modified ridges since the centrum changed- uses qh.visit_id-- see:- qh_getmergeset_initial()-- design:- for each facet on facetlist- for each ridge of facet- if untested ridge- test ridge for convexity- if non-convex- append ridge to qh.facet_mergeset- sort qh.facet_mergeset by angle-*/-void qh_getmergeset(qhT *qh, facetT *facetlist) {- facetT *facet, *neighbor, **neighborp;- ridgeT *ridge, **ridgep;- int nummerges;-- nummerges= qh_setsize(qh, qh->facet_mergeset);- trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));- qh->visit_id++;- FORALLfacet_(facetlist) {- if (facet->tested)- continue;- facet->visitid= qh->visit_id;- facet->tested= True; /* must be non-simplicial due to merge */- FOREACHneighbor_(facet)- neighbor->seen= False;- FOREACHridge_(facet->ridges) {- if (ridge->tested && !ridge->nonconvex)- continue;- /* if tested & nonconvex, need to append merge */- neighbor= otherfacet_(ridge, facet);- if (neighbor->seen) {- ridge->tested= True;- ridge->nonconvex= False;- }else if (neighbor->visitid != qh->visit_id) {- ridge->tested= True;- ridge->nonconvex= False;- neighbor->seen= True; /* only one ridge is marked nonconvex */- if (qh_test_appendmerge(qh, facet, neighbor))- ridge->nonconvex= True;- }- }- }- nummerges= qh_setsize(qh, qh->facet_mergeset);- if (qh->ANGLEmerge)- qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);- else- qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);- if (qh->POSTmerging) {- zadd_(Zmergesettot2, nummerges);- }else {- zadd_(Zmergesettot, nummerges);- zmax_(Zmergesetmax, nummerges);- }- trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));-} /* getmergeset */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="getmergeset_initial">-</a>-- qh_getmergeset_initial(qh, facetlist )- determine initial qh.facet_mergeset for facets- tests all facet/neighbor pairs on facetlist-- returns:- sorted qh.facet_mergeset with nonconvex ridges- sets facet->tested, ridge->tested, and ridge->nonconvex-- notes:- uses visit_id, assumes ridge->nonconvex is False-- see:- qh_getmergeset()-- design:- for each facet on facetlist- for each untested neighbor of facet- test facet and neighbor for convexity- if non-convex- append merge to qh.facet_mergeset- mark one of the ridges as nonconvex- sort qh.facet_mergeset by angle-*/-void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {- facetT *facet, *neighbor, **neighborp;- ridgeT *ridge, **ridgep;- int nummerges;-- qh->visit_id++;- FORALLfacet_(facetlist) {- facet->visitid= qh->visit_id;- facet->tested= True;- FOREACHneighbor_(facet) {- if (neighbor->visitid != qh->visit_id) {- if (qh_test_appendmerge(qh, facet, neighbor)) {- FOREACHridge_(neighbor->ridges) {- if (facet == otherfacet_(ridge, neighbor)) {- ridge->nonconvex= True;- break; /* only one ridge is marked nonconvex */- }- }- }- }- }- FOREACHridge_(facet->ridges)- ridge->tested= True;- }- nummerges= qh_setsize(qh, qh->facet_mergeset);- if (qh->ANGLEmerge)- qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);- else- qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);- if (qh->POSTmerging) {- zadd_(Zmergeinittot2, nummerges);- }else {- zadd_(Zmergeinittot, nummerges);- zmax_(Zmergeinitmax, nummerges);- }- trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));-} /* getmergeset_initial */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="hashridge">-</a>-- qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )- add ridge to hashtable without oldvertex-- notes:- assumes hashtable is large enough-- design:- determine hash value for ridge without oldvertex- find next empty slot for ridge-*/-void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {- int hash;- ridgeT *ridgeA;-- hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);- while (True) {- if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {- SETelem_(hashtable, hash)= ridge;- break;- }else if (ridgeA == ridge)- break;- if (++hash == hashsize)- hash= 0;- }-} /* hashridge */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="hashridge_find">-</a>-- qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )- returns matching ridge without oldvertex in hashtable- for ridge without vertex- if oldvertex is NULL- matches with any one skip-- returns:- matching ridge or NULL- if no match,- if ridge already in table- hashslot= -1- else- hashslot= next NULL index-- notes:- assumes hashtable is large enough- can't match ridge to itself-- design:- get hash value for ridge without vertex- for each hashslot- return match if ridge matches ridgeA without oldvertex-*/-ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,- vertexT *vertex, vertexT *oldvertex, int *hashslot) {- int hash;- ridgeT *ridgeA;-- *hashslot= 0;- zinc_(Zhashridge);- hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);- while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {- if (ridgeA == ridge)- *hashslot= -1;- else {- zinc_(Zhashridgetest);- if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))- return ridgeA;- }- if (++hash == hashsize)- hash= 0;- }- if (!*hashslot)- *hashslot= hash;- return NULL;-} /* hashridge_find */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="makeridges">-</a>-- qh_makeridges(qh, facet )- creates explicit ridges between simplicial facets-- returns:- facet with ridges and without qh_MERGEridge- ->simplicial is False-- notes:- allows qh_MERGEridge flag- uses existing ridges- duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)-- see:- qh_mergecycle_ridges()-- design:- look for qh_MERGEridge neighbors- mark neighbors that already have ridges- for each unprocessed neighbor of facet- create a ridge for neighbor and facet- if any qh_MERGEridge neighbors- delete qh_MERGEridge flags (already handled by qh_mark_dupridges)-*/-void qh_makeridges(qhT *qh, facetT *facet) {- facetT *neighbor, **neighborp;- ridgeT *ridge, **ridgep;- int neighbor_i, neighbor_n;- boolT toporient, mergeridge= False;-- if (!facet->simplicial)- return;- trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));- facet->simplicial= False;- FOREACHneighbor_(facet) {- if (neighbor == qh_MERGEridge)- mergeridge= True;- else- neighbor->seen= False;- }- FOREACHridge_(facet->ridges)- otherfacet_(ridge, facet)->seen= True;- FOREACHneighbor_i_(qh, facet) {- if (neighbor == qh_MERGEridge)- continue; /* fixed by qh_mark_dupridges */- else if (!neighbor->seen) { /* no current ridges */- ridge= qh_newridge(qh);- ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,- neighbor_i, 0);- toporient= facet->toporient ^ (neighbor_i & 0x1);- if (toporient) {- ridge->top= facet;- ridge->bottom= neighbor;- }else {- ridge->top= neighbor;- ridge->bottom= facet;- }-#if 0 /* this also works */- flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);- if (facet->toporient ^ (skip1 & 0x1) ^ flip) {- ridge->top= neighbor;- ridge->bottom= facet;- }else {- ridge->top= facet;- ridge->bottom= neighbor;- }-#endif- qh_setappend(qh, &(facet->ridges), ridge);- qh_setappend(qh, &(neighbor->ridges), ridge);- }- }- if (mergeridge) {- while (qh_setdel(facet->neighbors, qh_MERGEridge))- ; /* delete each one */- }-} /* makeridges */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mark_dupridges">-</a>-- qh_mark_dupridges(qh, facetlist )- add duplicated ridges to qh.facet_mergeset- facet->dupridge is true-- returns:- duplicate ridges on qh.facet_mergeset- ->mergeridge/->mergeridge2 set- duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge- no MERGEridges in neighbor sets-- notes:- duplicate ridges occur when the horizon is pinched,- i.e. a subridge occurs in more than two horizon ridges.- could rename vertices that pinch the horizon (thus removing subridge)- uses qh.visit_id-- design:- for all facets on facetlist- if facet contains a duplicate ridge- for each neighbor of facet- if neighbor marked qh_MERGEridge (one side of the merge)- set facet->mergeridge- else- if neighbor contains a duplicate ridge- and the back link is qh_MERGEridge- append duplicate ridge to qh.facet_mergeset- for each duplicate ridge- make ridge sets in preparation for merging- remove qh_MERGEridge from neighbor set- for each duplicate ridge- restore the missing neighbor from the neighbor set that was qh_MERGEridge- add the missing ridge for this neighbor-*/-void qh_mark_dupridges(qhT *qh, facetT *facetlist) {- facetT *facet, *neighbor, **neighborp;- int nummerge=0;- mergeT *merge, **mergep;--- trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify duplicate ridges\n"));- FORALLfacet_(facetlist) {- if (facet->dupridge) {- FOREACHneighbor_(facet) {- if (neighbor == qh_MERGEridge) {- facet->mergeridge= True;- continue;- }- if (neighbor->dupridge- && !qh_setin(neighbor->neighbors, facet)) { /* qh_MERGEridge */- qh_appendmergeset(qh, facet, neighbor, MRGridge, NULL);- facet->mergeridge2= True;- facet->mergeridge= True;- nummerge++;- }- }- }- }- if (!nummerge)- return;- FORALLfacet_(facetlist) { /* gets rid of qh_MERGEridge */- if (facet->mergeridge && !facet->mergeridge2)- qh_makeridges(qh, facet);- }- FOREACHmerge_(qh->facet_mergeset) { /* restore the missing neighbors */- if (merge->type == MRGridge) {- qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);- qh_makeridges(qh, merge->facet1); /* and the missing ridges */- }- }- trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges\n",- nummerge));-} /* mark_dupridges */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="maydropneighbor">-</a>-- qh_maydropneighbor(qh, facet )- drop neighbor relationship if no ridge between facet and neighbor-- returns:- neighbor sets updated- appends degenerate facets to qh.facet_mergeset-- notes:- won't cause redundant facets since vertex inclusion is the same- may drop vertex and neighbor if no ridge- uses qh.visit_id-- design:- visit all neighbors with ridges- for each unvisited neighbor of facet- delete neighbor and facet from the neighbor sets- if neighbor becomes degenerate- append neighbor to qh.degen_mergeset- if facet is degenerate- append facet to qh.degen_mergeset-*/-void qh_maydropneighbor(qhT *qh, facetT *facet) {- ridgeT *ridge, **ridgep;- realT angledegen= qh_ANGLEdegen;- facetT *neighbor, **neighborp;-- qh->visit_id++;- trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",- facet->id));- FOREACHridge_(facet->ridges) {- ridge->top->visitid= qh->visit_id;- ridge->bottom->visitid= qh->visit_id;- }- FOREACHneighbor_(facet) {- if (neighbor->visitid != qh->visit_id) {- trace0((qh, qh->ferr, 17, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",- facet->id, neighbor->id, qh->furthest_id));- zinc_(Zdropneighbor);- qh_setdel(facet->neighbors, neighbor);- neighborp--; /* repeat, deleted a neighbor */- qh_setdel(neighbor->neighbors, facet);- if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {- zinc_(Zdropdegen);- qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, &angledegen);- trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));- }- }- }- if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {- zinc_(Zdropdegen);- qh_appendmergeset(qh, facet, facet, MRGdegen, &angledegen);- trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));- }-} /* maydropneighbor */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="merge_degenredundant">-</a>-- qh_merge_degenredundant(qh)- merge all degenerate and redundant facets- qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()-- returns:- number of merges performed- resets facet->degenerate/redundant- if deleted (visible) facet has no neighbors- sets ->f.replace to NULL-- notes:- redundant merges happen before degenerate ones- merging and renaming vertices can result in degen/redundant facets-- design:- for each merge on qh.degen_mergeset- if redundant merge- if non-redundant facet merged into redundant facet- recheck facet for redundancy- else- merge redundant facet into other facet-*/-int qh_merge_degenredundant(qhT *qh) {- int size;- mergeT *merge;- facetT *bestneighbor, *facet1, *facet2;- realT dist, mindist, maxdist;- vertexT *vertex, **vertexp;- int nummerges= 0;- mergeType mergetype;-- while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {- facet1= merge->facet1;- facet2= merge->facet2;- mergetype= merge->type;- qh_memfree(qh, merge, (int)sizeof(mergeT));- if (facet1->visible)- continue;- facet1->degenerate= False;- facet1->redundant= False;- if (qh->TRACEmerge-1 == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- if (mergetype == MRGredundant) {- zinc_(Zneighbor);- while (facet2->visible) {- if (!facet2->f.replace) {- qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",- facet1->id, facet2->id);- qh_errexit2(qh, qh_ERRqhull, facet1, facet2);- }- facet2= facet2->f.replace;- }- if (facet1 == facet2) {- qh_degen_redundant_facet(qh, facet1); /* in case of others */- continue;- }- trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",- facet1->id, facet2->id));- qh_mergefacet(qh, facet1, facet2, NULL, NULL, !qh_MERGEapex);- /* merge distance is already accounted for */- nummerges++;- }else { /* mergetype == MRGdegen, other merges may have fixed */- if (!(size= qh_setsize(qh, facet1->neighbors))) {- zinc_(Zdelfacetdup);- trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors. Deleted\n", facet1->id));- qh_willdelete(qh, facet1, NULL);- FOREACHvertex_(facet1->vertices) {- qh_setdel(vertex->neighbors, facet1);- if (!SETfirst_(vertex->neighbors)) {- zinc_(Zdegenvertex);- trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",- vertex->id, facet1->id));- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);- }- }- nummerges++;- }else if (size < qh->hull_dim) {- bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);- trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",- facet1->id, size, bestneighbor->id, dist));- qh_mergefacet(qh, facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);- nummerges++;- if (qh->PRINTstatistics) {- zinc_(Zdegen);- wadd_(Wdegentot, dist);- wmax_(Wdegenmax, dist);- }- } /* else, another merge fixed the degeneracy and redundancy tested */- }- }- return nummerges;-} /* merge_degenredundant */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="merge_nonconvex">-</a>-- qh_merge_nonconvex(qh, facet1, facet2, mergetype )- remove non-convex ridge between facet1 into facet2- mergetype gives why the facet's are non-convex-- returns:- merges one of the facets into the best neighbor-- design:- if one of the facets is a new facet- prefer merging new facet into old facet- find best neighbors for both facets- merge the nearest facet into its best neighbor- update the statistics-*/-void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {- facetT *bestfacet, *bestneighbor, *neighbor;- realT dist, dist2, mindist, mindist2, maxdist, maxdist2;-- if (qh->TRACEmerge-1 == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",- zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));- /* concave or coplanar */- if (!facet1->newfacet) {- bestfacet= facet2; /* avoid merging old facet if new is ok */- facet2= facet1;- facet1= bestfacet;- }else- bestfacet= facet1;- bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);- neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);- if (dist < dist2) {- qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);- }else if (qh->AVOIDold && !facet2->newfacet- && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)- || dist * 1.5 < dist2)) {- zinc_(Zavoidold);- wadd_(Wavoidoldtot, dist);- wmax_(Wavoidoldmax, dist);- trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g. Use f%d dist %2.2g instead\n",- facet2->id, dist2, facet1->id, dist2));- qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);- }else {- qh_mergefacet(qh, facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);- dist= dist2;- }- if (qh->PRINTstatistics) {- if (mergetype == MRGanglecoplanar) {- zinc_(Zacoplanar);- wadd_(Wacoplanartot, dist);- wmax_(Wacoplanarmax, dist);- }else if (mergetype == MRGconcave) {- zinc_(Zconcave);- wadd_(Wconcavetot, dist);- wmax_(Wconcavemax, dist);- }else { /* MRGcoplanar */- zinc_(Zcoplanar);- wadd_(Wcoplanartot, dist);- wmax_(Wcoplanarmax, dist);- }- }-} /* merge_nonconvex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle">-</a>-- qh_mergecycle(qh, samecycle, newfacet )- merge a cycle of facets starting at samecycle into a newfacet- newfacet is a horizon facet with ->normal- samecycle facets are simplicial from an apex-- returns:- initializes vertex neighbors on first merge- samecycle deleted (placed on qh.visible_list)- newfacet at end of qh.facet_list- deleted vertices on qh.del_vertices-- see:- qh_mergefacet()- called by qh_mergecycle_all() for multiple, same cycle facets-- design:- make vertex neighbors if necessary- make ridges for newfacet- merge neighbor sets of samecycle into newfacet- merge ridges of samecycle into newfacet- merge vertex neighbors of samecycle into newfacet- make apex of samecycle the apex of newfacet- if newfacet wasn't a new facet- add its vertices to qh.newvertex_list- delete samecycle facets a make newfacet a newfacet-*/-void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {- int traceonce= False, tracerestore= 0;- vertexT *apex;-#ifndef qh_NOtrace- facetT *same;-#endif-- if (newfacet->tricoplanar) {- if (!qh->TRInormals) {- qh_fprintf(qh, qh->ferr, 6224, "Qhull internal error (qh_mergecycle): does not work for tricoplanar facets. Use option 'Q11'\n");- qh_errexit(qh, qh_ERRqhull, newfacet, NULL);- }- newfacet->tricoplanar= False;- newfacet->keepcentrum= False;- }- if (!qh->VERTEXneighbors)- qh_vertexneighbors(qh);- zzinc_(Ztotmerge);- if (qh->REPORTfreq2 && qh->POSTmerging) {- if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)- qh_tracemerging(qh);- }-#ifndef qh_NOtrace- if (qh->TRACEmerge == zzval_(Ztotmerge))- qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;- trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",- zzval_(Ztotmerge), samecycle->id, newfacet->id));- if (newfacet == qh->tracefacet) {- tracerestore= qh->IStracing;- qh->IStracing= 4;- qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",- zzval_(Ztotmerge), samecycle->id, newfacet->id, qh->furthest_id);- traceonce= True;- }- if (qh->IStracing >=4) {- qh_fprintf(qh, qh->ferr, 8069, " same cycle:");- FORALLsame_cycle_(samecycle)- qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);- qh_fprintf(qh, qh->ferr, 8071, "\n");- }- if (qh->IStracing >=4)- qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);-#endif /* !qh_NOtrace */- apex= SETfirstt_(samecycle->vertices, vertexT);- qh_makeridges(qh, newfacet);- qh_mergecycle_neighbors(qh, samecycle, newfacet);- qh_mergecycle_ridges(qh, samecycle, newfacet);- qh_mergecycle_vneighbors(qh, samecycle, newfacet);- if (SETfirstt_(newfacet->vertices, vertexT) != apex)- qh_setaddnth(qh, &newfacet->vertices, 0, apex); /* apex has last id */- if (!newfacet->newfacet)- qh_newvertices(qh, newfacet->vertices);- qh_mergecycle_facets(qh, samecycle, newfacet);- qh_tracemerge(qh, samecycle, newfacet);- /* check for degen_redundant_neighbors after qh_forcedmerges() */- if (traceonce) {- qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");- qh->IStracing= tracerestore;- }-} /* mergecycle */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle_all">-</a>-- qh_mergecycle_all(qh, facetlist, wasmerge )- merge all samecycles of coplanar facets into horizon- don't merge facets with ->mergeridge (these already have ->normal)- all facets are simplicial from apex- all facet->cycledone == False-- returns:- all newfacets merged into coplanar horizon facets- deleted vertices on qh.del_vertices- sets wasmerge if any merge-- see:- calls qh_mergecycle for multiple, same cycle facets-- design:- for each facet on facetlist- skip facets with duplicate ridges and normals- check that facet is in a samecycle (->mergehorizon)- if facet only member of samecycle- sets vertex->delridge for all vertices except apex- merge facet into horizon- else- mark all facets in samecycle- remove facets with duplicate ridges from samecycle- merge samecycle into horizon (deletes facets from facetlist)-*/-void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {- facetT *facet, *same, *prev, *horizon;- facetT *samecycle= NULL, *nextfacet, *nextsame;- vertexT *apex, *vertex, **vertexp;- int cycles=0, total=0, facets, nummerge;-- trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: begin\n"));- for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {- if (facet->normal)- continue;- if (!facet->mergehorizon) {- qh_fprintf(qh, qh->ferr, 6225, "Qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- horizon= SETfirstt_(facet->neighbors, facetT);- if (facet->f.samecycle == facet) {- zinc_(Zonehorizon);- /* merge distance done in qh_findhorizon */- apex= SETfirstt_(facet->vertices, vertexT);- FOREACHvertex_(facet->vertices) {- if (vertex != apex)- vertex->delridge= True;- }- horizon->f.newcycle= NULL;- qh_mergefacet(qh, facet, horizon, NULL, NULL, qh_MERGEapex);- }else {- samecycle= facet;- facets= 0;- prev= facet;- for (same= facet->f.samecycle; same; /* FORALLsame_cycle_(facet) */- same= (same == facet ? NULL :nextsame)) { /* ends at facet */- nextsame= same->f.samecycle;- if (same->cycledone || same->visible)- qh_infiniteloop(qh, same);- same->cycledone= True;- if (same->normal) {- prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */- same->f.samecycle= NULL;- }else {- prev= same;- facets++;- }- }- while (nextfacet && nextfacet->cycledone) /* will delete samecycle */- nextfacet= nextfacet->next;- horizon->f.newcycle= NULL;- qh_mergecycle(qh, samecycle, horizon);- nummerge= horizon->nummerge + facets;- if (nummerge > qh_MAXnummerge)- horizon->nummerge= qh_MAXnummerge;- else- horizon->nummerge= (short unsigned int)nummerge;- zzinc_(Zcyclehorizon);- total += facets;- zzadd_(Zcyclefacettot, facets);- zmax_(Zcyclefacetmax, facets);- }- cycles++;- }- if (cycles)- *wasmerge= True;- trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));-} /* mergecycle_all */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle_facets">-</a>-- qh_mergecycle_facets(qh, samecycle, newfacet )- finish merge of samecycle into newfacet-- returns:- samecycle prepended to visible_list for later deletion and partitioning- each facet->f.replace == newfacet-- newfacet moved to end of qh.facet_list- makes newfacet a newfacet (get's facet1->id if it was old)- sets newfacet->newmerge- clears newfacet->center (unless merging into a large facet)- clears newfacet->tested and ridge->tested for facet1-- adds neighboring facets to facet_mergeset if redundant or degenerate-- design:- make newfacet a new facet and set its flags- move samecycle facets to qh.visible_list for later deletion- unless newfacet is large- remove its centrum-*/-void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {- facetT *same, *next;-- trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));- qh_removefacet(qh, newfacet); /* append as a newfacet to end of qh->facet_list */- qh_appendfacet(qh, newfacet);- newfacet->newfacet= True;- newfacet->simplicial= False;- newfacet->newmerge= True;-- for (same= samecycle->f.samecycle; same; same= (same == samecycle ? NULL : next)) {- next= same->f.samecycle; /* reused by willdelete */- qh_willdelete(qh, same, newfacet);- }- if (newfacet->center- && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {- qh_memfree(qh, newfacet->center, qh->normal_size);- newfacet->center= NULL;- }- trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",- samecycle->id, newfacet->id));-} /* mergecycle_facets */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle_neighbors">-</a>-- qh_mergecycle_neighbors(qh, samecycle, newfacet )- add neighbors for samecycle facets to newfacet-- returns:- newfacet with updated neighbors and vice-versa- newfacet has ridges- all neighbors of newfacet marked with qh.visit_id- samecycle facets marked with qh.visit_id-1- ridges updated for simplicial neighbors of samecycle with a ridge-- notes:- assumes newfacet not in samecycle- usually, samecycle facets are new, simplicial facets without internal ridges- not so if horizon facet is coplanar to two different samecycles-- see:- qh_mergeneighbors()-- design:- check samecycle- delete neighbors from newfacet that are also in samecycle- for each neighbor of a facet in samecycle- if neighbor is simplicial- if first visit- move the neighbor relation to newfacet- update facet links for its ridges- else- make ridges for neighbor- remove samecycle reference- else- update neighbor sets-*/-void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {- facetT *same, *neighbor, **neighborp;- int delneighbors= 0, newneighbors= 0;- unsigned int samevisitid;- ridgeT *ridge, **ridgep;-- samevisitid= ++qh->visit_id;- FORALLsame_cycle_(samecycle) {- if (same->visitid == samevisitid || same->visible)- qh_infiniteloop(qh, samecycle);- same->visitid= samevisitid;- }- newfacet->visitid= ++qh->visit_id;- trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));- FOREACHneighbor_(newfacet) {- if (neighbor->visitid == samevisitid) {- SETref_(neighbor)= NULL; /* samecycle neighbors deleted */- delneighbors++;- }else- neighbor->visitid= qh->visit_id;- }- qh_setcompact(qh, newfacet->neighbors);-- trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));- FORALLsame_cycle_(samecycle) {- FOREACHneighbor_(same) {- if (neighbor->visitid == samevisitid)- continue;- if (neighbor->simplicial) {- if (neighbor->visitid != qh->visit_id) {- qh_setappend(qh, &newfacet->neighbors, neighbor);- qh_setreplace(qh, neighbor->neighbors, same, newfacet);- newneighbors++;- neighbor->visitid= qh->visit_id;- FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */- if (ridge->top == same) {- ridge->top= newfacet;- break;- }else if (ridge->bottom == same) {- ridge->bottom= newfacet;- break;- }- }- }else {- qh_makeridges(qh, neighbor);- qh_setdel(neighbor->neighbors, same);- /* same can't be horizon facet for neighbor */- }- }else { /* non-simplicial neighbor */- qh_setdel(neighbor->neighbors, same);- if (neighbor->visitid != qh->visit_id) {- qh_setappend(qh, &neighbor->neighbors, newfacet);- qh_setappend(qh, &newfacet->neighbors, neighbor);- neighbor->visitid= qh->visit_id;- newneighbors++;- }- }- }- }- trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",- delneighbors, newneighbors));-} /* mergecycle_neighbors */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle_ridges">-</a>-- qh_mergecycle_ridges(qh, samecycle, newfacet )- add ridges/neighbors for facets in samecycle to newfacet- all new/old neighbors of newfacet marked with qh.visit_id- facets in samecycle marked with qh.visit_id-1- newfacet marked with qh.visit_id-- returns:- newfacet has merged ridges-- notes:- ridge already updated for simplicial neighbors of samecycle with a ridge-- see:- qh_mergeridges()- qh_makeridges()-- design:- remove ridges between newfacet and samecycle- for each facet in samecycle- for each ridge in facet- update facet pointers in ridge- skip ridges processed in qh_mergecycle_neighors- free ridges between newfacet and samecycle- free ridges between facets of samecycle (on 2nd visit)- append remaining ridges to newfacet- if simpilicial facet- for each neighbor of facet- if simplicial facet- and not samecycle facet or newfacet- make ridge between neighbor and newfacet-*/-void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {- facetT *same, *neighbor= NULL;- int numold=0, numnew=0;- int neighbor_i, neighbor_n;- unsigned int samevisitid;- ridgeT *ridge, **ridgep;- boolT toporient;- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */-- trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));- samevisitid= qh->visit_id -1;- FOREACHridge_(newfacet->ridges) {- neighbor= otherfacet_(ridge, newfacet);- if (neighbor->visitid == samevisitid)- SETref_(ridge)= NULL; /* ridge free'd below */- }- qh_setcompact(qh, newfacet->ridges);-- trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));- FORALLsame_cycle_(samecycle) {- FOREACHridge_(same->ridges) {- if (ridge->top == same) {- ridge->top= newfacet;- neighbor= ridge->bottom;- }else if (ridge->bottom == same) {- ridge->bottom= newfacet;- neighbor= ridge->top;- }else if (ridge->top == newfacet || ridge->bottom == newfacet) {- qh_setappend(qh, &newfacet->ridges, ridge);- numold++; /* already set by qh_mergecycle_neighbors */- continue;- }else {- qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);- qh_errexit(qh, qh_ERRqhull, NULL, ridge);- }- if (neighbor == newfacet) {- qh_setfree(qh, &(ridge->vertices));- qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);- numold++;- }else if (neighbor->visitid == samevisitid) {- qh_setdel(neighbor->ridges, ridge);- qh_setfree(qh, &(ridge->vertices));- qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);- numold++;- }else {- qh_setappend(qh, &newfacet->ridges, ridge);- numold++;- }- }- if (same->ridges)- qh_settruncate(qh, same->ridges, 0);- if (!same->simplicial)- continue;- FOREACHneighbor_i_(qh, same) { /* note: !newfact->simplicial */- if (neighbor->visitid != samevisitid && neighbor->simplicial) {- ridge= qh_newridge(qh);- ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,- neighbor_i, 0);- toporient= same->toporient ^ (neighbor_i & 0x1);- if (toporient) {- ridge->top= newfacet;- ridge->bottom= neighbor;- }else {- ridge->top= neighbor;- ridge->bottom= newfacet;- }- qh_setappend(qh, &(newfacet->ridges), ridge);- qh_setappend(qh, &(neighbor->ridges), ridge);- numnew++;- }- }- }-- trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",- numold, numnew));-} /* mergecycle_ridges */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergecycle_vneighbors">-</a>-- qh_mergecycle_vneighbors(qh, samecycle, newfacet )- create vertex neighbors for newfacet from vertices of facets in samecycle- samecycle marked with visitid == qh.visit_id - 1-- returns:- newfacet vertices with updated neighbors- marks newfacet with qh.visit_id-1- deletes vertices that are merged away- sets delridge on all vertices (faster here than in mergecycle_ridges)-- see:- qh_mergevertex_neighbors()-- design:- for each vertex of samecycle facet- set vertex->delridge- delete samecycle facets from vertex neighbors- append newfacet to vertex neighbors- if vertex only in newfacet- delete it from newfacet- add it to qh.del_vertices for later deletion-*/-void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {- facetT *neighbor, **neighborp;- unsigned int mergeid;- vertexT *vertex, **vertexp, *apex;- setT *vertices;-- trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));- mergeid= qh->visit_id - 1;- newfacet->visitid= mergeid;- vertices= qh_basevertices(qh, samecycle); /* temp */- apex= SETfirstt_(samecycle->vertices, vertexT);- qh_setappend(qh, &vertices, apex);- FOREACHvertex_(vertices) {- vertex->delridge= True;- FOREACHneighbor_(vertex) {- if (neighbor->visitid == mergeid)- SETref_(neighbor)= NULL;- }- qh_setcompact(qh, vertex->neighbors);- qh_setappend(qh, &vertex->neighbors, newfacet);- if (!SETsecond_(vertex->neighbors)) {- zinc_(Zcyclevertex);- trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",- vertex->id, samecycle->id, newfacet->id));- qh_setdelsorted(newfacet->vertices, vertex);- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);- }- }- qh_settempfree(qh, &vertices);- trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",- samecycle->id, newfacet->id));-} /* mergecycle_vneighbors */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergefacet">-</a>-- qh_mergefacet(qh, facet1, facet2, mindist, maxdist, mergeapex )- merges facet1 into facet2- mergeapex==qh_MERGEapex if merging new facet into coplanar horizon-- returns:- qh.max_outside and qh.min_vertex updated- initializes vertex neighbors on first merge-- returns:- facet2 contains facet1's vertices, neighbors, and ridges- facet2 moved to end of qh.facet_list- makes facet2 a newfacet- sets facet2->newmerge set- clears facet2->center (unless merging into a large facet)- clears facet2->tested and ridge->tested for facet1-- facet1 prepended to visible_list for later deletion and partitioning- facet1->f.replace == facet2-- adds neighboring facets to facet_mergeset if redundant or degenerate-- notes:- mindist/maxdist may be NULL (only if both NULL)- traces merge if fmax_(maxdist,-mindist) > TRACEdist-- see:- qh_mergecycle()-- design:- trace merge and check for degenerate simplex- make ridges for both facets- update qh.max_outside, qh.max_vertex, qh.min_vertex- update facet2->maxoutside and keepcentrum- update facet2->nummerge- update tested flags for facet2- if facet1 is simplicial- merge facet1 into facet2- else- merge facet1's neighbors into facet2- merge facet1's ridges into facet2- merge facet1's vertices into facet2- merge facet1's vertex neighbors into facet2- add facet2's vertices to qh.new_vertexlist- unless qh_MERGEapex- test facet2 for degenerate or redundant neighbors- move facet1 to qh.visible_list for later deletion- move facet2 to end of qh.newfacet_list-*/-void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {- boolT traceonce= False;- vertexT *vertex, **vertexp;- int tracerestore=0, nummerge;-- if (facet1->tricoplanar || facet2->tricoplanar) {- if (!qh->TRInormals) {- qh_fprintf(qh, qh->ferr, 6226, "Qhull internal error (qh_mergefacet): does not work for tricoplanar facets. Use option 'Q11'\n");- qh_errexit2(qh, qh_ERRqhull, facet1, facet2);- }- if (facet2->tricoplanar) {- facet2->tricoplanar= False;- facet2->keepcentrum= False;- }- }- zzinc_(Ztotmerge);- if (qh->REPORTfreq2 && qh->POSTmerging) {- if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)- qh_tracemerging(qh);- }-#ifndef qh_NOtrace- if (qh->build_cnt >= qh->RERUN) {- if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {- tracerestore= 0;- qh->IStracing= qh->TRACElevel;- traceonce= True;- qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),- fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh->furthest_id);- }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {- tracerestore= qh->IStracing;- qh->IStracing= 4;- traceonce= True;- qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",- zzval_(Ztotmerge), qh->tracefacet_id, qh->furthest_id);- }- }- if (qh->IStracing >= 2) {- realT mergemin= -2;- realT mergemax= -2;-- if (mindist) {- mergemin= *mindist;- mergemax= *maxdist;- }- qh_fprintf(qh, qh->ferr, 8077, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n",- zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);- }-#endif /* !qh_NOtrace */- if (facet1 == facet2 || facet1->visible || facet2->visible) {- qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",- facet1->id, facet2->id);- qh_errexit2(qh, qh_ERRqhull, facet1, facet2);- }- if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {- qh_fprintf(qh, qh->ferr, 6227, "\n\-qhull precision error: Only %d facets remain. Can not merge another\n\-pair. The input is too degenerate or the convexity constraints are\n\-too strong.\n", qh->hull_dim+1);- if (qh->hull_dim >= 5 && !qh->MERGEexact)- qh_fprintf(qh, qh->ferr, 8079, "Option 'Qx' may avoid this problem.\n");- qh_errexit(qh, qh_ERRprec, NULL, NULL);- }- if (!qh->VERTEXneighbors)- qh_vertexneighbors(qh);- qh_makeridges(qh, facet1);- qh_makeridges(qh, facet2);- if (qh->IStracing >=4)- qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);- if (mindist) {- maximize_(qh->max_outside, *maxdist);- maximize_(qh->max_vertex, *maxdist);-#if qh_MAXoutside- maximize_(facet2->maxoutside, *maxdist);-#endif- minimize_(qh->min_vertex, *mindist);- if (!facet2->keepcentrum- && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {- facet2->keepcentrum= True;- zinc_(Zwidefacet);- }- }- nummerge= facet1->nummerge + facet2->nummerge + 1;- if (nummerge >= qh_MAXnummerge)- facet2->nummerge= qh_MAXnummerge;- else- facet2->nummerge= (short unsigned int)nummerge;- facet2->newmerge= True;- facet2->dupridge= False;- qh_updatetested(qh, facet1, facet2);- if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)- qh_mergesimplex(qh, facet1, facet2, mergeapex);- else {- qh->vertex_visit++;- FOREACHvertex_(facet2->vertices)- vertex->visitid= qh->vertex_visit;- if (qh->hull_dim == 2)- qh_mergefacet2d(qh, facet1, facet2);- else {- qh_mergeneighbors(qh, facet1, facet2);- qh_mergevertices(qh, facet1->vertices, &facet2->vertices);- }- qh_mergeridges(qh, facet1, facet2);- qh_mergevertex_neighbors(qh, facet1, facet2);- if (!facet2->newfacet)- qh_newvertices(qh, facet2->vertices);- }- if (!mergeapex)- qh_degen_redundant_neighbors(qh, facet2, facet1);- if (facet2->coplanar || !facet2->newfacet) {- zinc_(Zmergeintohorizon);- }else if (!facet1->newfacet && facet2->newfacet) {- zinc_(Zmergehorizon);- }else {- zinc_(Zmergenew);- }- qh_willdelete(qh, facet1, facet2);- qh_removefacet(qh, facet2); /* append as a newfacet to end of qh->facet_list */- qh_appendfacet(qh, facet2);- facet2->newfacet= True;- facet2->tested= False;- qh_tracemerge(qh, facet1, facet2);- if (traceonce) {- qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");- qh->IStracing= tracerestore;- }-} /* mergefacet */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergefacet2d">-</a>-- qh_mergefacet2d(qh, facet1, facet2 )- in 2d, merges neighbors and vertices of facet1 into facet2-- returns:- build ridges for neighbors if necessary- facet2 looks like a simplicial facet except for centrum, ridges- neighbors are opposite the corresponding vertex- maintains orientation of facet2-- notes:- qh_mergefacet() retains non-simplicial structures- they are not needed in 2d, but later routines may use them- preserves qh.vertex_visit for qh_mergevertex_neighbors()-- design:- get vertices and neighbors- determine new vertices and neighbors- set new vertices and neighbors and adjust orientation- make ridges for new neighbor if needed-*/-void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {- vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;- facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;-- vertex1A= SETfirstt_(facet1->vertices, vertexT);- vertex1B= SETsecondt_(facet1->vertices, vertexT);- vertex2A= SETfirstt_(facet2->vertices, vertexT);- vertex2B= SETsecondt_(facet2->vertices, vertexT);- neighbor1A= SETfirstt_(facet1->neighbors, facetT);- neighbor1B= SETsecondt_(facet1->neighbors, facetT);- neighbor2A= SETfirstt_(facet2->neighbors, facetT);- neighbor2B= SETsecondt_(facet2->neighbors, facetT);- if (vertex1A == vertex2A) {- vertexA= vertex1B;- vertexB= vertex2B;- neighborA= neighbor2A;- neighborB= neighbor1A;- }else if (vertex1A == vertex2B) {- vertexA= vertex1B;- vertexB= vertex2A;- neighborA= neighbor2B;- neighborB= neighbor1A;- }else if (vertex1B == vertex2A) {- vertexA= vertex1A;- vertexB= vertex2B;- neighborA= neighbor2A;- neighborB= neighbor1B;- }else { /* 1B == 2B */- vertexA= vertex1A;- vertexB= vertex2A;- neighborA= neighbor2B;- neighborB= neighbor1B;- }- /* vertexB always from facet2, neighborB always from facet1 */- if (vertexA->id > vertexB->id) {- SETfirst_(facet2->vertices)= vertexA;- SETsecond_(facet2->vertices)= vertexB;- if (vertexB == vertex2A)- facet2->toporient= !facet2->toporient;- SETfirst_(facet2->neighbors)= neighborA;- SETsecond_(facet2->neighbors)= neighborB;- }else {- SETfirst_(facet2->vertices)= vertexB;- SETsecond_(facet2->vertices)= vertexA;- if (vertexB == vertex2B)- facet2->toporient= !facet2->toporient;- SETfirst_(facet2->neighbors)= neighborB;- SETsecond_(facet2->neighbors)= neighborA;- }- qh_makeridges(qh, neighborB);- qh_setreplace(qh, neighborB->neighbors, facet1, facet2);- trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",- vertexA->id, neighborB->id, facet1->id, facet2->id));-} /* mergefacet2d */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergeneighbors">-</a>-- qh_mergeneighbors(qh, facet1, facet2 )- merges the neighbors of facet1 into facet2-- see:- qh_mergecycle_neighbors()-- design:- for each neighbor of facet1- if neighbor is also a neighbor of facet2- if neighbor is simpilicial- make ridges for later deletion as a degenerate facet- update its neighbor set- else- move the neighbor relation to facet2- remove the neighbor relation for facet1 and facet2-*/-void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {- facetT *neighbor, **neighborp;-- trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",- facet1->id, facet2->id));- qh->visit_id++;- FOREACHneighbor_(facet2) {- neighbor->visitid= qh->visit_id;- }- FOREACHneighbor_(facet1) {- if (neighbor->visitid == qh->visit_id) {- if (neighbor->simplicial) /* is degen, needs ridges */- qh_makeridges(qh, neighbor);- if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/- qh_setdel(neighbor->neighbors, facet1);- else {- qh_setdel(neighbor->neighbors, facet2);- qh_setreplace(qh, neighbor->neighbors, facet1, facet2);- }- }else if (neighbor != facet2) {- qh_setappend(qh, &(facet2->neighbors), neighbor);- qh_setreplace(qh, neighbor->neighbors, facet1, facet2);- }- }- qh_setdel(facet1->neighbors, facet2); /* here for makeridges */- qh_setdel(facet2->neighbors, facet1);-} /* mergeneighbors */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergeridges">-</a>-- qh_mergeridges(qh, facet1, facet2 )- merges the ridge set of facet1 into facet2-- returns:- may delete all ridges for a vertex- sets vertex->delridge on deleted ridges-- see:- qh_mergecycle_ridges()-- design:- delete ridges between facet1 and facet2- mark (delridge) vertices on these ridges for later testing- for each remaining ridge- rename facet1 to facet2-*/-void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {- ridgeT *ridge, **ridgep;- vertexT *vertex, **vertexp;-- trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d and f%d\n",- facet1->id, facet2->id));- FOREACHridge_(facet2->ridges) {- if ((ridge->top == facet1) || (ridge->bottom == facet1)) {- FOREACHvertex_(ridge->vertices)- vertex->delridge= True;- qh_delridge(qh, ridge); /* expensive in high-d, could rebuild */- ridgep--; /*repeat*/- }- }- FOREACHridge_(facet1->ridges) {- if (ridge->top == facet1)- ridge->top= facet2;- else- ridge->bottom= facet2;- qh_setappend(qh, &(facet2->ridges), ridge);- }-} /* mergeridges */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergesimplex">-</a>-- qh_mergesimplex(qh, facet1, facet2, mergeapex )- merge simplicial facet1 into facet2- mergeapex==qh_MERGEapex if merging samecycle into horizon facet- vertex id is latest (most recently created)- facet1 may be contained in facet2- ridges exist for both facets-- returns:- facet2 with updated vertices, ridges, neighbors- updated neighbors for facet1's vertices- facet1 not deleted- sets vertex->delridge on deleted ridges-- notes:- special case code since this is the most common merge- called from qh_mergefacet()-- design:- if qh_MERGEapex- add vertices of facet2 to qh.new_vertexlist if necessary- add apex to facet2- else- for each ridge between facet1 and facet2- set vertex->delridge- determine the apex for facet1 (i.e., vertex to be merged)- unless apex already in facet2- insert apex into vertices for facet2- add vertices of facet2 to qh.new_vertexlist if necessary- add apex to qh.new_vertexlist if necessary- for each vertex of facet1- if apex- rename facet1 to facet2 in its vertex neighbors- else- delete facet1 from vertex neighors- if only in facet2- add vertex to qh.del_vertices for later deletion- for each ridge of facet1- delete ridges between facet1 and facet2- append other ridges to facet2 after renaming facet to facet2-*/-void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {- vertexT *vertex, **vertexp, *apex;- ridgeT *ridge, **ridgep;- boolT issubset= False;- int vertex_i= -1, vertex_n;- facetT *neighbor, **neighborp, *otherfacet;-- if (mergeapex) {- if (!facet2->newfacet)- qh_newvertices(qh, facet2->vertices); /* apex is new */- apex= SETfirstt_(facet1->vertices, vertexT);- if (SETfirstt_(facet2->vertices, vertexT) != apex)- qh_setaddnth(qh, &facet2->vertices, 0, apex); /* apex has last id */- else- issubset= True;- }else {- zinc_(Zmergesimplex);- FOREACHvertex_(facet1->vertices)- vertex->seen= False;- FOREACHridge_(facet1->ridges) {- if (otherfacet_(ridge, facet1) == facet2) {- FOREACHvertex_(ridge->vertices) {- vertex->seen= True;- vertex->delridge= True;- }- break;- }- }- FOREACHvertex_(facet1->vertices) {- if (!vertex->seen)- break; /* must occur */- }- apex= vertex;- trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",- apex->id, facet1->id, facet2->id));- FOREACHvertex_i_(qh, facet2->vertices) {- if (vertex->id < apex->id) {- break;- }else if (vertex->id == apex->id) {- issubset= True;- break;- }- }- if (!issubset)- qh_setaddnth(qh, &facet2->vertices, vertex_i, apex);- if (!facet2->newfacet)- qh_newvertices(qh, facet2->vertices);- else if (!apex->newlist) {- qh_removevertex(qh, apex);- qh_appendvertex(qh, apex);- }- }- trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",- facet1->id));- FOREACHvertex_(facet1->vertices) {- if (vertex == apex && !issubset)- qh_setreplace(qh, vertex->neighbors, facet1, facet2);- else {- qh_setdel(vertex->neighbors, facet1);- if (!SETsecond_(vertex->neighbors))- qh_mergevertex_del(qh, vertex, facet1, facet2);- }- }- trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",- facet1->id, facet2->id));- qh->visit_id++;- FOREACHneighbor_(facet2)- neighbor->visitid= qh->visit_id;- FOREACHridge_(facet1->ridges) {- otherfacet= otherfacet_(ridge, facet1);- if (otherfacet == facet2) {- qh_setdel(facet2->ridges, ridge);- qh_setfree(qh, &(ridge->vertices));- qh_memfree(qh, ridge, (int)sizeof(ridgeT));- qh_setdel(facet2->neighbors, facet1);- }else {- qh_setappend(qh, &facet2->ridges, ridge);- if (otherfacet->visitid != qh->visit_id) {- qh_setappend(qh, &facet2->neighbors, otherfacet);- qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);- otherfacet->visitid= qh->visit_id;- }else {- if (otherfacet->simplicial) /* is degen, needs ridges */- qh_makeridges(qh, otherfacet);- if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)- qh_setdel(otherfacet->neighbors, facet1);- else { /*keep newfacet->neighbors->horizon*/- qh_setdel(otherfacet->neighbors, facet2);- qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);- }- }- if (ridge->top == facet1) /* wait until after qh_makeridges */- ridge->top= facet2;- else- ridge->bottom= facet2;- }- }- SETfirst_(facet1->ridges)= NULL; /* it will be deleted */- trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",- facet1->id, getid_(apex), facet2->id));-} /* mergesimplex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergevertex_del">-</a>-- qh_mergevertex_del(qh, vertex, facet1, facet2 )- delete a vertex because of merging facet1 into facet2-- returns:- deletes vertex from facet2- adds vertex to qh.del_vertices for later deletion-*/-void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {-- zinc_(Zmergevertex);- trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",- vertex->id, facet1->id, facet2->id));- qh_setdelsorted(facet2->vertices, vertex);- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);-} /* mergevertex_del */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergevertex_neighbors">-</a>-- qh_mergevertex_neighbors(qh, facet1, facet2 )- merge the vertex neighbors of facet1 to facet2-- returns:- if vertex is current qh.vertex_visit- deletes facet1 from vertex->neighbors- else- renames facet1 to facet2 in vertex->neighbors- deletes vertices if only one neighbor-- notes:- assumes vertex neighbor sets are good-*/-void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {- vertexT *vertex, **vertexp;-- trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",- facet1->id, facet2->id));- if (qh->tracevertex) {- qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",- facet1->id, facet2->id, qh->furthest_id, qh->tracevertex->neighbors->e[0].p);- qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);- }- FOREACHvertex_(facet1->vertices) {- if (vertex->visitid != qh->vertex_visit)- qh_setreplace(qh, vertex->neighbors, facet1, facet2);- else {- qh_setdel(vertex->neighbors, facet1);- if (!SETsecond_(vertex->neighbors))- qh_mergevertex_del(qh, vertex, facet1, facet2);- }- }- if (qh->tracevertex)- qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);-} /* mergevertex_neighbors */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="mergevertices">-</a>-- qh_mergevertices(qh, vertices1, vertices2 )- merges the vertex set of facet1 into facet2-- returns:- replaces vertices2 with merged set- preserves vertex_visit for qh_mergevertex_neighbors- updates qh.newvertex_list-- design:- create a merged set of both vertices (in inverse id order)-*/-void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {- int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;- setT *mergedvertices;- vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);-- mergedvertices= qh_settemp(qh, newsize);- FOREACHvertex_(vertices1) {- if (!*vertex2 || vertex->id > (*vertex2)->id)- qh_setappend(qh, &mergedvertices, vertex);- else {- while (*vertex2 && (*vertex2)->id > vertex->id)- qh_setappend(qh, &mergedvertices, *vertex2++);- if (!*vertex2 || (*vertex2)->id < vertex->id)- qh_setappend(qh, &mergedvertices, vertex);- else- qh_setappend(qh, &mergedvertices, *vertex2++);- }- }- while (*vertex2)- qh_setappend(qh, &mergedvertices, *vertex2++);- if (newsize < qh_setsize(qh, mergedvertices)) {- qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- qh_setfree(qh, vertices2);- *vertices2= mergedvertices;- qh_settemppop(qh);-} /* mergevertices */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="neighbor_intersections">-</a>-- qh_neighbor_intersections(qh, vertex )- return intersection of all vertices in vertex->neighbors except for vertex-- returns:- returns temporary set of vertices- does not include vertex- NULL if a neighbor is simplicial- NULL if empty set-- notes:- used for renaming vertices-- design:- initialize the intersection set with vertices of the first two neighbors- delete vertex from the intersection- for each remaining neighbor- intersect its vertex set with the intersection set- return NULL if empty- return the intersection set-*/-setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {- facetT *neighbor, **neighborp, *neighborA, *neighborB;- setT *intersect;- int neighbor_i, neighbor_n;-- FOREACHneighbor_(vertex) {- if (neighbor->simplicial)- return NULL;- }- neighborA= SETfirstt_(vertex->neighbors, facetT);- neighborB= SETsecondt_(vertex->neighbors, facetT);- zinc_(Zintersectnum);- if (!neighborA)- return NULL;- if (!neighborB)- intersect= qh_setcopy(qh, neighborA->vertices, 0);- else- intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);- qh_settemppush(qh, intersect);- qh_setdelsorted(intersect, vertex);- FOREACHneighbor_i_(qh, vertex) {- if (neighbor_i >= 2) {- zinc_(Zintersectnum);- qh_vertexintersect(qh, &intersect, neighbor->vertices);- if (!SETfirst_(intersect)) {- zinc_(Zintersectfail);- qh_settempfree(qh, &intersect);- return NULL;- }- }- }- trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",- qh_setsize(qh, intersect), vertex->id));- return intersect;-} /* neighbor_intersections */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="newvertices">-</a>-- qh_newvertices(qh, vertices )- add vertices to end of qh.vertex_list (marks as new vertices)-- returns:- vertices on qh.newvertex_list- vertex->newlist set-*/-void qh_newvertices(qhT *qh, setT *vertices) {- vertexT *vertex, **vertexp;-- FOREACHvertex_(vertices) {- if (!vertex->newlist) {- qh_removevertex(qh, vertex);- qh_appendvertex(qh, vertex);- }- }-} /* newvertices */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="reducevertices">-</a>-- qh_reducevertices(qh)- reduce extra vertices, shared vertices, and redundant vertices- facet->newmerge is set if merged since last call- if !qh.MERGEvertices, only removes extra vertices-- returns:- True if also merged degen_redundant facets- vertices are renamed if possible- clears facet->newmerge and vertex->delridge-- notes:- ignored if 2-d-- design:- merge any degenerate or redundant facets- for each newly merged facet- remove extra vertices- if qh.MERGEvertices- for each newly merged facet- for each vertex- if vertex was on a deleted ridge- rename vertex if it is shared- remove delridge flag from new vertices-*/-boolT qh_reducevertices(qhT *qh) {- int numshare=0, numrename= 0;- boolT degenredun= False;- facetT *newfacet;- vertexT *vertex, **vertexp;-- if (qh->hull_dim == 2)- return False;- if (qh_merge_degenredundant(qh))- degenredun= True;- LABELrestart:- FORALLnew_facets {- if (newfacet->newmerge) {- if (!qh->MERGEvertices)- newfacet->newmerge= False;- qh_remove_extravertices(qh, newfacet);- }- }- if (!qh->MERGEvertices)- return False;- FORALLnew_facets {- if (newfacet->newmerge) {- newfacet->newmerge= False;- FOREACHvertex_(newfacet->vertices) {- if (vertex->delridge) {- if (qh_rename_sharedvertex(qh, vertex, newfacet)) {- numshare++;- vertexp--; /* repeat since deleted vertex */- }- }- }- }- }- FORALLvertex_(qh->newvertex_list) {- if (vertex->delridge && !vertex->deleted) {- vertex->delridge= False;- if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {- numrename++;- if (qh_merge_degenredundant(qh)) {- degenredun= True;- goto LABELrestart;- }- }- }- }- trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",- numshare, numrename, degenredun));- return degenredun;-} /* reducevertices */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="redundant_vertex">-</a>-- qh_redundant_vertex(qh, vertex )- detect and rename a redundant vertex- vertices have full vertex->neighbors-- returns:- returns true if find a redundant vertex- deletes vertex(vertex->deleted)-- notes:- only needed if vertex->delridge and hull_dim >= 4- may add degenerate facets to qh.facet_mergeset- doesn't change vertex->neighbors or create redundant facets-- design:- intersect vertices of all facet neighbors of vertex- determine ridges for these vertices- if find a new vertex for vertex amoung these ridges and vertices- rename vertex to the new vertex-*/-vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {- vertexT *newvertex= NULL;- setT *vertices, *ridges;-- trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));- if ((vertices= qh_neighbor_intersections(qh, vertex))) {- ridges= qh_vertexridges(qh, vertex);- if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))- qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL);- qh_settempfree(qh, &ridges);- qh_settempfree(qh, &vertices);- }- return newvertex;-} /* redundant_vertex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="remove_extravertices">-</a>-- qh_remove_extravertices(qh, facet )- remove extra vertices from non-simplicial facets-- returns:- returns True if it finds them-- design:- for each vertex in facet- if vertex not in a ridge (i.e., no longer used)- delete vertex from facet- delete facet from vertice's neighbors- unless vertex in another facet- add vertex to qh.del_vertices for later deletion-*/-boolT qh_remove_extravertices(qhT *qh, facetT *facet) {- ridgeT *ridge, **ridgep;- vertexT *vertex, **vertexp;- boolT foundrem= False;-- trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test f%d for extra vertices\n",- facet->id));- FOREACHvertex_(facet->vertices)- vertex->seen= False;- FOREACHridge_(facet->ridges) {- FOREACHvertex_(ridge->vertices)- vertex->seen= True;- }- FOREACHvertex_(facet->vertices) {- if (!vertex->seen) {- foundrem= True;- zinc_(Zremvertex);- qh_setdelsorted(facet->vertices, vertex);- qh_setdel(vertex->neighbors, facet);- if (!qh_setsize(qh, vertex->neighbors)) {- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);- zinc_(Zremvertexdel);- trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));- }else- trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));- vertexp--; /*repeat*/- }- }- return foundrem;-} /* remove_extravertices */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="rename_sharedvertex">-</a>-- qh_rename_sharedvertex(qh, vertex, facet )- detect and rename if shared vertex in facet- vertices have full ->neighbors-- returns:- newvertex or NULL- the vertex may still exist in other facets (i.e., a neighbor was pinched)- does not change facet->neighbors- updates vertex->neighbors-- notes:- a shared vertex for a facet is only in ridges to one neighbor- this may undo a pinched facet-- it does not catch pinches involving multiple facets. These appear- to be difficult to detect, since an exhaustive search is too expensive.-- design:- if vertex only has two neighbors- determine the ridges that contain the vertex- determine the vertices shared by both neighbors- if can find a new vertex in this set- rename the vertex to the new vertex-*/-vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {- facetT *neighbor, **neighborp, *neighborA= NULL;- setT *vertices, *ridges;- vertexT *newvertex;-- if (qh_setsize(qh, vertex->neighbors) == 2) {- neighborA= SETfirstt_(vertex->neighbors, facetT);- if (neighborA == facet)- neighborA= SETsecondt_(vertex->neighbors, facetT);- }else if (qh->hull_dim == 3)- return NULL;- else {- qh->visit_id++;- FOREACHneighbor_(facet)- neighbor->visitid= qh->visit_id;- FOREACHneighbor_(vertex) {- if (neighbor->visitid == qh->visit_id) {- if (neighborA)- return NULL;- neighborA= neighbor;- }- }- if (!neighborA) {- qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",- vertex->id, facet->id);- qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- }- /* the vertex is shared by facet and neighborA */- ridges= qh_settemp(qh, qh->TEMPsize);- neighborA->visitid= ++qh->visit_id;- qh_vertexridges_facet(qh, vertex, facet, &ridges);- trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",- qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));- zinc_(Zintersectnum);- vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);- qh_setdel(vertices, vertex);- qh_settemppush(qh, vertices);- if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))- qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA);- qh_settempfree(qh, &vertices);- qh_settempfree(qh, &ridges);- return newvertex;-} /* rename_sharedvertex */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="renameridgevertex">-</a>-- qh_renameridgevertex(qh, ridge, oldvertex, newvertex )- renames oldvertex as newvertex in ridge-- returns:-- design:- delete oldvertex from ridge- if newvertex already in ridge- copy ridge->noconvex to another ridge if possible- delete the ridge- else- insert newvertex into the ridge- adjust the ridge's orientation-*/-void qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {- int nth= 0, oldnth;- facetT *temp;- vertexT *vertex, **vertexp;-- oldnth= qh_setindex(ridge->vertices, oldvertex);- qh_setdelnthsorted(qh, ridge->vertices, oldnth);- FOREACHvertex_(ridge->vertices) {- if (vertex == newvertex) {- zinc_(Zdelridge);- if (ridge->nonconvex) /* only one ridge has nonconvex set */- qh_copynonconvex(qh, ridge);- trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted. It contained both v%d and v%d\n",- ridge->id, oldvertex->id, newvertex->id));- qh_delridge(qh, ridge);- return;- }- if (vertex->id < newvertex->id)- break;- nth++;- }- qh_setaddnth(qh, &ridge->vertices, nth, newvertex);- if (abs(oldnth - nth)%2) {- trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",- ridge->id));- temp= ridge->top;- ridge->top= ridge->bottom;- ridge->bottom= temp;- }-} /* renameridgevertex */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="renamevertex">-</a>-- qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )- renames oldvertex as newvertex in ridges- gives oldfacet/neighborA if oldvertex is shared between two facets-- returns:- oldvertex may still exist afterwards--- notes:- can not change neighbors of newvertex (since it's a subset)-- design:- for each ridge in ridges- rename oldvertex to newvertex and delete degenerate ridges- if oldfacet not defined- for each neighbor of oldvertex- delete oldvertex from neighbor's vertices- remove extra vertices from neighbor- add oldvertex to qh.del_vertices- else if oldvertex only between oldfacet and neighborA- delete oldvertex from oldfacet and neighborA- add oldvertex to qh.del_vertices- else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)- delete oldvertex from oldfacet- delete oldfacet from oldvertice's neighbors- remove extra vertices (e.g., oldvertex) from neighborA-*/-void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {- facetT *neighbor, **neighborp;- ridgeT *ridge, **ridgep;- boolT istrace= False;-- if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||- newvertex->id == qh->tracevertex_id)- istrace= True;- FOREACHridge_(ridges)- qh_renameridgevertex(qh, ridge, oldvertex, newvertex);- if (!oldfacet) {- zinc_(Zrenameall);- if (istrace)- qh_fprintf(qh, qh->ferr, 8082, "qh_renamevertex: renamed v%d to v%d in several facets\n",- oldvertex->id, newvertex->id);- FOREACHneighbor_(oldvertex) {- qh_maydropneighbor(qh, neighbor);- qh_setdelsorted(neighbor->vertices, oldvertex);- if (qh_remove_extravertices(qh, neighbor))- neighborp--; /* neighbor may be deleted */- }- if (!oldvertex->deleted) {- oldvertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, oldvertex);- }- }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {- zinc_(Zrenameshare);- if (istrace)- qh_fprintf(qh, qh->ferr, 8083, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n",- oldvertex->id, newvertex->id, oldfacet->id);- FOREACHneighbor_(oldvertex)- qh_setdelsorted(neighbor->vertices, oldvertex);- oldvertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, oldvertex);- }else {- zinc_(Zrenamepinch);- if (istrace || qh->IStracing)- qh_fprintf(qh, qh->ferr, 8084, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n",- oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);- qh_setdelsorted(oldfacet->vertices, oldvertex);- qh_setdel(oldvertex->neighbors, oldfacet);- qh_remove_extravertices(qh, neighborA);- }-} /* renamevertex */---/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="test_appendmerge">-</a>-- qh_test_appendmerge(qh, facet, neighbor )- tests facet/neighbor for convexity- appends to mergeset if non-convex- if pre-merging,- nop if qh.SKIPconvex, or qh.MERGEexact and coplanar-- returns:- true if appends facet/neighbor to mergeset- sets facet->center as needed- does not change facet->seen-- design:- if qh.cos_max is defined- if the angle between facet normals is too shallow- append an angle-coplanar merge to qh.mergeset- return True- make facet's centrum if needed- if facet's centrum is above the neighbor- set isconcave- else- if facet's centrum is not below the neighbor- set iscoplanar- make neighbor's centrum if needed- if neighbor's centrum is above the facet- set isconcave- else if neighbor's centrum is not below the facet- set iscoplanar- if isconcave or iscoplanar- get angle if needed- append concave or coplanar merge to qh.mergeset-*/-boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor) {- realT dist, dist2= -REALmax, angle= -REALmax;- boolT isconcave= False, iscoplanar= False, okangle= False;-- if (qh->SKIPconvex && !qh->POSTmerging)- return False;- if ((!qh->MERGEexact || qh->POSTmerging) && qh->cos_max < REALmax/2) {- angle= qh_getangle(qh, facet->normal, neighbor->normal);- zinc_(Zangletests);- if (angle > qh->cos_max) {- zinc_(Zcoplanarangle);- qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, &angle);- trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",- angle, facet->id, neighbor->id));- return True;- }else- okangle= True;- }- if (!facet->center)- facet->center= qh_getcentrum(qh, facet);- zzinc_(Zcentrumtests);- qh_distplane(qh, facet->center, neighbor, &dist);- if (dist > qh->centrum_radius)- isconcave= True;- else {- if (dist > -qh->centrum_radius)- iscoplanar= True;- if (!neighbor->center)- neighbor->center= qh_getcentrum(qh, neighbor);- zzinc_(Zcentrumtests);- qh_distplane(qh, neighbor->center, facet, &dist2);- if (dist2 > qh->centrum_radius)- isconcave= True;- else if (!iscoplanar && dist2 > -qh->centrum_radius)- iscoplanar= True;- }- if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))- return False;- if (!okangle && qh->ANGLEmerge) {- angle= qh_getangle(qh, facet->normal, neighbor->normal);- zinc_(Zangletests);- }- if (isconcave) {- zinc_(Zconcaveridge);- if (qh->ANGLEmerge)- angle += qh_ANGLEconcave + 0.5;- qh_appendmergeset(qh, facet, neighbor, MRGconcave, &angle);- trace0((qh, qh->ferr, 18, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",- facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));- }else /* iscoplanar */ {- zinc_(Zcoplanarcentrum);- qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, &angle);- trace2((qh, qh->ferr, 2040, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",- facet->id, neighbor->id, dist, dist2, angle));- }- return True;-} /* test_appendmerge */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="test_vneighbors">-</a>-- qh_test_vneighbors(qh)- test vertex neighbors for convexity- tests all facets on qh.newfacet_list-- returns:- true if non-convex vneighbors appended to qh.facet_mergeset- initializes vertex neighbors if needed-- notes:- assumes all facet neighbors have been tested- this can be expensive- this does not guarantee that a centrum is below all facets- but it is unlikely- uses qh.visit_id-- design:- build vertex neighbors if necessary- for all new facets- for all vertices- for each unvisited facet neighbor of the vertex- test new facet and neighbor for convexity-*/-boolT qh_test_vneighbors(qhT *qh /* qh->newfacet_list */) {- facetT *newfacet, *neighbor, **neighborp;- vertexT *vertex, **vertexp;- int nummerges= 0;-- trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));- if (!qh->VERTEXneighbors)- qh_vertexneighbors(qh);- FORALLnew_facets- newfacet->seen= False;- FORALLnew_facets {- newfacet->seen= True;- newfacet->visitid= qh->visit_id++;- FOREACHneighbor_(newfacet)- newfacet->visitid= qh->visit_id;- FOREACHvertex_(newfacet->vertices) {- FOREACHneighbor_(vertex) {- if (neighbor->seen || neighbor->visitid == qh->visit_id)- continue;- if (qh_test_appendmerge(qh, newfacet, neighbor))- nummerges++;- }- }- }- zadd_(Ztestvneighbor, nummerges);- trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",- nummerges));- return (nummerges > 0);-} /* test_vneighbors */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="tracemerge">-</a>-- qh_tracemerge(qh, facet1, facet2 )- print trace message after merge-*/-void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2) {- boolT waserror= False;--#ifndef qh_NOtrace- if (qh->IStracing >= 4)- qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);- if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newlist)) {- qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh->furthest_id);- if (facet2 != qh->tracefacet)- qh_errprint(qh, "TRACE", qh->tracefacet,- (qh->tracevertex && qh->tracevertex->neighbors) ?- SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,- NULL, qh->tracevertex);- }- if (qh->tracevertex) {- if (qh->tracevertex->deleted)- qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",- qh->furthest_id);- else- qh_checkvertex(qh, qh->tracevertex);- }- if (qh->tracefacet) {- qh_checkfacet(qh, qh->tracefacet, True, &waserror);- if (waserror)- qh_errexit(qh, qh_ERRqhull, qh->tracefacet, NULL);- }-#endif /* !qh_NOtrace */- if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */- qh_checkfacet(qh, facet2, True, &waserror);- if (waserror)- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }-} /* tracemerge */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="tracemerging">-</a>-- qh_tracemerging(qh)- print trace message during POSTmerging-- returns:- updates qh.mergereport-- notes:- called from qh_mergecycle() and qh_mergefacet()-- see:- qh_buildtracing()-*/-void qh_tracemerging(qhT *qh) {- realT cpu;- int total;- time_t timedata;- struct tm *tp;-- qh->mergereport= zzval_(Ztotmerge);- time(&timedata);- tp= localtime(&timedata);- cpu= qh_CPUclock;- cpu /= qh_SECticks;- total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);- qh_fprintf(qh, qh->ferr, 8087, "\n\-At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets. The hull\n\- contains %d facets and %d vertices.\n",- tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,- total, qh->num_facets - qh->num_visible,- qh->num_vertices-qh_setsize(qh, qh->del_vertices));-} /* tracemerging */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="updatetested">-</a>-- qh_updatetested(qh, facet1, facet2 )- clear facet2->tested and facet1->ridge->tested for merge-- returns:- deletes facet2->center unless it's already large- if so, clears facet2->ridge->tested-- design:- clear facet2->tested- clear ridge->tested for facet1's ridges- if facet2 has a centrum- if facet2 is large- set facet2->keepcentrum- else if facet2 has 3 vertices due to many merges, or not large and post merging- clear facet2->keepcentrum- unless facet2->keepcentrum- clear facet2->center to recompute centrum later- clear ridge->tested for facet2's ridges-*/-void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {- ridgeT *ridge, **ridgep;- int size;-- facet2->tested= False;- FOREACHridge_(facet1->ridges)- ridge->tested= False;- if (!facet2->center)- return;- size= qh_setsize(qh, facet2->vertices);- if (!facet2->keepcentrum) {- if (size > qh->hull_dim + qh_MAXnewcentrum) {- facet2->keepcentrum= True;- zinc_(Zwidevertices);- }- }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {- /* center and keepcentrum was set */- if (size == qh->hull_dim || qh->POSTmerging)- facet2->keepcentrum= False; /* if many merges need to recompute centrum */- }- if (!facet2->keepcentrum) {- qh_memfree(qh, facet2->center, qh->normal_size);- facet2->center= NULL;- FOREACHridge_(facet2->ridges)- ridge->tested= False;- }-} /* updatetested */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="vertexridges">-</a>-- qh_vertexridges(qh, vertex )- return temporary set of ridges adjacent to a vertex- vertex->neighbors defined-- ntoes:- uses qh.visit_id- does not include implicit ridges for simplicial facets-- design:- for each neighbor of vertex- add ridges that include the vertex to ridges-*/-setT *qh_vertexridges(qhT *qh, vertexT *vertex) {- facetT *neighbor, **neighborp;- setT *ridges= qh_settemp(qh, qh->TEMPsize);- int size;-- qh->visit_id++;- FOREACHneighbor_(vertex)- neighbor->visitid= qh->visit_id;- FOREACHneighbor_(vertex) {- if (*neighborp) /* no new ridges in last neighbor */- qh_vertexridges_facet(qh, vertex, neighbor, &ridges);- }- if (qh->PRINTstatistics || qh->IStracing) {- size= qh_setsize(qh, ridges);- zinc_(Zvertexridge);- zadd_(Zvertexridgetot, size);- zmax_(Zvertexridgemax, size);- trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",- size, vertex->id));- }- return ridges;-} /* vertexridges */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="vertexridges_facet">-</a>-- qh_vertexridges_facet(qh, vertex, facet, ridges )- add adjacent ridges for vertex in facet- neighbor->visitid==qh.visit_id if it hasn't been visited-- returns:- ridges updated- sets facet->visitid to qh.visit_id-1-- design:- for each ridge of facet- if ridge of visited neighbor (i.e., unprocessed)- if vertex in ridge- append ridge to vertex- mark facet processed-*/-void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {- ridgeT *ridge, **ridgep;- facetT *neighbor;-- FOREACHridge_(facet->ridges) {- neighbor= otherfacet_(ridge, facet);- if (neighbor->visitid == qh->visit_id- && qh_setin(ridge->vertices, vertex))- qh_setappend(qh, ridges, ridge);- }- facet->visitid= qh->visit_id-1;-} /* vertexridges_facet */--/*-<a href="qh-merge_r.htm#TOC"- >-------------------------------</a><a name="willdelete">-</a>-- qh_willdelete(qh, facet, replace )- moves facet to visible list- sets facet->f.replace to replace (may be NULL)-- returns:- bumps qh.num_visible-*/-void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {-- qh_removefacet(qh, facet);- qh_prependfacet(qh, facet, &qh->visible_list);- qh->num_visible++;- facet->visible= True;- facet->f.replace= replace;-} /* willdelete */--#else /* qh_NOmerge */-void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {-}-void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,- boolT vneighbors) {-}-boolT qh_checkzero(qhT *qh, boolT testall) {- }-#endif /* qh_NOmerge */-
− C/poly2_r.c
@@ -1,3222 +0,0 @@-/*<html><pre> -<a href="qh-poly_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- poly2_r.c- implements polygons and simplicies-- see qh-poly_r.htm, poly_r.h and libqhull_r.h-- frequently used code is in poly_r.c-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/poly2_r.c#10 $$Change: 2069 $- $DateTime: 2016/01/18 22:05:03 $$Author: bbarber $-*/--#include "qhull_ra.h"--/*======== functions in alphabetical order ==========*/--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="addhash">-</a>-- qh_addhash( newelem, hashtable, hashsize, hash )- add newelem to linear hash table at hash if not already there-*/-void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {- int scan;- void *elem;-- for (scan= (int)hash; (elem= SETelem_(hashtable, scan));- scan= (++scan >= hashsize ? 0 : scan)) {- if (elem == newelem)- break;- }- /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */- if (!elem)- SETelem_(hashtable, scan)= newelem;-} /* addhash */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_bestdist">-</a>-- qh_check_bestdist(qh)- check that all points are within max_outside of the nearest facet- if qh.ONLYgood,- ignores !good facets-- see:- qh_check_maxout(), qh_outerinner()-- notes:- only called from qh_check_points()- seldom used since qh.MERGING is almost always set- if notverified>0 at end of routine- some points were well inside the hull. If the hull contains- a lens-shaped component, these points were not verified. Use- options 'Qi Tv' to verify all points. (Exhaustive check also verifies)-- design:- determine facet for each point (if any)- for each point- start with the assigned facet or with the first facet- find the best facet for the point and check all coplanar facets- error if point is outside of facet-*/-void qh_check_bestdist(qhT *qh) {- boolT waserror= False, unassigned;- facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;- facetT *facetlist;- realT dist, maxoutside, maxdist= -REALmax;- pointT *point;- int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;- setT *facets;-- trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet. Facet_list f%d\n",- qh->facet_list->id));- maxoutside= qh_maxouter(qh);- maxoutside += qh->DISTround;- /* one more qh.DISTround for check computation */- trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));- facets= qh_pointfacet(qh /*qh.facet_list*/);- if (!qh_QUICKhelp && qh->PRINTprecision)- qh_fprintf(qh, qh->ferr, 8091, "\n\-qhull output completed. Verifying that %d points are\n\-below %2.2g of the nearest %sfacet.\n",- qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ? "good " : ""));- FOREACHfacet_i_(qh, facets) { /* for each point with facet assignment */- if (facet)- unassigned= False;- else {- unassigned= True;- facet= qh->facet_list;- }- point= qh_point(qh, facet_i);- if (point == qh->GOODpointp)- continue;- qh_distplane(qh, point, facet, &dist);- numpart++;- bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);- /* occurs after statistics reported */- maximize_(maxdist, dist);- if (dist > maxoutside) {- if (qh->ONLYgood && !bestfacet->good- && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))- && dist > maxoutside))- notgood++;- else {- waserror= True;- qh_fprintf(qh, qh->ferr, 6109, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",- facet_i, bestfacet->id, dist, maxoutside);- if (errfacet1 != bestfacet) {- errfacet2= errfacet1;- errfacet1= bestfacet;- }- }- }else if (unassigned && dist < -qh->MAXcoplanar)- notverified++;- }- qh_settempfree(qh, &facets);- if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)- qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull. If the hull contains\n\-a lens-shaped component, these points were not verified. Use\n\-options 'Qci Tv' to verify all points.\n", notverified);- if (maxdist > qh->outside_err) {- qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n",- maxdist, qh->outside_err);- qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);- }else if (waserror && qh->outside_err > REALmax/2)- qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);- /* else if waserror, the error was logged to qh.ferr but does not effect the output */- trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));-} /* check_bestdist */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_dupridge">-</a>-- qh_check_dupridge(qh, facet1, dist1, facet2, dist2)- Check duplicate ridge between facet1 and facet2 for wide merge- dist1 is the maximum distance of facet1's vertices to facet2- dist2 is the maximum distance of facet2's vertices to facet1-- Returns- Level 1 log of the duplicate ridge with the minimum distance between vertices- Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)-- called from:- qh_forcedmerges()-*/-#ifndef qh_NOmerge-void qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2) {- vertexT *vertex, **vertexp, *vertexA, **vertexAp;- realT dist, innerplane, mergedist, outerplane, prevdist, ratio;- realT minvertex= REALmax;-- mergedist= fmin_(dist1, dist2);- qh_outerinner(qh, NULL, &outerplane, &innerplane); /* ratio from qh_printsummary */- prevdist= fmax_(outerplane, innerplane);- maximize_(prevdist, qh->ONEmerge + qh->DISTround);- maximize_(prevdist, qh->MINoutside + qh->DISTround);- ratio= mergedist/prevdist;- FOREACHvertex_(facet1->vertices) { /* The duplicate ridge is between facet1 and facet2, so either facet can be tested */- FOREACHvertexA_(facet1->vertices) {- if (vertex > vertexA){ /* Test each pair once */- dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);- minimize_(minvertex, dist);- }- }- }- trace0((qh, qh->ferr, 16, "qh_check_dupridge: duplicate ridge between f%d and f%d due to nearly-coincident vertices (%2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",- facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh->furthest_id));- if (ratio > qh_WIDEduplicate) {- qh_fprintf(qh, qh->ferr, 6271, "qhull precision error (qh_check_dupridge): wide merge (%.0f times wider) due to duplicate ridge with nearly coincident points (%2.2g) between f%d and f%d, merge dist %2.2g, while processing p%d\n- Ignore error with option 'Q12'\n- To be fixed in a later version of Qhull\n",- ratio, minvertex, facet1->id, facet2->id, mergedist, qh->furthest_id);- if (qh->DELAUNAY)- qh_fprintf(qh, qh->ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");- if(minvertex > qh_WIDEduplicate*prevdist)- qh_fprintf(qh, qh->ferr, 8146, "- Vertex distance %2.2g is greater than %d times maximum distance %2.2g\n Please report to bradb@shore.net with steps to reproduce and all output\n",- minvertex, qh_WIDEduplicate, prevdist);- if (!qh->NOwide)- qh_errexit2(qh, qh_ERRqhull, facet1, facet2);- }-} /* check_dupridge */-#endif--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_maxout">-</a>-- qh_check_maxout(qh)- updates qh.max_outside by checking all points against bestfacet- if qh.ONLYgood, ignores !good facets-- returns:- updates facet->maxoutside via qh_findbesthorizon()- sets qh.maxoutdone- if printing qh.min_vertex (qh_outerinner),- it is updated to the current vertices- removes inside/coplanar points from coplanarset as needed-- notes:- defines coplanar as min_vertex instead of MAXcoplanar- may not need to check near-inside points because of qh.MAXcoplanar- and qh.KEEPnearinside (before it was -DISTround)-- see also:- qh_check_bestdist()-- design:- if qh.min_vertex is needed- for all neighbors of all vertices- test distance from vertex to neighbor- determine facet for each point (if any)- for each point with an assigned facet- find the best facet for the point and check all coplanar facets- (updates outer planes)- remove near-inside points from coplanar sets-*/-#ifndef qh_NOmerge-void qh_check_maxout(qhT *qh) {- facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;- realT dist, maxoutside, minvertex, old_maxoutside;- pointT *point;- int numpart= 0, facet_i, facet_n, notgood= 0;- setT *facets, *vertices;- vertexT *vertex;-- trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update maxoutside for each facet.\n"));- maxoutside= minvertex= 0;- if (qh->VERTEXneighbors- && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar- || qh->TRACElevel || qh->PRINTstatistics- || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {- trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual maxoutside and minvertex\n"));- vertices= qh_pointvertex(qh /*qh.facet_list*/);- FORALLvertices {- FOREACHneighbor_(vertex) {- zinc_(Zdistvertex); /* distance also computed by main loop below */- qh_distplane(qh, vertex->point, neighbor, &dist);- minimize_(minvertex, dist);- if (-dist > qh->TRACEdist || dist > qh->TRACEdist- || neighbor == qh->tracefacet || vertex == qh->tracevertex)- qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d\n",- qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);- }- }- if (qh->MERGING) {- wmin_(Wminvertex, qh->min_vertex);- }- qh->min_vertex= minvertex;- qh_settempfree(qh, &vertices);- }- facets= qh_pointfacet(qh /*qh.facet_list*/);- do {- old_maxoutside= fmax_(qh->max_outside, maxoutside);- FOREACHfacet_i_(qh, facets) { /* for each point with facet assignment */- if (facet) {- point= qh_point(qh, facet_i);- if (point == qh->GOODpointp)- continue;- zzinc_(Ztotcheck);- qh_distplane(qh, point, facet, &dist);- numpart++;- bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);- if (bestfacet && dist > maxoutside) {- if (qh->ONLYgood && !bestfacet->good- && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))- && dist > maxoutside))- notgood++;- else- maxoutside= dist;- }- if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))- qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",- qh_pointid(qh, point), dist, (bestfacet ? bestfacet->id : UINT_MAX));- }- }- }while- (maxoutside > 2*old_maxoutside);- /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid- e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */- zzadd_(Zcheckpart, numpart);- qh_settempfree(qh, &facets);- wval_(Wmaxout)= maxoutside - qh->max_outside;- wmax_(Wmaxoutside, qh->max_outside);- qh->max_outside= maxoutside;- qh_nearcoplanar(qh /*qh.facet_list*/);- qh->maxoutdone= True;- trace1((qh, qh->ferr, 1024, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",- maxoutside, qh->min_vertex, notgood));-} /* check_maxout */-#else /* qh_NOmerge */-void qh_check_maxout(qhT *qh) {-}-#endif--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_output">-</a>-- qh_check_output(qh)- performs the checks at the end of qhull algorithm- Maybe called after voronoi output. Will recompute otherwise centrums are Voronoi centers instead-*/-void qh_check_output(qhT *qh) {- int i;-- if (qh->STOPcone)- return;- if (qh->VERIFYoutput | qh->IStracing | qh->CHECKfrequently) {- qh_checkpolygon(qh, qh->facet_list);- qh_checkflipped_all(qh, qh->facet_list);- qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);- }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {- qh_checkflipped_all(qh, qh->facet_list);- qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);- }-} /* check_output */----/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_point">-</a>-- qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2 )- check that point is less than maxoutside from facet-*/-void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {- realT dist;-- /* occurs after statistics reported */- qh_distplane(qh, point, facet, &dist);- if (dist > *maxoutside) {- if (*errfacet1 != facet) {- *errfacet2= *errfacet1;- *errfacet1= facet;- }- qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",- qh_pointid(qh, point), facet->id, dist, *maxoutside);- }- maximize_(*maxdist, dist);-} /* qh_check_point */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="check_points">-</a>-- qh_check_points(qh)- checks that all points are inside all facets-- notes:- if many points and qh_check_maxout not called (i.e., !qh.MERGING),- calls qh_findbesthorizon (seldom done).- ignores flipped facets- maxoutside includes 2 qh.DISTrounds- one qh.DISTround for the computed distances in qh_check_points- qh_printafacet and qh_printsummary needs only one qh.DISTround- the computation for qh.VERIFYdirect does not account for qh.other_points-- design:- if many points- use qh_check_bestdist()- else- for all facets- for all points- check that point is inside facet-*/-void qh_check_points(qhT *qh) {- facetT *facet, *errfacet1= NULL, *errfacet2= NULL;- realT total, maxoutside, maxdist= -REALmax;- pointT *point, **pointp, *pointtemp;- boolT testouter;-- maxoutside= qh_maxouter(qh);- maxoutside += qh->DISTround;- /* one more qh.DISTround for check computation */- trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",- maxoutside));- if (qh->num_good) /* miss counts other_points and !good facets */- total= (float)qh->num_good * (float)qh->num_points;- else- total= (float)qh->num_facets * (float)qh->num_points;- if (total >= qh_VERIFYdirect && !qh->maxoutdone) {- if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)- qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').\n\-Verify may report that a point is outside of a facet.\n");- qh_check_bestdist(qh);- }else {- if (qh_MAXoutside && qh->maxoutdone)- testouter= True;- else- testouter= False;- if (!qh_QUICKhelp) {- if (qh->MERGEexact)- qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx'). Verify may report that a point\n\-is outside of a facet. See qh-optq.htm#Qx\n");- else if (qh->SKIPcheckmax || qh->NOnearinside)- qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of\n\-near-inside points ('Q8'). Verify may report that a point is outside\n\-of a facet.\n");- }- if (qh->PRINTprecision) {- if (testouter)- qh_fprintf(qh, qh->ferr, 8098, "\n\-Output completed. Verifying that all points are below outer planes of\n\-all %sfacets. Will make %2.0f distance computations.\n",- (qh->ONLYgood ? "good " : ""), total);- else- qh_fprintf(qh, qh->ferr, 8099, "\n\-Output completed. Verifying that all points are below %2.2g of\n\-all %sfacets. Will make %2.0f distance computations.\n",- maxoutside, (qh->ONLYgood ? "good " : ""), total);- }- FORALLfacets {- if (!facet->good && qh->ONLYgood)- continue;- if (facet->flipped)- continue;- if (!facet->normal) {- qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);- continue;- }- if (testouter) {-#if qh_MAXoutside- maxoutside= facet->maxoutside + 2* qh->DISTround;- /* one DISTround to actual point and another to computed point */-#endif- }- FORALLpoints {- if (point != qh->GOODpointp)- qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);- }- FOREACHpoint_(qh->other_points) {- if (point != qh->GOODpointp)- qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);- }- }- if (maxdist > qh->outside_err) {- qh_fprintf(qh, qh->ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n",- maxdist, qh->outside_err );- qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );- }else if (errfacet1 && qh->outside_err > REALmax/2)- qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );- /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */- trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));- }-} /* check_points */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkconvex">-</a>-- qh_checkconvex(qh, facetlist, fault )- check that each ridge in facetlist is convex- fault = qh_DATAfault if reporting errors- = qh_ALGORITHMfault otherwise-- returns:- counts Zconcaveridges and Zcoplanarridges- errors if concaveridge or if merging an coplanar ridge-- note:- if not merging,- tests vertices for neighboring simplicial facets- else if ZEROcentrum,- tests vertices for neighboring simplicial facets- else- tests centrums of neighboring facets-- design:- for all facets- report flipped facets- if ZEROcentrum and simplicial neighbors- test vertices for neighboring simplicial facets- else- test centrum against all neighbors-*/-void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {- facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;- vertexT *vertex;- realT dist;- pointT *centrum;- boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;- int neighbor_i;-- trace1((qh, qh->ferr, 1026, "qh_checkconvex: check all ridges are convex\n"));- if (!qh->RERUN) {- zzval_(Zconcaveridges)= 0;- zzval_(Zcoplanarridges)= 0;- }- FORALLfacet_(facetlist) {- if (facet->flipped) {- qh_precision(qh, "flipped facet");- qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped(interior point is outside)\n",- facet->id);- errfacet1= facet;- waserror= True;- continue;- }- if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial || facet->tricoplanar))- allsimplicial= False;- else {- allsimplicial= True;- neighbor_i= 0;- FOREACHneighbor_(facet) {- vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);- if (!neighbor->simplicial || neighbor->tricoplanar) {- allsimplicial= False;- continue;- }- qh_distplane(qh, vertex->point, neighbor, &dist);- if (dist > -qh->DISTround) {- if (fault == qh_DATAfault) {- qh_precision(qh, "coplanar or concave ridge");- qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);- qh_errexit(qh, qh_ERRsingular, NULL, NULL);- }- if (dist > qh->DISTround) {- zzinc_(Zconcaveridges);- qh_precision(qh, "concave ridge");- qh_fprintf(qh, qh->ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above\n",- facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);- errfacet1= facet;- errfacet2= neighbor;- waserror= True;- }else if (qh->ZEROcentrum) {- if (dist > 0) { /* qh_checkzero checks that dist < - qh->DISTround */- zzinc_(Zcoplanarridges);- qh_precision(qh, "coplanar ridge");- qh_fprintf(qh, qh->ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above\n",- facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);- errfacet1= facet;- errfacet2= neighbor;- waserror= True;- }- }else {- zzinc_(Zcoplanarridges);- qh_precision(qh, "coplanar ridge");- trace0((qh, qh->ferr, 22, "qhull precision error: f%d may be coplanar to f%d, since p%d(v%d) is within %6.4g during p%d\n",- facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, qh->furthest_id));- }- }- }- }- if (!allsimplicial) {- if (qh->CENTERtype == qh_AScentrum) {- if (!facet->center)- facet->center= qh_getcentrum(qh, facet);- centrum= facet->center;- }else {- if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {- centrum_warning= True;- qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test. This may lead to false, precision errors.\n");- }- centrum= qh_getcentrum(qh, facet);- tempcentrum= True;- }- FOREACHneighbor_(facet) {- if (qh->ZEROcentrum && facet->simplicial && neighbor->simplicial)- continue;- if (facet->tricoplanar || neighbor->tricoplanar)- continue;- zzinc_(Zdistconvex);- qh_distplane(qh, centrum, neighbor, &dist);- if (dist > qh->DISTround) {- zzinc_(Zconcaveridges);- qh_precision(qh, "concave ridge");- qh_fprintf(qh, qh->ferr, 6117, "qhull precision error: f%d is concave to f%d. Centrum of f%d is %6.4g above f%d\n",- facet->id, neighbor->id, facet->id, dist, neighbor->id);- errfacet1= facet;- errfacet2= neighbor;- waserror= True;- }else if (dist >= 0.0) { /* if arithmetic always rounds the same,- can test against centrum radius instead */- zzinc_(Zcoplanarridges);- qh_precision(qh, "coplanar ridge");- qh_fprintf(qh, qh->ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d. Centrum of f%d is %6.4g above f%d\n",- facet->id, neighbor->id, facet->id, dist, neighbor->id);- errfacet1= facet;- errfacet2= neighbor;- waserror= True;- }- }- if (tempcentrum)- qh_memfree(qh, centrum, qh->normal_size);- }- }- if (waserror && !qh->FORCEoutput)- qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);-} /* checkconvex */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkfacet">-</a>-- qh_checkfacet(qh, facet, newmerge, waserror )- checks for consistency errors in facet- newmerge set if from merge_r.c-- returns:- sets waserror if any error occurs-- checks:- vertex ids are inverse sorted- unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)- if non-simplicial, at least as many ridges as neighbors- neighbors are not duplicated- ridges are not duplicated- in 3-d, ridges=verticies- (qh.hull_dim-1) ridge vertices- neighbors are reciprocated- ridge neighbors are facet neighbors and a ridge for every neighbor- simplicial neighbors match facetintersect- vertex intersection matches vertices of common ridges- vertex neighbors and facet vertices agree- all ridges have distinct vertex sets-- notes:- uses neighbor->seen-- design:- check sets- check vertices- check sizes of neighbors and vertices- check for qh_MERGEridge and qh_DUPLICATEridge flags- check neighbor set- check ridge set- check ridges, neighbors, and vertices-*/-void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {- facetT *neighbor, **neighborp, *errother=NULL;- ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;- vertexT *vertex, **vertexp;- unsigned previousid= INT_MAX;- int numneighbors, numvertices, numridges=0, numRvertices=0;- boolT waserror= False;- int skipA, skipB, ridge_i, ridge_n, i;- setT *intersection;-- if (facet->visible) {- qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",- facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- if (!facet->normal) {- qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",- facet->id);- waserror= True;- }- qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);- qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);- qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);- qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);- qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);- FOREACHvertex_(facet->vertices) {- if (vertex->deleted) {- qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);- qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);- waserror= True;- }- if (vertex->id >= previousid) {- qh_fprintf(qh, qh->ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);- waserror= True;- break;- }- previousid= vertex->id;- }- numneighbors= qh_setsize(qh, facet->neighbors);- numvertices= qh_setsize(qh, facet->vertices);- numridges= qh_setsize(qh, facet->ridges);- if (facet->simplicial) {- if (numvertices+numneighbors != 2*qh->hull_dim- && !facet->degenerate && !facet->redundant) {- qh_fprintf(qh, qh->ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh->hull_dim\n",- facet->id, numvertices, numneighbors);- qh_setprint(qh, qh->ferr, "", facet->neighbors);- waserror= True;- }- }else { /* non-simplicial */- if (!newmerge- &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)- && !facet->degenerate && !facet->redundant) {- qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",- facet->id, numvertices, numneighbors);- waserror= True;- }- /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */- if (numridges < numneighbors- ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)- ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {- if (!facet->degenerate && !facet->redundant) {- qh_fprintf(qh, qh->ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",- facet->id, numridges, numneighbors, numvertices);- waserror= True;- }- }- }- FOREACHneighbor_(facet) {- if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {- qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- neighbor->seen= True;- }- FOREACHneighbor_(facet) {- if (!qh_setin(neighbor->neighbors, facet)) {- qh_fprintf(qh, qh->ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",- facet->id, neighbor->id, neighbor->id, facet->id);- errother= neighbor;- waserror= True;- }- if (!neighbor->seen) {- qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",- facet->id, neighbor->id);- errother= neighbor;- waserror= True;- }- neighbor->seen= False;- }- FOREACHridge_(facet->ridges) {- qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);- ridge->seen= False;- }- FOREACHridge_(facet->ridges) {- if (ridge->seen) {- qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",- facet->id, ridge->id);- errridge= ridge;- waserror= True;- }- ridge->seen= True;- numRvertices= qh_setsize(qh, ridge->vertices);- if (numRvertices != qh->hull_dim - 1) {- qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",- ridge->top->id, ridge->bottom->id, numRvertices);- errridge= ridge;- waserror= True;- }- neighbor= otherfacet_(ridge, facet);- neighbor->seen= True;- if (!qh_setin(facet->neighbors, neighbor)) {- qh_fprintf(qh, qh->ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",- facet->id, neighbor->id, ridge->id);- errridge= ridge;- waserror= True;- }- }- if (!facet->simplicial) {- FOREACHneighbor_(facet) {- if (!neighbor->seen) {- qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",- facet->id, neighbor->id);- errother= neighbor;- waserror= True;- }- intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);- qh_settemppush(qh, intersection);- FOREACHvertex_(facet->vertices) {- vertex->seen= False;- vertex->seen2= False;- }- FOREACHvertex_(intersection)- vertex->seen= True;- FOREACHridge_(facet->ridges) {- if (neighbor != otherfacet_(ridge, facet))- continue;- FOREACHvertex_(ridge->vertices) {- if (!vertex->seen) {- qh_fprintf(qh, qh->ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",- vertex->id, ridge->id, facet->id, neighbor->id);- qh_errexit(qh, qh_ERRqhull, facet, ridge);- }- vertex->seen2= True;- }- }- if (!newmerge) {- FOREACHvertex_(intersection) {- if (!vertex->seen2) {- if (qh->IStracing >=3 || !qh->MERGING) {- qh_fprintf(qh, qh->ferr, 6134, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\- not in a ridge. This is ok under merging. Last point was p%d\n",- vertex->id, facet->id, neighbor->id, qh->furthest_id);- if (!qh->FORCEoutput && !qh->MERGING) {- qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);- if (!qh->MERGING)- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- }- }- }- }- qh_settempfree(qh, &intersection);- }- }else { /* simplicial */- FOREACHneighbor_(facet) {- if (neighbor->simplicial) {- skipA= SETindex_(facet->neighbors, neighbor);- skipB= qh_setindex(neighbor->neighbors, facet);- if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {- qh_fprintf(qh, qh->ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",- facet->id, skipA, neighbor->id, skipB);- errother= neighbor;- waserror= True;- }- }- }- }- if (qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {- FOREACHridge_i_(qh, facet->ridges) { /* expensive */- for (i=ridge_i+1; i < ridge_n; i++) {- ridge2= SETelemt_(facet->ridges, i, ridgeT);- if (qh_setequal(ridge->vertices, ridge2->vertices)) {- qh_fprintf(qh, qh->ferr, 6227, "Qhull internal error (qh_checkfacet): ridges r%d and r%d have the same vertices\n",- ridge->id, ridge2->id);- errridge= ridge;- waserror= True;- }- }- }- }- if (waserror) {- qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);- *waserrorp= True;- }-} /* checkfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkflipped_all">-</a>-- qh_checkflipped_all(qh, facetlist )- checks orientation of facets in list against interior point-*/-void qh_checkflipped_all(qhT *qh, facetT *facetlist) {- facetT *facet;- boolT waserror= False;- realT dist;-- if (facetlist == qh->facet_list)- zzval_(Zflippedfacets)= 0;- FORALLfacet_(facetlist) {- if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {- qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",- facet->id, dist);- if (!qh->FORCEoutput) {- qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);- waserror= True;- }- }- }- if (waserror) {- qh_fprintf(qh, qh->ferr, 8101, "\n\-A flipped facet occurs when its distance to the interior point is\n\-greater than %2.2g, the maximum roundoff error.\n", -qh->DISTround);- qh_errexit(qh, qh_ERRprec, NULL, NULL);- }-} /* checkflipped_all */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkpolygon">-</a>-- qh_checkpolygon(qh, facetlist )- checks the correctness of the structure-- notes:- call with either qh.facet_list or qh.newfacet_list- checks num_facets and num_vertices if qh.facet_list-- design:- for each facet- checks facet and outside set- initializes vertexlist- for each facet- checks vertex set- if checking all facets(qh.facetlist)- check facet count- if qh.VERTEXneighbors- check vertex neighbors and count- check vertex count-*/-void qh_checkpolygon(qhT *qh, facetT *facetlist) {- facetT *facet;- vertexT *vertex, **vertexp, *vertexlist;- int numfacets= 0, numvertices= 0, numridges= 0;- int totvneighbors= 0, totvertices= 0;- boolT waserror= False, nextseen= False, visibleseen= False;-- trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));- if (facetlist != qh->facet_list || qh->ONLYgood)- nextseen= True;- FORALLfacet_(facetlist) {- if (facet == qh->visible_list)- visibleseen= True;- if (!facet->visible) {- if (!nextseen) {- if (facet == qh->facet_next)- nextseen= True;- else if (qh_setsize(qh, facet->outsideset)) {- if (!qh->NARROWhull-#if !qh_COMPUTEfurthest- || facet->furthestdist >= qh->MINoutside-#endif- ) {- qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh->facet_next\n",- facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- }- }- numfacets++;- qh_checkfacet(qh, facet, False, &waserror);- }- }- if (qh->visible_list && !visibleseen && facetlist == qh->facet_list) {- qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh->visible_list->id);- qh_printlists(qh);- qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);- }- if (facetlist == qh->facet_list)- vertexlist= qh->vertex_list;- else if (facetlist == qh->newfacet_list)- vertexlist= qh->newvertex_list;- else- vertexlist= NULL;- FORALLvertex_(vertexlist) {- vertex->seen= False;- vertex->visitid= 0;- }- FORALLfacet_(facetlist) {- if (facet->visible)- continue;- if (facet->simplicial)- numridges += qh->hull_dim;- else- numridges += qh_setsize(qh, facet->ridges);- FOREACHvertex_(facet->vertices) {- vertex->visitid++;- if (!vertex->seen) {- vertex->seen= True;- numvertices++;- if (qh_pointid(qh, vertex->point) == qh_IDunknown) {- qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",- vertex->point, vertex->id, qh->first_point);- waserror= True;- }- }- }- }- qh->vertex_visit += (unsigned int)numfacets;- if (facetlist == qh->facet_list) {- if (numfacets != qh->num_facets - qh->num_visible) {- qh_fprintf(qh, qh->ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",- numfacets, qh->num_facets, qh->num_visible);- waserror= True;- }- qh->vertex_visit++;- if (qh->VERTEXneighbors) {- FORALLvertices {- qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);- if (vertex->deleted)- continue;- totvneighbors += qh_setsize(qh, vertex->neighbors);- }- FORALLfacet_(facetlist)- totvertices += qh_setsize(qh, facet->vertices);- if (totvneighbors != totvertices) {- qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent. Totvneighbors %d, totvertices %d\n",- totvneighbors, totvertices);- waserror= True;- }- }- if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {- qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",- numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));- waserror= True;- }- if (qh->hull_dim == 2 && numvertices != numfacets) {- qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",- numvertices, numfacets);- waserror= True;- }- if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {- qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\- A vertex appears twice in a edge list. May occur during merging.",- numvertices, numfacets, numridges/2);- /* occurs if lots of merging and a vertex ends up twice in an edge list. e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */- }- }- if (waserror)- qh_errexit(qh, qh_ERRqhull, NULL, NULL);-} /* checkpolygon */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkvertex">-</a>-- qh_checkvertex(qh, vertex )- check vertex for consistency- checks vertex->neighbors-- notes:- neighbors checked efficiently in checkpolygon-*/-void qh_checkvertex(qhT *qh, vertexT *vertex) {- boolT waserror= False;- facetT *neighbor, **neighborp, *errfacet=NULL;-- if (qh_pointid(qh, vertex->point) == qh_IDunknown) {- qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);- waserror= True;- }- if (vertex->id >= qh->vertex_id) {- qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);- waserror= True;- }- if (!waserror && !vertex->deleted) {- if (qh_setsize(qh, vertex->neighbors)) {- FOREACHneighbor_(vertex) {- if (!qh_setin(neighbor->vertices, vertex)) {- qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);- errfacet= neighbor;- waserror= True;- }- }- }- }- if (waserror) {- qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);- qh_errexit(qh, qh_ERRqhull, errfacet, NULL);- }-} /* checkvertex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="clearcenters">-</a>-- qh_clearcenters(qh, type )- clear old data from facet->center-- notes:- sets new centertype- nop if CENTERtype is the same-*/-void qh_clearcenters(qhT *qh, qh_CENTER type) {- facetT *facet;-- if (qh->CENTERtype != type) {- FORALLfacets {- if (facet->tricoplanar && !facet->keepcentrum)- facet->center= NULL; /* center is owned by the ->keepcentrum facet */- else if (qh->CENTERtype == qh_ASvoronoi){- if (facet->center) {- qh_memfree(qh, facet->center, qh->center_size);- facet->center= NULL;- }- }else /* qh->CENTERtype == qh_AScentrum */ {- if (facet->center) {- qh_memfree(qh, facet->center, qh->normal_size);- facet->center= NULL;- }- }- }- qh->CENTERtype= type;- }- trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));-} /* clearcenters */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="createsimplex">-</a>-- qh_createsimplex(qh, vertices )- creates a simplex from a set of vertices-- returns:- initializes qh.facet_list to the simplex- initializes qh.newfacet_list, .facet_tail- initializes qh.vertex_list, .newvertex_list, .vertex_tail-- design:- initializes lists- for each vertex- create a new facet- for each new facet- create its neighbor set-*/-void qh_createsimplex(qhT *qh, setT *vertices) {- facetT *facet= NULL, *newfacet;- boolT toporient= True;- int vertex_i, vertex_n, nth;- setT *newfacets= qh_settemp(qh, qh->hull_dim+1);- vertexT *vertex;-- qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);- qh->num_facets= qh->num_vertices= qh->num_visible= 0;- qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);- FOREACHvertex_i_(qh, vertices) {- newfacet= qh_newfacet(qh);- newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n,- vertex_i, 0);- newfacet->toporient= (unsigned char)toporient;- qh_appendfacet(qh, newfacet);- newfacet->newfacet= True;- qh_appendvertex(qh, vertex);- qh_setappend(qh, &newfacets, newfacet);- toporient ^= True;- }- FORALLnew_facets {- nth= 0;- FORALLfacet_(qh->newfacet_list) {- if (facet != newfacet)- SETelem_(newfacet->neighbors, nth++)= facet;- }- qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);- }- qh_settempfree(qh, &newfacets);- trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));-} /* createsimplex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="delridge">-</a>-- qh_delridge(qh, ridge )- deletes ridge from data structures it belongs to- frees up its memory-- notes:- in merge_r.c, caller sets vertex->delridge for each vertex- ridges also freed in qh_freeqhull-*/-void qh_delridge(qhT *qh, ridgeT *ridge) {- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */-- qh_setdel(ridge->top->ridges, ridge);- qh_setdel(ridge->bottom->ridges, ridge);- qh_setfree(qh, &(ridge->vertices));- qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);-} /* delridge */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="delvertex">-</a>-- qh_delvertex(qh, vertex )- deletes a vertex and frees its memory-- notes:- assumes vertex->adjacencies have been updated if needed- unlinks from vertex_list-*/-void qh_delvertex(qhT *qh, vertexT *vertex) {-- if (vertex == qh->tracevertex)- qh->tracevertex= NULL;- qh_removevertex(qh, vertex);- qh_setfree(qh, &vertex->neighbors);- qh_memfree(qh, vertex, (int)sizeof(vertexT));-} /* delvertex */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="facet3vertex">-</a>-- qh_facet3vertex(qh, )- return temporary set of 3-d vertices in qh_ORIENTclock order-- design:- if simplicial facet- build set from facet->vertices with facet->toporient- else- for each ridge in order- build set from ridge's vertices-*/-setT *qh_facet3vertex(qhT *qh, facetT *facet) {- ridgeT *ridge, *firstridge;- vertexT *vertex;- int cntvertices, cntprojected=0;- setT *vertices;-- cntvertices= qh_setsize(qh, facet->vertices);- vertices= qh_settemp(qh, cntvertices);- if (facet->simplicial) {- if (cntvertices != 3) {- qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",- cntvertices, facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- qh_setappend(qh, &vertices, SETfirst_(facet->vertices));- if (facet->toporient ^ qh_ORIENTclock)- qh_setappend(qh, &vertices, SETsecond_(facet->vertices));- else- qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));- qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));- }else {- ridge= firstridge= SETfirstt_(facet->ridges, ridgeT); /* no infinite */- while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {- qh_setappend(qh, &vertices, vertex);- if (++cntprojected > cntvertices || ridge == firstridge)- break;- }- if (!ridge || cntprojected != cntvertices) {- qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up. got at least %d\n",- facet->id, cntprojected);- qh_errexit(qh, qh_ERRqhull, facet, ridge);- }- }- return vertices;-} /* facet3vertex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="findbestfacet">-</a>-- qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )- find facet that is furthest below a point-- for Delaunay triangulations,- Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed- Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.-- returns:- if bestoutside is set (e.g., qh_ALL)- returns best facet that is not upperdelaunay- if Delaunay and inside, point is outside circumsphere of bestfacet- else- returns first facet below point- if point is inside, returns nearest, !upperdelaunay facet- distance to facet- isoutside set if outside of facet-- notes:- For tricoplanar facets, this finds one of the tricoplanar facets closest- to the point. For Delaunay triangulations, the point may be inside a- different tricoplanar facet. See <a href="../html/qh-code.htm#findfacet">locate a facet with qh_findbestfacet()</a>-- If inside, qh_findbestfacet performs an exhaustive search- this may be too conservative. Sometimes it is clearly required.-- qh_findbestfacet is not used by qhull.- uses qh.visit_id and qh.coplanarset-- see:- <a href="geom_r.c#findbest">qh_findbest</a>-*/-facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,- realT *bestdist, boolT *isoutside) {- facetT *bestfacet= NULL;- int numpart, totpart= 0;-- bestfacet= qh_findbest(qh, point, qh->facet_list,- bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,- bestdist, isoutside, &totpart);- if (*bestdist < -qh->DISTround) {- bestfacet= qh_findfacet_all(qh, point, bestdist, isoutside, &numpart);- totpart += numpart;- if ((isoutside && *isoutside && bestoutside)- || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {- bestfacet= qh_findbest(qh, point, bestfacet,- bestoutside, False, bestoutside,- bestdist, isoutside, &totpart);- totpart += numpart;- }- }- trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",- bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));- return bestfacet;-} /* findbestfacet */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="findbestlower">-</a>-- qh_findbestlower(qh, facet, point, bestdist, numpart )- returns best non-upper, non-flipped neighbor of facet for point- if needed, searches vertex neighbors-- returns:- returns bestdist and updates numpart-- notes:- if Delaunay and inside, point is outside of circumsphere of bestfacet- called by qh_findbest() for points above an upperdelaunay facet--*/-facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {- facetT *neighbor, **neighborp, *bestfacet= NULL;- realT bestdist= -REALmax/2 /* avoid underflow */;- realT dist;- vertexT *vertex;- boolT isoutside= False; /* not used */-- zinc_(Zbestlower);- FOREACHneighbor_(upperfacet) {- if (neighbor->upperdelaunay || neighbor->flipped)- continue;- (*numpart)++;- qh_distplane(qh, point, neighbor, &dist);- if (dist > bestdist) {- bestfacet= neighbor;- bestdist= dist;- }- }- if (!bestfacet) {- zinc_(Zbestlowerv);- /* rarely called, numpart does not count nearvertex computations */- vertex= qh_nearvertex(qh, upperfacet, point, &dist);- qh_vertexneighbors(qh);- FOREACHneighbor_(vertex) {- if (neighbor->upperdelaunay || neighbor->flipped)- continue;- (*numpart)++;- qh_distplane(qh, point, neighbor, &dist);- if (dist > bestdist) {- bestfacet= neighbor;- bestdist= dist;- }- }- }- if (!bestfacet) {- zinc_(Zbestlowerall); /* invoked once per point in outsideset */- zmax_(Zbestloweralln, qh->num_facets);- /* [dec'15] Previously reported as QH6228 */- trace3((qh, qh->ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay. Search all facets\n",- upperfacet->id));- /* rarely called */- bestfacet= qh_findfacet_all(qh, point, &bestdist, &isoutside, numpart);- }- *bestdistp= bestdist;- trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",- bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));- return bestfacet;-} /* findbestlower */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="findfacet_all">-</a>-- qh_findfacet_all(qh, point, bestdist, isoutside, numpart )- exhaustive search for facet below a point-- for Delaunay triangulations,- Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed- Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.-- returns:- returns first facet below point- if point is inside,- returns nearest facet- distance to facet- isoutside if point is outside of the hull- number of distance tests-- notes:- primarily for library users, rarely used by Qhull-*/-facetT *qh_findfacet_all(qhT *qh, pointT *point, realT *bestdist, boolT *isoutside,- int *numpart) {- facetT *bestfacet= NULL, *facet;- realT dist;- int totpart= 0;-- *bestdist= -REALmax;- *isoutside= False;- FORALLfacets {- if (facet->flipped || !facet->normal)- continue;- totpart++;- qh_distplane(qh, point, facet, &dist);- if (dist > *bestdist) {- *bestdist= dist;- bestfacet= facet;- if (dist > qh->MINoutside) {- *isoutside= True;- break;- }- }- }- *numpart= totpart;- trace3((qh, qh->ferr, 3016, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",- getid_(bestfacet), *bestdist, *isoutside, totpart));- return bestfacet;-} /* findfacet_all */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="findgood">-</a>-- qh_findgood(qh, facetlist, goodhorizon )- identify good facets for qh.PRINTgood- if qh.GOODvertex>0- facet includes point as vertex- if !match, returns goodhorizon- inactive if qh.MERGING- if qh.GOODpoint- facet is visible or coplanar (>0) or not visible (<0)- if qh.GOODthreshold- facet->normal matches threshold- if !goodhorizon and !match,- selects facet with closest angle- sets GOODclosest-- returns:- number of new, good facets found- determines facet->good- may update qh.GOODclosest-- notes:- qh_findgood_all further reduces the good region-- design:- count good facets- mark good facets for qh.GOODpoint- mark good facets for qh.GOODthreshold- if necessary- update qh.GOODclosest-*/-int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {- facetT *facet, *bestfacet= NULL;- realT angle, bestangle= REALmax, dist;- int numgood=0;-- FORALLfacet_(facetlist) {- if (facet->good)- numgood++;- }- if (qh->GOODvertex>0 && !qh->MERGING) {- FORALLfacet_(facetlist) {- if (!qh_isvertex(qh->GOODvertexp, facet->vertices)) {- facet->good= False;- numgood--;- }- }- }- if (qh->GOODpoint && numgood) {- FORALLfacet_(facetlist) {- if (facet->good && facet->normal) {- zinc_(Zdistgood);- qh_distplane(qh, qh->GOODpointp, facet, &dist);- if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {- facet->good= False;- numgood--;- }- }- }- }- if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {- FORALLfacet_(facetlist) {- if (facet->good && facet->normal) {- if (!qh_inthresholds(qh, facet->normal, &angle)) {- facet->good= False;- numgood--;- if (angle < bestangle) {- bestangle= angle;- bestfacet= facet;- }- }- }- }- if (!numgood && (!goodhorizon || qh->GOODclosest)) {- if (qh->GOODclosest) {- if (qh->GOODclosest->visible)- qh->GOODclosest= NULL;- else {- qh_inthresholds(qh, qh->GOODclosest->normal, &angle);- if (angle < bestangle)- bestfacet= qh->GOODclosest;- }- }- if (bestfacet && bestfacet != qh->GOODclosest) {- if (qh->GOODclosest)- qh->GOODclosest->good= False;- qh->GOODclosest= bestfacet;- bestfacet->good= True;- numgood++;- trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",- bestfacet->id, bestangle));- return numgood;- }- }else if (qh->GOODclosest) { /* numgood > 0 */- qh->GOODclosest->good= False;- qh->GOODclosest= NULL;- }- }- zadd_(Zgoodfacet, numgood);- trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon\n",- numgood, goodhorizon));- if (!numgood && qh->GOODvertex>0 && !qh->MERGING)- return goodhorizon;- return numgood;-} /* findgood */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="findgood_all">-</a>-- qh_findgood_all(qh, facetlist )- apply other constraints for good facets (used by qh.PRINTgood)- if qh.GOODvertex- facet includes (>0) or doesn't include (<0) point as vertex- if last good facet and ONLYgood, prints warning and continues- if qh.SPLITthresholds- facet->normal matches threshold, or if none, the closest one- calls qh_findgood- nop if good not used-- returns:- clears facet->good if not good- sets qh.num_good-- notes:- this is like qh_findgood but more restrictive-- design:- uses qh_findgood to mark good facets- marks facets for qh.GOODvertex- marks facets for qh.SPLITthreholds-*/-void qh_findgood_all(qhT *qh, facetT *facetlist) {- facetT *facet, *bestfacet=NULL;- realT angle, bestangle= REALmax;- int numgood=0, startgood;-- if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint- && !qh->SPLITthresholds)- return;- if (!qh->ONLYgood)- qh_findgood(qh, qh->facet_list, 0);- FORALLfacet_(facetlist) {- if (facet->good)- numgood++;- }- if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {- FORALLfacet_(facetlist) {- if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh->GOODvertexp, facet->vertices))) {- if (!--numgood) {- if (qh->ONLYgood) {- qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d. Ignored.\n",- qh_pointid(qh, qh->GOODvertexp), facet->id);- return;- }else if (qh->GOODvertex > 0)- qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",- qh->GOODvertex-1, qh->GOODvertex-1);- else- qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",- -qh->GOODvertex - 1, -qh->GOODvertex - 1);- }- facet->good= False;- }- }- }- startgood= numgood;- if (qh->SPLITthresholds) {- FORALLfacet_(facetlist) {- if (facet->good) {- if (!qh_inthresholds(qh, facet->normal, &angle)) {- facet->good= False;- numgood--;- if (angle < bestangle) {- bestangle= angle;- bestfacet= facet;- }- }- }- }- if (!numgood && bestfacet) {- bestfacet->good= True;- numgood++;- trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to thresholds\n",- bestfacet->id, bestangle));- return;- }- }- qh->num_good= numgood;- trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",- numgood, startgood));-} /* findgood_all */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="furthestnext">-</a>-- qh_furthestnext()- set qh.facet_next to facet with furthest of all furthest points- searches all facets on qh.facet_list-- notes:- this may help avoid precision problems-*/-void qh_furthestnext(qhT *qh /* qh->facet_list */) {- facetT *facet, *bestfacet= NULL;- realT dist, bestdist= -REALmax;-- FORALLfacets {- if (facet->outsideset) {-#if qh_COMPUTEfurthest- pointT *furthest;- furthest= (pointT*)qh_setlast(facet->outsideset);- zinc_(Zcomputefurthest);- qh_distplane(qh, furthest, facet, &dist);-#else- dist= facet->furthestdist;-#endif- if (dist > bestdist) {- bestfacet= facet;- bestdist= dist;- }- }- }- if (bestfacet) {- qh_removefacet(qh, bestfacet);- qh_prependfacet(qh, bestfacet, &qh->facet_next);- trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",- bestfacet->id, bestdist));- }-} /* furthestnext */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="furthestout">-</a>-- qh_furthestout(qh, facet )- make furthest outside point the last point of outsideset-- returns:- updates facet->outsideset- clears facet->notfurthest- sets facet->furthestdist-- design:- determine best point of outsideset- make it the last point of outsideset-*/-void qh_furthestout(qhT *qh, facetT *facet) {- pointT *point, **pointp, *bestpoint= NULL;- realT dist, bestdist= -REALmax;-- FOREACHpoint_(facet->outsideset) {- qh_distplane(qh, point, facet, &dist);- zinc_(Zcomputefurthest);- if (dist > bestdist) {- bestpoint= point;- bestdist= dist;- }- }- if (bestpoint) {- qh_setdel(facet->outsideset, point);- qh_setappend(qh, &facet->outsideset, point);-#if !qh_COMPUTEfurthest- facet->furthestdist= bestdist;-#endif- }- facet->notfurthest= False;- trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",- qh_pointid(qh, point), facet->id));-} /* furthestout */---/*-<a href="qh-qhull_r.htm#TOC"- >-------------------------------</a><a name="infiniteloop">-</a>-- qh_infiniteloop(qh, facet )- report infinite loop error due to facet-*/-void qh_infiniteloop(qhT *qh, facetT *facet) {-- qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");- qh_errexit(qh, qh_ERRqhull, facet, NULL);-} /* qh_infiniteloop */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="initbuild">-</a>-- qh_initbuild()- initialize hull and outside sets with point array- qh.FIRSTpoint/qh.NUMpoints is point array- if qh.GOODpoint- adds qh.GOODpoint to initial hull-- returns:- qh_facetlist with initial hull- points partioned into outside sets, coplanar sets, or inside- initializes qh.GOODpointp, qh.GOODvertexp,-- design:- initialize global variables used during qh_buildhull- determine precision constants and points with max/min coordinate values- if qh.SCALElast, scale last coordinate(for 'd')- build initial simplex- partition input points into facets of initial simplex- set up lists- if qh.ONLYgood- check consistency- add qh.GOODvertex if defined-*/-void qh_initbuild(qhT *qh) {- setT *maxpoints, *vertices;- facetT *facet;- int i, numpart;- realT dist;- boolT isoutside;-- qh->furthest_id= qh_IDunknown;- qh->lastreport= 0;- qh->facet_id= qh->vertex_id= qh->ridge_id= 0;- qh->visit_id= qh->vertex_visit= 0;- qh->maxoutdone= False;-- if (qh->GOODpoint > 0)- qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);- else if (qh->GOODpoint < 0)- qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);- if (qh->GOODvertex > 0)- qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);- else if (qh->GOODvertex < 0)- qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);- if ((qh->GOODpoint- && (qh->GOODpointp < qh->first_point /* also catches !GOODpointp */- || qh->GOODpointp > qh_point(qh, qh->num_points-1)))- || (qh->GOODvertex- && (qh->GOODvertexp < qh->first_point /* also catches !GOODvertexp */- || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {- qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",- qh->num_points-1);- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);- if (qh->SCALElast)- qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim,- qh->MINlastcoord, qh->MAXlastcoord, qh->MAXwidth);- qh_detroundoff(qh);- if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2- && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {- for (i=qh_PRINTEND; i--; ) {- if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0- && !qh->GOODthreshold && !qh->SPLITthresholds)- break; /* in this case, don't set upper_threshold */- }- if (i < 0) {- if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */- qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;- qh->GOODthreshold= True;- }else {- qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;- if (!qh->GOODthreshold)- qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */- /* qh_initqhull_globals errors if Qg without Pdk/etc. */- }- }- }- vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);- qh_initialhull(qh, vertices); /* initial qh->facet_list */- qh_partitionall(qh, vertices, qh->first_point, qh->num_points);- if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {- if (qh->TRACElevel || qh->IStracing)- qh_fprintf(qh, qh->ferr, 8103, "\nTrace level %d for %s | %s\n",- qh->IStracing ? qh->IStracing : qh->TRACElevel, qh->rbox_command, qh->qhull_command);- qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);- }- qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);- qh->facet_next= qh->facet_list;- qh_furthestnext(qh /* qh->facet_list */);- if (qh->PREmerge) {- qh->cos_max= qh->premerge_cos;- qh->centrum_radius= qh->premerge_centrum;- }- if (qh->ONLYgood) {- if (qh->GOODvertex > 0 && qh->MERGING) {- qh_fprintf(qh, qh->ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (!(qh->GOODthreshold || qh->GOODpoint- || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {- qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a\n\-good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (qh->GOODvertex > 0 && !qh->MERGING /* matches qh_partitionall */- && !qh_isvertex(qh->GOODvertexp, vertices)) {- facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,- &dist, !qh_ALL, &isoutside, &numpart);- zadd_(Zdistgood, numpart);- if (!isoutside) {- qh_fprintf(qh, qh->ferr, 6153, "qhull input error: point for QV%d is inside initial simplex. It can not be made a vertex.\n",- qh_pointid(qh, qh->GOODvertexp));- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {- qh_settempfree(qh, &vertices);- qh_settempfree(qh, &maxpoints);- return;- }- }- qh_findgood(qh, qh->facet_list, 0);- }- qh_settempfree(qh, &vertices);- qh_settempfree(qh, &maxpoints);- trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));-} /* initbuild */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="initialhull">-</a>-- qh_initialhull(qh, vertices )- constructs the initial hull as a DIM3 simplex of vertices-- design:- creates a simplex (initializes lists)- determines orientation of simplex- sets hyperplanes for facets- doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)- checks for flipped facets and qh.NARROWhull- checks the result-*/-void qh_initialhull(qhT *qh, setT *vertices) {- facetT *facet, *firstfacet, *neighbor, **neighborp;- realT dist, angle, minangle= REALmax;-#ifndef qh_NOtrace- int k;-#endif-- qh_createsimplex(qh, vertices); /* qh->facet_list */- qh_resetlists(qh, False, qh_RESETvisible);- qh->facet_next= qh->facet_list; /* advance facet when processed */- qh->interior_point= qh_getcenter(qh, vertices);- firstfacet= qh->facet_list;- qh_setfacetplane(qh, firstfacet);- zinc_(Znumvisibility); /* needs to be in printsummary */- qh_distplane(qh, qh->interior_point, firstfacet, &dist);- if (dist > 0) {- FORALLfacets- facet->toporient ^= (unsigned char)True;- }- FORALLfacets- qh_setfacetplane(qh, facet);- FORALLfacets {- if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {/* due to axis-parallel facet */- trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect. Correct all facets\n"));- facet->flipped= False;- FORALLfacets {- facet->toporient ^= (unsigned char)True;- qh_orientoutside(qh, facet);- }- break;- }- }- FORALLfacets {- if (!qh_checkflipped(qh, facet, NULL, !qh_ALL)) { /* can happen with 'R0.1' */- if (qh->DELAUNAY && ! qh->ATinfinity) {- if (qh->UPPERdelaunay)- qh_fprintf(qh, qh->ferr, 6240, "Qhull precision error: Initial simplex is cocircular or cospherical. Option 'Qs' searches all points. Can not compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");- else- qh_fprintf(qh, qh->ferr, 6239, "Qhull precision error: Initial simplex is cocircular or cospherical. Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points. Option 'Qz' adds a point \"at infinity\". Use option 'Qs' to search all points for the initial simplex.\n");- qh_errexit(qh, qh_ERRinput, NULL, NULL);- }- qh_precision(qh, "initial simplex is flat");- qh_fprintf(qh, qh->ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",- facet->id);- qh_errexit(qh, qh_ERRsingular, NULL, NULL); /* calls qh_printhelp_singular */- }- FOREACHneighbor_(facet) {- angle= qh_getangle(qh, facet->normal, neighbor->normal);- minimize_( minangle, angle);- }- }- if (minangle < qh_MAXnarrow && !qh->NOnarrow) {- realT diff= 1.0 + minangle;-- qh->NARROWhull= True;- qh_option(qh, "_narrow-hull", NULL, &diff);- if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)- qh_printhelp_narrowhull(qh, qh->ferr, minangle);- }- zzval_(Zprocessed)= qh->hull_dim+1;- qh_checkpolygon(qh, qh->facet_list);- qh_checkconvex(qh, qh->facet_list, qh_DATAfault);-#ifndef qh_NOtrace- if (qh->IStracing >= 1) {- qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed, interior point:");- for (k=0; k < qh->hull_dim; k++)- qh_fprintf(qh, qh->ferr, 8106, " %6.4g", qh->interior_point[k]);- qh_fprintf(qh, qh->ferr, 8107, "\n");- }-#endif-} /* initialhull */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="initialvertices">-</a>-- qh_initialvertices(qh, dim, maxpoints, points, numpoints )- determines a non-singular set of initial vertices- maxpoints may include duplicate points-- returns:- temporary set of dim+1 vertices in descending order by vertex id- if qh.RANDOMoutside && !qh.ALLpoints- picks random points- if dim >= qh_INITIALmax,- uses min/max x and max points with non-zero determinants-- notes:- unless qh.ALLpoints,- uses maxpoints as long as determinate is non-zero-*/-setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {- pointT *point, **pointp;- setT *vertices, *simplex, *tested;- realT randr;- int idx, point_i, point_n, k;- boolT nearzero= False;-- vertices= qh_settemp(qh, dim + 1);- simplex= qh_settemp(qh, dim+1);- if (qh->ALLpoints)- qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);- else if (qh->RANDOMoutside) {- while (qh_setsize(qh, simplex) != dim+1) {- randr= qh_RANDOMint;- randr= randr/(qh_RANDOMmax+1);- idx= (int)floor(qh->num_points * randr);- while (qh_setin(simplex, qh_point(qh, idx))) {- idx++; /* in case qh_RANDOMint always returns the same value */- idx= idx < qh->num_points ? idx : 0;- }- qh_setappend(qh, &simplex, qh_point(qh, idx));- }- }else if (qh->hull_dim >= qh_INITIALmax) {- tested= qh_settemp(qh, dim+1);- qh_setappend(qh, &simplex, SETfirst_(maxpoints)); /* max and min X coord */- qh_setappend(qh, &simplex, SETsecond_(maxpoints));- qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);- k= qh_setsize(qh, simplex);- FOREACHpoint_i_(qh, maxpoints) {- if (point_i & 0x1) { /* first pick up max. coord. points */- if (!qh_setin(simplex, point) && !qh_setin(tested, point)){- qh_detsimplex(qh, point, simplex, k, &nearzero);- if (nearzero)- qh_setappend(qh, &tested, point);- else {- qh_setappend(qh, &simplex, point);- if (++k == dim) /* use search for last point */- break;- }- }- }- }- while (k != dim && (point= (pointT*)qh_setdellast(maxpoints))) {- if (!qh_setin(simplex, point) && !qh_setin(tested, point)){- qh_detsimplex(qh, point, simplex, k, &nearzero);- if (nearzero)- qh_setappend(qh, &tested, point);- else {- qh_setappend(qh, &simplex, point);- k++;- }- }- }- idx= 0;- while (k != dim && (point= qh_point(qh, idx++))) {- if (!qh_setin(simplex, point) && !qh_setin(tested, point)){- qh_detsimplex(qh, point, simplex, k, &nearzero);- if (!nearzero){- qh_setappend(qh, &simplex, point);- k++;- }- }- }- qh_settempfree(qh, &tested);- qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);- }else- qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);- FOREACHpoint_(simplex)- qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */- qh_settempfree(qh, &simplex);- return vertices;-} /* initialvertices */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="isvertex">-</a>-- qh_isvertex( point, vertices )- returns vertex if point is in vertex set, else returns NULL-- notes:- for qh.GOODvertex-*/-vertexT *qh_isvertex(pointT *point, setT *vertices) {- vertexT *vertex, **vertexp;-- FOREACHvertex_(vertices) {- if (vertex->point == point)- return vertex;- }- return NULL;-} /* isvertex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="makenewfacets">-</a>-- qh_makenewfacets(qh, point )- make new facets from point and qh.visible_list-- returns:- qh.newfacet_list= list of new facets with hyperplanes and ->newfacet- qh.newvertex_list= list of vertices in new facets with ->newlist set-- if (qh.ONLYgood)- newfacets reference horizon facets, but not vice versa- ridges reference non-simplicial horizon ridges, but not vice versa- does not change existing facets- else- sets qh.NEWfacets- new facets attached to horizon facets and ridges- for visible facets,- visible->r.replace is corresponding new facet-- see also:- qh_makenewplanes() -- make hyperplanes for facets- qh_attachnewfacets() -- attachnewfacets if not done here(qh->ONLYgood)- qh_matchnewfacets() -- match up neighbors- qh_updatevertices() -- update vertex neighbors and delvertices- qh_deletevisible() -- delete visible facets- qh_checkpolygon() --check the result- qh_triangulate() -- triangulate a non-simplicial facet-- design:- for each visible facet- make new facets to its horizon facets- update its f.replace- clear its neighbor set-*/-vertexT *qh_makenewfacets(qhT *qh, pointT *point /*visible_list*/) {- facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;- vertexT *apex;- int numnew=0;-- qh->newfacet_list= qh->facet_tail;- qh->newvertex_list= qh->vertex_tail;- apex= qh_newvertex(qh, point);- qh_appendvertex(qh, apex);- qh->visit_id++;- if (!qh->ONLYgood)- qh->NEWfacets= True;- FORALLvisible_facets {- FOREACHneighbor_(visible)- neighbor->seen= False;- if (visible->ridges) {- visible->visitid= qh->visit_id;- newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);- }- if (visible->simplicial)- newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);- if (!qh->ONLYgood) {- if (newfacet2) /* newfacet is null if all ridges defined */- newfacet= newfacet2;- if (newfacet)- visible->f.replace= newfacet;- else- zinc_(Zinsidevisible);- SETfirst_(visible->neighbors)= NULL;- }- }- trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",- numnew, qh_pointid(qh, point)));- if (qh->IStracing >= 4)- qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);- return apex;-} /* makenewfacets */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="matchduplicates">-</a>-- qh_matchduplicates(qh, atfacet, atskip, hashsize, hashcount )- match duplicate ridges in qh.hash_table for atfacet/atskip- duplicates marked with ->dupridge and qh_DUPLICATEridge-- returns:- picks match with worst merge (min distance apart)- updates hashcount-- see also:- qh_matchneighbor-- notes:-- design:- compute hash value for atfacet and atskip- repeat twice -- once to make best matches, once to match the rest- for each possible facet in qh.hash_table- if it is a matching facet and pass 2- make match- unless tricoplanar, mark match for merging (qh_MERGEridge)- [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]- if it is a matching facet and pass 1- test if this is a better match- if pass 1,- make best match (it will not be merged)-*/-#ifndef qh_NOmerge-void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {- boolT same, ismatch;- int hash, scan;- facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;- int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;- realT maxdist= -REALmax, mindist, dist2, low, high;-- hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,- SETelem_(atfacet->vertices, atskip));- trace2((qh, qh->ferr, 2046, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",- atfacet->id, atskip, hash, *hashcount));- for (makematch= 0; makematch < 2; makematch++) {- qh->visit_id++;- for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {- zinc_(Zhashlookup);- nextfacet= NULL;- newfacet->visitid= qh->visit_id;- for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));- scan= (++scan >= hashsize ? 0 : scan)) {- if (!facet->dupridge || facet->visitid == qh->visit_id)- continue;- zinc_(Zhashtests);- if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {- ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));- if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {- if (!makematch) {- qh_fprintf(qh, qh->ferr, 6155, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",- facet->id, skip, newfacet->id, newskip, hash);- qh_errexit2(qh, qh_ERRqhull, facet, newfacet);- }- }else if (ismatch && makematch) {- if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {- SETelem_(facet->neighbors, skip)= newfacet;- if (newfacet->tricoplanar)- SETelem_(newfacet->neighbors, newskip)= facet;- else- SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;- *hashcount -= 2; /* removed two unmatched facets */- trace4((qh, qh->ferr, 4059, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",- facet->id, skip, newfacet->id, newskip));- }- }else if (ismatch) {- mindist= qh_getdistance(qh, facet, newfacet, &low, &high);- dist2= qh_getdistance(qh, newfacet, facet, &low, &high);- minimize_(mindist, dist2);- if (mindist > maxdist) {- maxdist= mindist;- maxmatch= facet;- maxskip= skip;- maxmatch2= newfacet;- maxskip2= newskip;- }- trace3((qh, qh->ferr, 3018, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",- facet->id, skip, newfacet->id, newskip, mindist,- maxmatch->id, maxmatch2->id));- }else { /* !ismatch */- nextfacet= facet;- nextskip= skip;- }- }- if (makematch && !facet- && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {- qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",- newfacet->id, newskip, hash);- qh_errexit(qh, qh_ERRqhull, newfacet, NULL);- }- }- } /* end of for each new facet at hash */- if (!makematch) {- if (!maxmatch) {- qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",- atfacet->id, atskip, hash);- qh_errexit(qh, qh_ERRqhull, atfacet, NULL);- }- SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=0 by QH6157 */- SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;- *hashcount -= 2; /* removed two unmatched facets */- zzinc_(Zmultiridge);- trace0((qh, qh->ferr, 25, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",- maxmatch->id, maxskip, maxmatch2->id, maxskip2));- qh_precision(qh, "ridge with multiple neighbors");- if (qh->IStracing >= 4)- qh_errprint(qh, "DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);- }- }-} /* matchduplicates */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="nearcoplanar">-</a>-- qh_nearcoplanar()- for all facets, remove near-inside points from facet->coplanarset</li>- coplanar points defined by innerplane from qh_outerinner()-- returns:- if qh->KEEPcoplanar && !qh->KEEPinside- facet->coplanarset only contains coplanar points- if qh.JOGGLEmax- drops inner plane by another qh.JOGGLEmax diagonal since a- vertex could shift out while a coplanar point shifts in-- notes:- used for qh.PREmerge and qh.JOGGLEmax- must agree with computation of qh.NEARcoplanar in qh_detroundoff(qh)- design:- if not keeping coplanar or inside points- free all coplanar sets- else if not keeping both coplanar and inside points- remove !coplanar or !inside points from coplanar sets-*/-void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {- facetT *facet;- pointT *point, **pointp;- int numpart;- realT dist, innerplane;-- if (!qh->KEEPcoplanar && !qh->KEEPinside) {- FORALLfacets {- if (facet->coplanarset)- qh_setfree(qh, &facet->coplanarset);- }- }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {- qh_outerinner(qh, NULL, NULL, &innerplane);- if (qh->JOGGLEmax < REALmax/2)- innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);- numpart= 0;- FORALLfacets {- if (facet->coplanarset) {- FOREACHpoint_(facet->coplanarset) {- numpart++;- qh_distplane(qh, point, facet, &dist);- if (dist < innerplane) {- if (!qh->KEEPinside)- SETref_(point)= NULL;- }else if (!qh->KEEPcoplanar)- SETref_(point)= NULL;- }- qh_setcompact(qh, facet->coplanarset);- }- }- zzadd_(Zcheckpart, numpart);- }-} /* nearcoplanar */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="nearvertex">-</a>-- qh_nearvertex(qh, facet, point, bestdist )- return nearest vertex in facet to point-- returns:- vertex and its distance-- notes:- if qh.DELAUNAY- distance is measured in the input set- searches neighboring tricoplanar facets (requires vertexneighbors)- Slow implementation. Recomputes vertex set for each point.- The vertex set could be stored in the qh.keepcentrum facet.-*/-vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {- realT bestdist= REALmax, dist;- vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;- coordT *center;- facetT *neighbor, **neighborp;- setT *vertices;- int dim= qh->hull_dim;-- if (qh->DELAUNAY)- dim--;- if (facet->tricoplanar) {- if (!qh->VERTEXneighbors || !facet->center) {- qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- vertices= qh_settemp(qh, qh->TEMPsize);- apex= SETfirstt_(facet->vertices, vertexT);- center= facet->center;- FOREACHneighbor_(apex) {- if (neighbor->center == center) {- FOREACHvertex_(neighbor->vertices)- qh_setappend(qh, &vertices, vertex);- }- }- }else- vertices= facet->vertices;- FOREACHvertex_(vertices) {- dist= qh_pointdist(vertex->point, point, -dim);- if (dist < bestdist) {- bestdist= dist;- bestvertex= vertex;- }- }- if (facet->tricoplanar)- qh_settempfree(qh, &vertices);- *bestdistp= sqrt(bestdist);- if (!bestvertex) {- qh_fprintf(qh, qh->ferr, 6261, "qhull internal error (qh_nearvertex): did not find bestvertex for f%d p%d\n", facet->id, qh_pointid(qh, point));- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",- bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point))); /* bestvertex!=0 by QH2161 */- return bestvertex;-} /* nearvertex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="newhashtable">-</a>-- qh_newhashtable(qh, newsize )- returns size of qh.hash_table of at least newsize slots-- notes:- assumes qh.hash_table is NULL- qh_HASHfactor determines the number of extra slots- size is not divisible by 2, 3, or 5-*/-int qh_newhashtable(qhT *qh, int newsize) {- int size;-- size= ((newsize+1)*qh_HASHfactor) | 0x1; /* odd number */- while (True) {- if (newsize<0 || size<0) {- qh_fprintf(qh, qh->qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d). Did int overflow due to high-D?\n", newsize, size); /* WARN64 */- qh_errexit(qh, qhmem_ERRmem, NULL, NULL);- }- if ((size%3) && (size%5))- break;- size += 2;- /* loop terminates because there is an infinite number of primes */- }- qh->hash_table= qh_setnew(qh, size);- qh_setzero(qh, qh->hash_table, 0, size);- return size;-} /* newhashtable */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="newvertex">-</a>-- qh_newvertex(qh, point )- returns a new vertex for point-*/-vertexT *qh_newvertex(qhT *qh, pointT *point) {- vertexT *vertex;-- zinc_(Ztotvertices);- vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));- memset((char *) vertex, (size_t)0, sizeof(vertexT));- if (qh->vertex_id == UINT_MAX) {- qh_memfree(qh, vertex, (int)sizeof(vertexT));- qh_fprintf(qh, qh->ferr, 6159, "qhull error: more than 2^32 vertices. vertexT.id field overflows. Vertices would not be sorted correctly.\n");- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- if (qh->vertex_id == qh->tracevertex_id)- qh->tracevertex= vertex;- vertex->id= qh->vertex_id++;- vertex->point= point;- trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),- vertex->id));- return(vertex);-} /* newvertex */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="nextridge3d">-</a>-- qh_nextridge3d( atridge, facet, vertex )- return next ridge and vertex for a 3d facet- returns NULL on error- [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.-- notes:- in qh_ORIENTclock order- this is a O(n^2) implementation to trace all ridges- be sure to stop on any 2nd visit- same as QhullRidge::nextRidge3d- does not use qhT or qh_errexit [QhullFacet.cpp]-- design:- for each ridge- exit if it is the ridge after atridge-*/-ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {- vertexT *atvertex, *vertex, *othervertex;- ridgeT *ridge, **ridgep;-- if ((atridge->top == facet) ^ qh_ORIENTclock)- atvertex= SETsecondt_(atridge->vertices, vertexT);- else- atvertex= SETfirstt_(atridge->vertices, vertexT);- FOREACHridge_(facet->ridges) {- if (ridge == atridge)- continue;- if ((ridge->top == facet) ^ qh_ORIENTclock) {- othervertex= SETsecondt_(ridge->vertices, vertexT);- vertex= SETfirstt_(ridge->vertices, vertexT);- }else {- vertex= SETsecondt_(ridge->vertices, vertexT);- othervertex= SETfirstt_(ridge->vertices, vertexT);- }- if (vertex == atvertex) {- if (vertexp)- *vertexp= othervertex;- return ridge;- }- }- return NULL;-} /* nextridge3d */-#else /* qh_NOmerge */-void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {-}-ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {-- return NULL;-}-#endif /* qh_NOmerge */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="outcoplanar">-</a>-- qh_outcoplanar()- move points from all facets' outsidesets to their coplanarsets-- notes:- for post-processing under qh.NARROWhull-- design:- for each facet- for each outside point for facet- partition point into coplanar set-*/-void qh_outcoplanar(qhT *qh /* facet_list */) {- pointT *point, **pointp;- facetT *facet;- realT dist;-- trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));- FORALLfacets {- FOREACHpoint_(facet->outsideset) {- qh->num_outside--;- if (qh->KEEPcoplanar || qh->KEEPnearinside) {- qh_distplane(qh, point, facet, &dist);- zinc_(Zpartition);- qh_partitioncoplanar(qh, point, facet, &dist);- }- }- qh_setfree(qh, &facet->outsideset);- }-} /* outcoplanar */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="point">-</a>-- qh_point(qh, id )- return point for a point id, or NULL if unknown-- alternative code:- return((pointT *)((unsigned long)qh.first_point- + (unsigned long)((id)*qh.normal_size)));-*/-pointT *qh_point(qhT *qh, int id) {-- if (id < 0)- return NULL;- if (id < qh->num_points)- return qh->first_point + id * qh->hull_dim;- id -= qh->num_points;- if (id < qh_setsize(qh, qh->other_points))- return SETelemt_(qh->other_points, id, pointT);- return NULL;-} /* point */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="point_add">-</a>-- qh_point_add(qh, set, point, elem )- stores elem at set[point.id]-- returns:- access function for qh_pointfacet and qh_pointvertex-- notes:- checks point.id-*/-void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {- int id, size;-- SETreturnsize_(set, size);- if ((id= qh_pointid(qh, point)) < 0)- qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",- point, id);- else if (id >= size) {- qh_fprintf(qh, qh->ferr, 6160, "qhull internal errror(point_add): point p%d is out of bounds(%d)\n",- id, size);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }else- SETelem_(set, id)= elem;-} /* point_add */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="pointfacet">-</a>-- qh_pointfacet()- return temporary set of facet for each point- the set is indexed by point id-- notes:- vertices assigned to one of the facets- coplanarset assigned to the facet- outside set assigned to the facet- NULL if no facet for point (inside)- includes qh.GOODpointp-- access:- FOREACHfacet_i_(qh, facets) { ... }- SETelem_(facets, i)-- design:- for each facet- add each vertex- add each coplanar point- add each outside point-*/-setT *qh_pointfacet(qhT *qh /*qh.facet_list*/) {- int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);- setT *facets;- facetT *facet;- vertexT *vertex, **vertexp;- pointT *point, **pointp;-- facets= qh_settemp(qh, numpoints);- qh_setzero(qh, facets, 0, numpoints);- qh->vertex_visit++;- FORALLfacets {- FOREACHvertex_(facet->vertices) {- if (vertex->visitid != qh->vertex_visit) {- vertex->visitid= qh->vertex_visit;- qh_point_add(qh, facets, vertex->point, facet);- }- }- FOREACHpoint_(facet->coplanarset)- qh_point_add(qh, facets, point, facet);- FOREACHpoint_(facet->outsideset)- qh_point_add(qh, facets, point, facet);- }- return facets;-} /* pointfacet */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="pointvertex">-</a>-- qh_pointvertex(qh, )- return temporary set of vertices indexed by point id- entry is NULL if no vertex for a point- this will include qh.GOODpointp-- access:- FOREACHvertex_i_(qh, vertices) { ... }- SETelem_(vertices, i)-*/-setT *qh_pointvertex(qhT *qh /*qh.facet_list*/) {- int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);- setT *vertices;- vertexT *vertex;-- vertices= qh_settemp(qh, numpoints);- qh_setzero(qh, vertices, 0, numpoints);- FORALLvertices- qh_point_add(qh, vertices, vertex->point, vertex);- return vertices;-} /* pointvertex */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="prependfacet">-</a>-- qh_prependfacet(qh, facet, facetlist )- prepend facet to the start of a facetlist-- returns:- increments qh.numfacets- updates facetlist, qh.facet_list, facet_next-- notes:- be careful of prepending since it can lose a pointer.- e.g., can lose _next by deleting and then prepending before _next-*/-void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {- facetT *prevfacet, *list;--- trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",- facet->id, getid_(*facetlist)));- if (!*facetlist)- (*facetlist)= qh->facet_tail;- list= *facetlist;- prevfacet= list->previous;- facet->previous= prevfacet;- if (prevfacet)- prevfacet->next= facet;- list->previous= facet;- facet->next= *facetlist;- if (qh->facet_list == list) /* this may change *facetlist */- qh->facet_list= facet;- if (qh->facet_next == list)- qh->facet_next= facet;- *facetlist= facet;- qh->num_facets++;-} /* prependfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="printhashtable">-</a>-- qh_printhashtable(qh, fp )- print hash table to fp-- notes:- not in I/O to avoid bringing io_r.c in-- design:- for each hash entry- if defined- if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)- print entry and neighbors-*/-void qh_printhashtable(qhT *qh, FILE *fp) {- facetT *facet, *neighbor;- int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;- vertexT *vertex, **vertexp;-- FOREACHfacet_i_(qh, qh->hash_table) {- if (facet) {- FOREACHneighbor_i_(qh, facet) {- if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)- break;- }- if (neighbor_i == neighbor_n)- continue;- qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);- FOREACHvertex_(facet->vertices)- qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);- qh_fprintf(qh, fp, 9285, "\n neighbors:");- FOREACHneighbor_i_(qh, facet) {- if (neighbor == qh_MERGEridge)- id= -3;- else if (neighbor == qh_DUPLICATEridge)- id= -2;- else- id= getid_(neighbor);- qh_fprintf(qh, fp, 9286, " %d", id);- }- qh_fprintf(qh, fp, 9287, "\n");- }- }-} /* printhashtable */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="printlists">-</a>-- qh_printlists(qh, fp )- print out facet and vertex list for debugging (without 'f/v' tags)-*/-void qh_printlists(qhT *qh) {- facetT *facet;- vertexT *vertex;- int count= 0;-- qh_fprintf(qh, qh->ferr, 8108, "qh_printlists: facets:");- FORALLfacets {- if (++count % 100 == 0)- qh_fprintf(qh, qh->ferr, 8109, "\n ");- qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);- }- qh_fprintf(qh, qh->ferr, 8111, "\n new facets %d visible facets %d next facet for qh_addpoint %d\n vertices(new %d):",- getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_next),- getid_(qh->newvertex_list));- count = 0;- FORALLvertices {- if (++count % 100 == 0)- qh_fprintf(qh, qh->ferr, 8112, "\n ");- qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);- }- qh_fprintf(qh, qh->ferr, 8114, "\n");-} /* printlists */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="resetlists">-</a>-- qh_resetlists(qh, stats, qh_RESETvisible )- reset newvertex_list, newfacet_list, visible_list- if stats,- maintains statistics-- returns:- visible_list is empty if qh_deletevisible was called-*/-void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/) {- vertexT *vertex;- facetT *newfacet, *visible;- int totnew=0, totver=0;-- if (stats) {- FORALLvertex_(qh->newvertex_list)- totver++;- FORALLnew_facets- totnew++;- zadd_(Zvisvertextot, totver);- zmax_(Zvisvertexmax, totver);- zadd_(Znewfacettot, totnew);- zmax_(Znewfacetmax, totnew);- }- FORALLvertex_(qh->newvertex_list)- vertex->newlist= False;- qh->newvertex_list= NULL;- FORALLnew_facets- newfacet->newfacet= False;- qh->newfacet_list= NULL;- if (resetVisible) {- FORALLvisible_facets {- visible->f.replace= NULL;- visible->visible= False;- }- qh->num_visible= 0;- }- qh->visible_list= NULL; /* may still have visible facets via qh_triangulate */- qh->NEWfacets= False;-} /* resetlists */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="setvoronoi_all">-</a>-- qh_setvoronoi_all(qh)- compute Voronoi centers for all facets- includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')-- returns:- facet->center is the Voronoi center-- notes:- this is unused/untested code- please email bradb@shore.net if this works ok for you-- use:- FORALLvertices {...} to locate the vertex for a point.- FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.-*/-void qh_setvoronoi_all(qhT *qh) {- facetT *facet;-- qh_clearcenters(qh, qh_ASvoronoi);- qh_vertexneighbors(qh);-- FORALLfacets {- if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {- if (!facet->center)- facet->center= qh_facetcenter(qh, facet->vertices);- }- }-} /* setvoronoi_all */--#ifndef qh_NOmerge--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="triangulate">-</a>-- qh_triangulate()- triangulate non-simplicial facets on qh.facet_list,- if qh->VORONOI, sets Voronoi centers of non-simplicial facets- nop if hasTriangulation-- returns:- all facets simplicial- each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.-- notes:- call after qh_check_output since may switch to Voronoi centers- Output may overwrite ->f.triowner with ->f.area-*/-void qh_triangulate(qhT *qh /*qh.facet_list*/) {- facetT *facet, *nextfacet, *owner;- int onlygood= qh->ONLYgood;- facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;- facetT *orig_neighbor= NULL, *otherfacet;- vertexT *new_vertex_list= NULL;- mergeT *merge;- mergeType mergetype;- int neighbor_i, neighbor_n;-- if (qh->hasTriangulation)- return;- trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));- if (qh->hull_dim == 2)- return;- if (qh->VORONOI) { /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */- qh_clearcenters(qh, qh_ASvoronoi);- qh_vertexneighbors(qh);- }- qh->ONLYgood= False; /* for makenew_nonsimplicial */- qh->visit_id++;- qh->NEWfacets= True;- qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);- qh->newvertex_list= qh->vertex_tail;- for (facet= qh->facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */- nextfacet= facet->next;- if (facet->visible || facet->simplicial)- continue;- /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */- if (!new_facet_list)- new_facet_list= facet; /* will be moved to end */- qh_triangulate_facet(qh, facet, &new_vertex_list);- }- trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));- for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */- nextfacet= facet->next;- if (facet->visible)- continue;- if (facet->ridges) {- if (qh_setsize(qh, facet->ridges) > 0) {- qh_fprintf(qh, qh->ferr, 6161, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);- qh_errexit(qh, qh_ERRqhull, facet, NULL);- }- qh_setfree(qh, &facet->ridges);- }- if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {- zinc_(Ztrinull);- qh_triangulate_null(qh, facet);- }- }- trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh, qh->degen_mergeset)));- qh->visible_list= qh->facet_tail;- while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {- facet1= merge->facet1;- facet2= merge->facet2;- mergetype= merge->type;- qh_memfree(qh, merge, (int)sizeof(mergeT));- if (mergetype == MRGmirror) {- zinc_(Ztrimirror);- qh_triangulate_mirror(qh, facet1, facet2);- }- }- qh_settempfree(qh, &qh->degen_mergeset);- trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));- qh->newvertex_list= new_vertex_list; /* all vertices of new facets */- qh->visible_list= NULL;- qh_updatevertices(qh /*qh.newvertex_list, empty newfacet_list and visible_list*/);- qh_resetlists(qh, False, !qh_RESETvisible /*qh.newvertex_list, empty newfacet_list and visible_list*/);-- trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));- trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));- FORALLfacet_(new_facet_list) {- if (facet->tricoplanar && !facet->visible) {- FOREACHneighbor_i_(qh, facet) {- if (neighbor_i == 0) { /* first iteration */- if (neighbor->tricoplanar)- orig_neighbor= neighbor->f.triowner;- else- orig_neighbor= neighbor;- }else {- if (neighbor->tricoplanar)- otherfacet= neighbor->f.triowner;- else- otherfacet= neighbor;- if (orig_neighbor == otherfacet) {- zinc_(Ztridegen);- facet->degenerate= True;- break;- }- }- }- }- }-- trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));- owner= NULL;- visible= NULL;- for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */- nextfacet= facet->next;- if (facet->visible) {- if (facet->tricoplanar) { /* a null or mirrored facet */- qh_delfacet(qh, facet);- qh->num_visible--;- }else { /* a non-simplicial facet followed by its tricoplanars */- if (visible && !owner) {- /* RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */- trace2((qh, qh->ferr, 2053, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",- visible->id));- qh_delfacet(qh, visible);- qh->num_visible--;- }- visible= facet;- owner= NULL;- }- }else if (facet->tricoplanar) {- if (facet->f.triowner != visible || visible==NULL) {- qh_fprintf(qh, qh->ferr, 6162, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));- qh_errexit2(qh, qh_ERRqhull, facet, visible);- }- if (owner)- facet->f.triowner= owner;- else if (!facet->degenerate) {- owner= facet;- nextfacet= visible->next; /* rescan tricoplanar facets with owner, visible!=0 by QH6162 */- facet->keepcentrum= True; /* one facet owns ->normal, etc. */- facet->coplanarset= visible->coplanarset;- facet->outsideset= visible->outsideset;- visible->coplanarset= NULL;- visible->outsideset= NULL;- if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */- visible->center= NULL;- visible->normal= NULL;- }- qh_delfacet(qh, visible);- qh->num_visible--;- }- }- }- if (visible && !owner) {- trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",- visible->id));- qh_delfacet(qh, visible);- qh->num_visible--;- }- qh->NEWfacets= False;- qh->ONLYgood= onlygood; /* restore value */- if (qh->CHECKfrequently)- qh_checkpolygon(qh, qh->facet_list);- qh->hasTriangulation= True;-} /* triangulate */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="triangulate_facet">-</a>-- qh_triangulate_facet(qh, facetA, &firstVertex )- triangulate a non-simplicial facet- if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center- returns:- qh.newfacet_list == simplicial facets- facet->tricoplanar set and ->keepcentrum false- facet->degenerate set if duplicated apex- facet->f.trivisible set to facetA- facet->center copied from facetA (created if qh_ASvoronoi)- qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied- facet->normal,offset,maxoutside copied from facetA-- notes:- only called by qh_triangulate- qh_makenew_nonsimplicial uses neighbor->seen for the same- if qh.TRInormals, newfacet->normal will need qh_free- if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free- keepcentrum is also set on Zwidefacet in qh_mergefacet- freed by qh_clearcenters-- see also:- qh_addpoint() -- add a point- qh_makenewfacets() -- construct a cone of facets for a new vertex-- design:- if qh_ASvoronoi,- compute Voronoi center (facet->center)- select first vertex (highest ID to preserve ID ordering of ->vertices)- triangulate from vertex to ridges- copy facet->center, normal, offset- update vertex neighbors-*/-void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {- facetT *newfacet;- facetT *neighbor, **neighborp;- vertexT *apex;- int numnew=0;-- trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));-- if (qh->IStracing >= 4)- qh_printfacet(qh, qh->ferr, facetA);- FOREACHneighbor_(facetA) {- neighbor->seen= False;- neighbor->coplanar= False;- }- if (qh->CENTERtype == qh_ASvoronoi && !facetA->center /* matches upperdelaunay in qh_setfacetplane() */- && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {- facetA->center= qh_facetcenter(qh, facetA->vertices);- }- qh_willdelete(qh, facetA, NULL);- qh->newfacet_list= qh->facet_tail;- facetA->visitid= qh->visit_id;- apex= SETfirstt_(facetA->vertices, vertexT);- qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);- SETfirst_(facetA->neighbors)= NULL;- FORALLnew_facets {- newfacet->tricoplanar= True;- newfacet->f.trivisible= facetA;- newfacet->degenerate= False;- newfacet->upperdelaunay= facetA->upperdelaunay;- newfacet->good= facetA->good;- if (qh->TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */- newfacet->keepcentrum= True;- if(facetA->normal){- newfacet->normal= qh_memalloc(qh, qh->normal_size);- memcpy((char *)newfacet->normal, facetA->normal, qh->normal_size);- }- if (qh->CENTERtype == qh_AScentrum)- newfacet->center= qh_getcentrum(qh, newfacet);- else if (qh->CENTERtype == qh_ASvoronoi && facetA->center){- newfacet->center= qh_memalloc(qh, qh->center_size);- memcpy((char *)newfacet->center, facetA->center, qh->center_size);- }- }else {- newfacet->keepcentrum= False;- /* one facet will have keepcentrum=True at end of qh_triangulate */- newfacet->normal= facetA->normal;- newfacet->center= facetA->center;- }- newfacet->offset= facetA->offset;-#if qh_MAXoutside- newfacet->maxoutside= facetA->maxoutside;-#endif- }- qh_matchnewfacets(qh /*qh.newfacet_list*/);- zinc_(Ztricoplanar);- zadd_(Ztricoplanartot, numnew);- zmax_(Ztricoplanarmax, numnew);- qh->visible_list= NULL;- if (!(*first_vertex))- (*first_vertex)= qh->newvertex_list;- qh->newvertex_list= NULL;- qh_updatevertices(qh /*qh.newfacet_list, qh.empty visible_list and qh.newvertex_list*/);- qh_resetlists(qh, False, !qh_RESETvisible /*qh.newfacet_list, qh.empty visible_list and qh.newvertex_list*/);-} /* triangulate_facet */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="triangulate_link">-</a>-- qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)- relink facetA to facetB via oldfacets- returns:- adds mirror facets to qh->degen_mergeset (4-d and up only)- design:- if they are already neighbors, the opposing neighbors become MRGmirror facets-*/-void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {- int errmirror= False;-- trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n",- oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));- if (qh_setin(facetA->neighbors, facetB)) {- if (!qh_setin(facetB->neighbors, facetA))- errmirror= True;- else- qh_appendmergeset(qh, facetA, facetB, MRGmirror, NULL);- }else if (qh_setin(facetB->neighbors, facetA))- errmirror= True;- if (errmirror) {- qh_fprintf(qh, qh->ferr, 6163, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",- facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);- qh_errexit2(qh, qh_ERRqhull, facetA, facetB);- }- qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);- qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);-} /* triangulate_link */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="triangulate_mirror">-</a>-- qh_triangulate_mirror(qh, facetA, facetB)- delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror- a mirrored facet shares the same vertices of a logical ridge- design:- since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet- if they are already neighbors, the opposing neighbors become MRGmirror facets-*/-void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {- facetT *neighbor, *neighborB;- int neighbor_i, neighbor_n;-- trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n",- facetA->id, facetB->id));- FOREACHneighbor_i_(qh, facetA) {- neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);- if (neighbor == neighborB)- continue; /* occurs twice */- qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);- }- qh_willdelete(qh, facetA, NULL);- qh_willdelete(qh, facetB, NULL);-} /* triangulate_mirror */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="triangulate_null">-</a>-- qh_triangulate_null(qh, facetA)- remove null facetA from qh_triangulate_facet()- a null facet has vertex #1 (apex) == vertex #2- returns:- adds facetA to ->visible for deletion after qh_updatevertices- qh->degen_mergeset contains mirror facets (4-d and up only)- design:- since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet- if they are already neighbors, the opposing neighbors become MRGmirror facets-*/-void qh_triangulate_null(qhT *qh, facetT *facetA) {- facetT *neighbor, *otherfacet;-- trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));- neighbor= SETfirstt_(facetA->neighbors, facetT);- otherfacet= SETsecondt_(facetA->neighbors, facetT);- qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);- qh_willdelete(qh, facetA, NULL);-} /* triangulate_null */--#else /* qh_NOmerge */-void qh_triangulate(qhT *qh) {-}-#endif /* qh_NOmerge */-- /*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="vertexintersect">-</a>-- qh_vertexintersect(qh, vertexsetA, vertexsetB )- intersects two vertex sets (inverse id ordered)- vertexsetA is a temporary set at the top of qh->qhmem.tempstack-- returns:- replaces vertexsetA with the intersection-- notes:- could overwrite vertexsetA if currently too slow-*/-void qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB) {- setT *intersection;-- intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);- qh_settempfree(qh, vertexsetA);- *vertexsetA= intersection;- qh_settemppush(qh, intersection);-} /* vertexintersect */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="vertexintersect_new">-</a>-- qh_vertexintersect_new(qh, )- intersects two vertex sets (inverse id ordered)-- returns:- a new set-*/-setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB) {- setT *intersection= qh_setnew(qh, qh->hull_dim - 1);- vertexT **vertexA= SETaddr_(vertexsetA, vertexT);- vertexT **vertexB= SETaddr_(vertexsetB, vertexT);-- while (*vertexA && *vertexB) {- if (*vertexA == *vertexB) {- qh_setappend(qh, &intersection, *vertexA);- vertexA++; vertexB++;- }else {- if ((*vertexA)->id > (*vertexB)->id)- vertexA++;- else- vertexB++;- }- }- return intersection;-} /* vertexintersect_new */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="vertexneighbors">-</a>-- qh_vertexneighbors(qh)- for each vertex in qh.facet_list,- determine its neighboring facets-- returns:- sets qh.VERTEXneighbors- nop if qh.VERTEXneighbors already set- qh_addpoint() will maintain them-- notes:- assumes all vertex->neighbors are NULL-- design:- for each facet- for each vertex- append facet to vertex->neighbors-*/-void qh_vertexneighbors(qhT *qh /*qh.facet_list*/) {- facetT *facet;- vertexT *vertex, **vertexp;-- if (qh->VERTEXneighbors)- return;- trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));- qh->vertex_visit++;- FORALLfacets {- if (facet->visible)- continue;- FOREACHvertex_(facet->vertices) {- if (vertex->visitid != qh->vertex_visit) {- vertex->visitid= qh->vertex_visit;- vertex->neighbors= qh_setnew(qh, qh->hull_dim);- }- qh_setappend(qh, &vertex->neighbors, facet);- }- }- qh->VERTEXneighbors= True;-} /* vertexneighbors */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="vertexsubset">-</a>-- qh_vertexsubset( vertexsetA, vertexsetB )- returns True if vertexsetA is a subset of vertexsetB- assumes vertexsets are sorted-- note:- empty set is a subset of any other set-*/-boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {- vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);- vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);-- while (True) {- if (!*vertexA)- return True;- if (!*vertexB)- return False;- if ((*vertexA)->id > (*vertexB)->id)- return False;- if (*vertexA == *vertexB)- vertexA++;- vertexB++;- }- return False; /* avoid warnings */-} /* vertexsubset */
− C/poly_r.c
@@ -1,1205 +0,0 @@-/*<html><pre> -<a href="qh-poly_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- poly_r.c- implements polygons and simplices-- see qh-poly_r.htm, poly_r.h and libqhull_r.h-- infrequent code is in poly2_r.c- (all but top 50 and their callers 12/3/95)-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/poly_r.c#3 $$Change: 2064 $- $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $-*/--#include "qhull_ra.h"--/*======== functions in alphabetical order ==========*/--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="appendfacet">-</a>-- qh_appendfacet(qh, facet )- appends facet to end of qh.facet_list,-- returns:- updates qh.newfacet_list, facet_next, facet_list- increments qh.numfacets-- notes:- assumes qh.facet_list/facet_tail is defined (createsimplex)-- see:- qh_removefacet()--*/-void qh_appendfacet(qhT *qh, facetT *facet) {- facetT *tail= qh->facet_tail;-- if (tail == qh->newfacet_list)- qh->newfacet_list= facet;- if (tail == qh->facet_next)- qh->facet_next= facet;- facet->previous= tail->previous;- facet->next= tail;- if (tail->previous)- tail->previous->next= facet;- else- qh->facet_list= facet;- tail->previous= facet;- qh->num_facets++;- trace4((qh, qh->ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));-} /* appendfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="appendvertex">-</a>-- qh_appendvertex(qh, vertex )- appends vertex to end of qh.vertex_list,-- returns:- sets vertex->newlist- updates qh.vertex_list, newvertex_list- increments qh.num_vertices-- notes:- assumes qh.vertex_list/vertex_tail is defined (createsimplex)--*/-void qh_appendvertex(qhT *qh, vertexT *vertex) {- vertexT *tail= qh->vertex_tail;-- if (tail == qh->newvertex_list)- qh->newvertex_list= vertex;- vertex->newlist= True;- vertex->previous= tail->previous;- vertex->next= tail;- if (tail->previous)- tail->previous->next= vertex;- else- qh->vertex_list= vertex;- tail->previous= vertex;- qh->num_vertices++;- trace4((qh, qh->ferr, 4045, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));-} /* appendvertex */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="attachnewfacets">-</a>-- qh_attachnewfacets(qh, )- attach horizon facets to new facets in qh.newfacet_list- newfacets have neighbor and ridge links to horizon but not vice versa- only needed for qh.ONLYgood-- returns:- set qh.NEWfacets- horizon facets linked to new facets- ridges changed from visible facets to new facets- simplicial ridges deleted- qh.visible_list, no ridges valid- facet->f.replace is a newfacet (if any)-- design:- delete interior ridges and neighbor sets by- for each visible, non-simplicial facet- for each ridge- if last visit or if neighbor is simplicial- if horizon neighbor- delete ridge for horizon's ridge set- delete ridge- erase neighbor set- attach horizon facets and new facets by- for all new facets- if corresponding horizon facet is simplicial- locate corresponding visible facet {may be more than one}- link visible facet to new facet- replace visible facet with new facet in horizon- else it's non-simplicial- for all visible neighbors of the horizon facet- link visible neighbor to new facet- delete visible neighbor from horizon facet- append new facet to horizon's neighbors- the first ridge of the new facet is the horizon ridge- link the new facet into the horizon ridge-*/-void qh_attachnewfacets(qhT *qh /* qh.visible_list, newfacet_list */) {- facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;- ridgeT *ridge, **ridgep;-- qh->NEWfacets= True;- trace3((qh, qh->ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));- qh->visit_id++;- FORALLvisible_facets {- visible->visitid= qh->visit_id;- if (visible->ridges) {- FOREACHridge_(visible->ridges) {- neighbor= otherfacet_(ridge, visible);- if (neighbor->visitid == qh->visit_id- || (!neighbor->visible && neighbor->simplicial)) {- if (!neighbor->visible) /* delete ridge for simplicial horizon */- qh_setdel(neighbor->ridges, ridge);- qh_setfree(qh, &(ridge->vertices)); /* delete on 2nd visit */- qh_memfree(qh, ridge, (int)sizeof(ridgeT));- }- }- SETfirst_(visible->ridges)= NULL;- }- SETfirst_(visible->neighbors)= NULL;- }- trace1((qh, qh->ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));- FORALLnew_facets {- horizon= SETfirstt_(newfacet->neighbors, facetT);- if (horizon->simplicial) {- visible= NULL;- FOREACHneighbor_(horizon) { /* may have more than one horizon ridge */- if (neighbor->visible) {- if (visible) {- if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,- SETindex_(horizon->neighbors, neighbor))) {- visible= neighbor;- break;- }- }else- visible= neighbor;- }- }- if (visible) {- visible->f.replace= newfacet;- qh_setreplace(qh, horizon->neighbors, visible, newfacet);- }else {- qh_fprintf(qh, qh->ferr, 6102, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",- horizon->id, newfacet->id);- qh_errexit2(qh, qh_ERRqhull, horizon, newfacet);- }- }else { /* non-simplicial, with a ridge for newfacet */- FOREACHneighbor_(horizon) { /* may hold for many new facets */- if (neighbor->visible) {- neighbor->f.replace= newfacet;- qh_setdelnth(qh, horizon->neighbors,- SETindex_(horizon->neighbors, neighbor));- neighborp--; /* repeat */- }- }- qh_setappend(qh, &horizon->neighbors, newfacet);- ridge= SETfirstt_(newfacet->ridges, ridgeT);- if (ridge->top == horizon)- ridge->bottom= newfacet;- else- ridge->top= newfacet;- }- } /* newfacets */- if (qh->PRINTstatistics) {- FORALLvisible_facets {- if (!visible->f.replace)- zinc_(Zinsidevisible);- }- }-} /* attachnewfacets */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="checkflipped">-</a>-- qh_checkflipped(qh, facet, dist, allerror )- checks facet orientation to interior point-- if allerror set,- tests against qh.DISTround- else- tests against 0 since tested against DISTround before-- returns:- False if it flipped orientation (sets facet->flipped)- distance if non-NULL-*/-boolT qh_checkflipped(qhT *qh, facetT *facet, realT *distp, boolT allerror) {- realT dist;-- if (facet->flipped && !distp)- return False;- zzinc_(Zdistcheck);- qh_distplane(qh, qh->interior_point, facet, &dist);- if (distp)- *distp= dist;- if ((allerror && dist > -qh->DISTround)|| (!allerror && dist >= 0.0)) {- facet->flipped= True;- zzinc_(Zflippedfacets);- trace0((qh, qh->ferr, 19, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",- facet->id, dist, qh->furthest_id));- qh_precision(qh, "flipped facet");- return False;- }- return True;-} /* checkflipped */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="delfacet">-</a>-- qh_delfacet(qh, facet )- removes facet from facet_list and frees up its memory-- notes:- assumes vertices and ridges already freed-*/-void qh_delfacet(qhT *qh, facetT *facet) {- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */-- trace4((qh, qh->ferr, 4046, "qh_delfacet: delete f%d\n", facet->id));- if (facet == qh->tracefacet)- qh->tracefacet= NULL;- if (facet == qh->GOODclosest)- qh->GOODclosest= NULL;- qh_removefacet(qh, facet);- if (!facet->tricoplanar || facet->keepcentrum) {- qh_memfree_(qh, facet->normal, qh->normal_size, freelistp);- if (qh->CENTERtype == qh_ASvoronoi) { /* braces for macro calls */- qh_memfree_(qh, facet->center, qh->center_size, freelistp);- }else /* AScentrum */ {- qh_memfree_(qh, facet->center, qh->normal_size, freelistp);- }- }- qh_setfree(qh, &(facet->neighbors));- if (facet->ridges)- qh_setfree(qh, &(facet->ridges));- qh_setfree(qh, &(facet->vertices));- if (facet->outsideset)- qh_setfree(qh, &(facet->outsideset));- if (facet->coplanarset)- qh_setfree(qh, &(facet->coplanarset));- qh_memfree_(qh, facet, (int)sizeof(facetT), freelistp);-} /* delfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="deletevisible">-</a>-- qh_deletevisible()- delete visible facets and vertices-- returns:- deletes each facet and removes from facetlist- at exit, qh.visible_list empty (== qh.newfacet_list)-- notes:- ridges already deleted- horizon facets do not reference facets on qh.visible_list- new facets in qh.newfacet_list- uses qh.visit_id;-*/-void qh_deletevisible(qhT *qh /*qh.visible_list*/) {- facetT *visible, *nextfacet;- vertexT *vertex, **vertexp;- int numvisible= 0, numdel= qh_setsize(qh, qh->del_vertices);-- trace1((qh, qh->ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",- qh->num_visible, numdel));- for (visible= qh->visible_list; visible && visible->visible;- visible= nextfacet) { /* deleting current */- nextfacet= visible->next;- numvisible++;- qh_delfacet(qh, visible);- }- if (numvisible != qh->num_visible) {- qh_fprintf(qh, qh->ferr, 6103, "qhull internal error (qh_deletevisible): qh->num_visible %d is not number of visible facets %d\n",- qh->num_visible, numvisible);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }- qh->num_visible= 0;- zadd_(Zvisfacettot, numvisible);- zmax_(Zvisfacetmax, numvisible);- zzadd_(Zdelvertextot, numdel);- zmax_(Zdelvertexmax, numdel);- FOREACHvertex_(qh->del_vertices)- qh_delvertex(qh, vertex);- qh_settruncate(qh, qh->del_vertices, 0);-} /* deletevisible */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="facetintersect">-</a>-- qh_facetintersect(qh, facetA, facetB, skipa, skipB, prepend )- return vertices for intersection of two simplicial facets- may include 1 prepended entry (if more, need to settemppush)-- returns:- returns set of qh.hull_dim-1 + prepend vertices- returns skipped index for each test and checks for exactly one-- notes:- does not need settemp since set in quick memory-- see also:- qh_vertexintersect and qh_vertexintersect_new- use qh_setnew_delnthsorted to get nth ridge (no skip information)-- design:- locate skipped vertex by scanning facet A's neighbors- locate skipped vertex by scanning facet B's neighbors- intersect the vertex sets-*/-setT *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB,- int *skipA,int *skipB, int prepend) {- setT *intersect;- int dim= qh->hull_dim, i, j;- facetT **neighborsA, **neighborsB;-- neighborsA= SETaddr_(facetA->neighbors, facetT);- neighborsB= SETaddr_(facetB->neighbors, facetT);- i= j= 0;- if (facetB == *neighborsA++)- *skipA= 0;- else if (facetB == *neighborsA++)- *skipA= 1;- else if (facetB == *neighborsA++)- *skipA= 2;- else {- for (i=3; i < dim; i++) {- if (facetB == *neighborsA++) {- *skipA= i;- break;- }- }- }- if (facetA == *neighborsB++)- *skipB= 0;- else if (facetA == *neighborsB++)- *skipB= 1;- else if (facetA == *neighborsB++)- *skipB= 2;- else {- for (j=3; j < dim; j++) {- if (facetA == *neighborsB++) {- *skipB= j;- break;- }- }- }- if (i >= dim || j >= dim) {- qh_fprintf(qh, qh->ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",- facetA->id, facetB->id);- qh_errexit2(qh, qh_ERRqhull, facetA, facetB);- }- intersect= qh_setnew_delnthsorted(qh, facetA->vertices, qh->hull_dim, *skipA, prepend);- trace4((qh, qh->ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",- facetA->id, *skipA, facetB->id, *skipB));- return(intersect);-} /* facetintersect */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="gethash">-</a>-- qh_gethash(qh, hashsize, set, size, firstindex, skipelem )- return hashvalue for a set with firstindex and skipelem-- notes:- returned hash is in [0,hashsize)- assumes at least firstindex+1 elements- assumes skipelem is NULL, in set, or part of hash-- hashes memory addresses which may change over different runs of the same data- using sum for hash does badly in high d-*/-int qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem) {- void **elemp= SETelemaddr_(set, firstindex, void);- ptr_intT hash = 0, elem;- unsigned result;- int i;-#ifdef _MSC_VER /* Microsoft Visual C++ -- warn about 64-bit issues */-#pragma warning( push) /* WARN64 -- ptr_intT holds a 64-bit pointer */-#pragma warning( disable : 4311) /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */-#endif-- switch (size-firstindex) {- case 1:- hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;- break;- case 2:- hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;- break;- case 3:- hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]- - (ptr_intT) skipelem;- break;- case 4:- hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]- + (ptr_intT)elemp[3] - (ptr_intT) skipelem;- break;- case 5:- hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]- + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;- break;- case 6:- hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]- + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]- - (ptr_intT) skipelem;- break;- default:- hash= 0;- i= 3;- do { /* this is about 10% in 10-d */- if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {- hash ^= (elem << i) + (elem >> (32-i));- i += 3;- if (i >= 32)- i -= 32;- }- }while (*elemp);- break;- }- if (hashsize<0) {- qh_fprintf(qh, qh->ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize);- qh_errexit2(qh, qh_ERRqhull, NULL, NULL);- }- result= (unsigned)hash;- result %= (unsigned)hashsize;- /* result= 0; for debugging */- return result;-#ifdef _MSC_VER-#pragma warning( pop)-#endif-} /* gethash */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="makenewfacet">-</a>-- qh_makenewfacet(qh, vertices, toporient, horizon )- creates a toporient? facet from vertices-- returns:- returns newfacet- adds newfacet to qh.facet_list- newfacet->vertices= vertices- if horizon- newfacet->neighbor= horizon, but not vice versa- newvertex_list updated with vertices-*/-facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient,facetT *horizon) {- facetT *newfacet;- vertexT *vertex, **vertexp;-- FOREACHvertex_(vertices) {- if (!vertex->newlist) {- qh_removevertex(qh, vertex);- qh_appendvertex(qh, vertex);- }- }- newfacet= qh_newfacet(qh);- newfacet->vertices= vertices;- newfacet->toporient= (unsigned char)toporient;- if (horizon)- qh_setappend(qh, &(newfacet->neighbors), horizon);- qh_appendfacet(qh, newfacet);- return(newfacet);-} /* makenewfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="makenewplanes">-</a>-- qh_makenewplanes()- make new hyperplanes for facets on qh.newfacet_list-- returns:- all facets have hyperplanes or are marked for merging- doesn't create hyperplane if horizon is coplanar (will merge)- updates qh.min_vertex if qh.JOGGLEmax-- notes:- facet->f.samecycle is defined for facet->mergehorizon facets-*/-void qh_makenewplanes(qhT *qh /* qh.newfacet_list */) {- facetT *newfacet;-- FORALLnew_facets {- if (!newfacet->mergehorizon)- qh_setfacetplane(qh, newfacet);- }- if (qh->JOGGLEmax < REALmax/2)- minimize_(qh->min_vertex, -wwval_(Wnewvertexmax));-} /* makenewplanes */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="makenew_nonsimplicial">-</a>-- qh_makenew_nonsimplicial(qh, visible, apex, numnew )- make new facets for ridges of a visible facet-- returns:- first newfacet, bumps numnew as needed- attaches new facets if !qh.ONLYgood- marks ridge neighbors for simplicial visible- if (qh.ONLYgood)- ridges on newfacet, horizon, and visible- else- ridge and neighbors between newfacet and horizon- visible facet's ridges are deleted-- notes:- qh.visit_id if visible has already been processed- sets neighbor->seen for building f.samecycle- assumes all 'seen' flags initially false-- design:- for each ridge of visible facet- get neighbor of visible facet- if neighbor was already processed- delete the ridge (will delete all visible facets later)- if neighbor is a horizon facet- create a new facet- if neighbor coplanar- adds newfacet to f.samecycle for later merging- else- updates neighbor's neighbor set- (checks for non-simplicial facet with multiple ridges to visible facet)- updates neighbor's ridge set- (checks for simplicial neighbor to non-simplicial visible facet)- (deletes ridge if neighbor is simplicial)--*/-#ifndef qh_NOmerge-facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */- ridgeT *ridge, **ridgep;- facetT *neighbor, *newfacet= NULL, *samecycle;- setT *vertices;- boolT toporient;- int ridgeid;-- FOREACHridge_(visible->ridges) {- ridgeid= ridge->id;- neighbor= otherfacet_(ridge, visible);- if (neighbor->visible) {- if (!qh->ONLYgood) {- if (neighbor->visitid == qh->visit_id) {- qh_setfree(qh, &(ridge->vertices)); /* delete on 2nd visit */- qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);- }- }- }else { /* neighbor is an horizon facet */- toporient= (ridge->top == visible);- vertices= qh_setnew(qh, qh->hull_dim); /* makes sure this is quick */- qh_setappend(qh, &vertices, apex);- qh_setappend_set(qh, &vertices, ridge->vertices);- newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);- (*numnew)++;- if (neighbor->coplanar) {- newfacet->mergehorizon= True;- if (!neighbor->seen) {- newfacet->f.samecycle= newfacet;- neighbor->f.newcycle= newfacet;- }else {- samecycle= neighbor->f.newcycle;- newfacet->f.samecycle= samecycle->f.samecycle;- samecycle->f.samecycle= newfacet;- }- }- if (qh->ONLYgood) {- if (!neighbor->simplicial)- qh_setappend(qh, &(newfacet->ridges), ridge);- }else { /* qh_attachnewfacets */- if (neighbor->seen) {- if (neighbor->simplicial) {- qh_fprintf(qh, qh->ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",- neighbor->id, visible->id);- qh_errexit2(qh, qh_ERRqhull, neighbor, visible);- }- qh_setappend(qh, &(neighbor->neighbors), newfacet);- }else- qh_setreplace(qh, neighbor->neighbors, visible, newfacet);- if (neighbor->simplicial) {- qh_setdel(neighbor->ridges, ridge);- qh_setfree(qh, &(ridge->vertices));- qh_memfree(qh, ridge, (int)sizeof(ridgeT));- }else {- qh_setappend(qh, &(newfacet->ridges), ridge);- if (toporient)- ridge->top= newfacet;- else- ridge->bottom= newfacet;- }- trace4((qh, qh->ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",- newfacet->id, apex->id, ridgeid, neighbor->id));- }- }- neighbor->seen= True;- } /* for each ridge */- if (!qh->ONLYgood)- SETfirst_(visible->ridges)= NULL;- return newfacet;-} /* makenew_nonsimplicial */-#else /* qh_NOmerge */-facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {- return NULL;-}-#endif /* qh_NOmerge */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="makenew_simplicial">-</a>-- qh_makenew_simplicial(qh, visible, apex, numnew )- make new facets for simplicial visible facet and apex-- returns:- attaches new facets if (!qh.ONLYgood)- neighbors between newfacet and horizon-- notes:- nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)-- design:- locate neighboring horizon facet for visible facet- determine vertices and orientation- create new facet- if coplanar,- add new facet to f.samecycle- update horizon facet's neighbor list-*/-facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {- facetT *neighbor, **neighborp, *newfacet= NULL;- setT *vertices;- boolT flip, toporient;- int horizonskip= 0, visibleskip= 0;-- FOREACHneighbor_(visible) {- if (!neighbor->seen && !neighbor->visible) {- vertices= qh_facetintersect(qh, neighbor,visible, &horizonskip, &visibleskip, 1);- SETfirst_(vertices)= apex;- flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));- if (neighbor->toporient)- toporient= horizonskip & 0x1;- else- toporient= (horizonskip & 0x1) ^ 0x1;- newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);- (*numnew)++;- if (neighbor->coplanar && (qh->PREmerge || qh->MERGEexact)) {-#ifndef qh_NOmerge- newfacet->f.samecycle= newfacet;- newfacet->mergehorizon= True;-#endif- }- if (!qh->ONLYgood)- SETelem_(neighbor->neighbors, horizonskip)= newfacet;- trace4((qh, qh->ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",- newfacet->id, toporient, apex->id, neighbor->id, horizonskip,- neighbor->toporient, visible->id, visibleskip, flip));- }- }- return newfacet;-} /* makenew_simplicial */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="matchneighbor">-</a>-- qh_matchneighbor(qh, newfacet, newskip, hashsize, hashcount )- either match subridge of newfacet with neighbor or add to hash_table-- returns:- duplicate ridges are unmatched and marked by qh_DUPLICATEridge-- notes:- ridge is newfacet->vertices w/o newskip vertex- do not allocate memory (need to free hash_table cleanly)- uses linear hash chains-- see also:- qh_matchduplicates-- design:- for each possible matching facet in qh.hash_table- if vertices match- set ismatch, if facets have opposite orientation- if ismatch and matching facet doesn't have a match- match the facets by updating their neighbor sets- else- indicate a duplicate ridge- set facet hyperplane for later testing- add facet to hashtable- unless the other facet was already a duplicate ridge- mark both facets with a duplicate ridge- add other facet (if defined) to hash table-*/-void qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize, int *hashcount) {- boolT newfound= False; /* True, if new facet is already in hash chain */- boolT same, ismatch;- int hash, scan;- facetT *facet, *matchfacet;- int skip, matchskip;-- hash= qh_gethash(qh, hashsize, newfacet->vertices, qh->hull_dim, 1,- SETelem_(newfacet->vertices, newskip));- trace4((qh, qh->ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",- newfacet->id, newskip, hash, *hashcount));- zinc_(Zhashlookup);- for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));- scan= (++scan >= hashsize ? 0 : scan)) {- if (facet == newfacet) {- newfound= True;- continue;- }- zinc_(Zhashtests);- if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {- if (SETelem_(newfacet->vertices, newskip) ==- SETelem_(facet->vertices, skip)) {- qh_precision(qh, "two facets with the same vertices");- qh_fprintf(qh, qh->ferr, 6106, "qhull precision error: Vertex sets are the same for f%d and f%d. Can not force output.\n",- facet->id, newfacet->id);- qh_errexit2(qh, qh_ERRprec, facet, newfacet);- }- ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));- matchfacet= SETelemt_(facet->neighbors, skip, facetT);- if (ismatch && !matchfacet) {- SETelem_(facet->neighbors, skip)= newfacet;- SETelem_(newfacet->neighbors, newskip)= facet;- (*hashcount)--;- trace4((qh, qh->ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",- facet->id, skip, newfacet->id, newskip));- return;- }- if (!qh->PREmerge && !qh->MERGEexact) {- qh_precision(qh, "a ridge with more than two neighbors");- qh_fprintf(qh, qh->ferr, 6107, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors. Can not continue.\n",- facet->id, newfacet->id, getid_(matchfacet));- qh_errexit2(qh, qh_ERRprec, facet, newfacet);- }- SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;- newfacet->dupridge= True;- if (!newfacet->normal)- qh_setfacetplane(qh, newfacet);- qh_addhash(newfacet, qh->hash_table, hashsize, hash);- (*hashcount)++;- if (!facet->normal)- qh_setfacetplane(qh, facet);- if (matchfacet != qh_DUPLICATEridge) {- SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;- facet->dupridge= True;- if (!facet->normal)- qh_setfacetplane(qh, facet);- if (matchfacet) {- matchskip= qh_setindex(matchfacet->neighbors, facet);- if (matchskip<0) {- qh_fprintf(qh, qh->ferr, 6260, "qhull internal error (qh_matchneighbor): matchfacet f%d is in f%d neighbors but not vice versa. Can not continue.\n",- matchfacet->id, facet->id);- qh_errexit2(qh, qh_ERRqhull, matchfacet, facet);- }- SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; /* matchskip>=0 by QH6260 */- matchfacet->dupridge= True;- if (!matchfacet->normal)- qh_setfacetplane(qh, matchfacet);- qh_addhash(matchfacet, qh->hash_table, hashsize, hash);- *hashcount += 2;- }- }- trace4((qh, qh->ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",- newfacet->id, newskip, facet->id, skip,- (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),- ismatch, hash));- return; /* end of duplicate ridge */- }- }- if (!newfound)- SETelem_(qh->hash_table, scan)= newfacet; /* same as qh_addhash */- (*hashcount)++;- trace4((qh, qh->ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",- newfacet->id, newskip, hash));-} /* matchneighbor */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="matchnewfacets">-</a>-- qh_matchnewfacets()- match newfacets in qh.newfacet_list to their newfacet neighbors-- returns:- qh.newfacet_list with full neighbor sets- get vertices with nth neighbor by deleting nth vertex- if qh.PREmerge/MERGEexact or qh.FORCEoutput- sets facet->flippped if flipped normal (also prevents point partitioning)- if duplicate ridges and qh.PREmerge/MERGEexact- sets facet->dupridge- missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)-- notes:- newfacets already have neighbor[0] (horizon facet)- assumes qh.hash_table is NULL- vertex->neighbors has not been updated yet- do not allocate memory after qh.hash_table (need to free it cleanly)-- design:- delete neighbor sets for all new facets- initialize a hash table- for all new facets- match facet with neighbors- if unmatched facets (due to duplicate ridges)- for each new facet with a duplicate ridge- match it with a facet- check for flipped facets-*/-void qh_matchnewfacets(qhT *qh /* qh.newfacet_list */) {- int numnew=0, hashcount=0, newskip;- facetT *newfacet, *neighbor;- int dim= qh->hull_dim, hashsize, neighbor_i, neighbor_n;- setT *neighbors;-#ifndef qh_NOtrace- int facet_i, facet_n, numfree= 0;- facetT *facet;-#endif-- trace1((qh, qh->ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));- FORALLnew_facets {- numnew++;- { /* inline qh_setzero(qh, newfacet->neighbors, 1, qh->hull_dim); */- neighbors= newfacet->neighbors;- neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/- memset((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);- }- }-- qh_newhashtable(qh, numnew*(qh->hull_dim-1)); /* twice what is normally needed,- but every ridge could be DUPLICATEridge */- hashsize= qh_setsize(qh, qh->hash_table);- FORALLnew_facets {- for (newskip=1; newskip<qh->hull_dim; newskip++) /* furthest/horizon already matched */- /* hashsize>0 because hull_dim>1 and numnew>0 */- qh_matchneighbor(qh, newfacet, newskip, hashsize, &hashcount);-#if 0 /* use the following to trap hashcount errors */- {- int count= 0, k;- facetT *facet, *neighbor;-- count= 0;- FORALLfacet_(qh->newfacet_list) { /* newfacet already in use */- for (k=1; k < qh->hull_dim; k++) {- neighbor= SETelemt_(facet->neighbors, k, facetT);- if (!neighbor || neighbor == qh_DUPLICATEridge)- count++;- }- if (facet == newfacet)- break;- }- if (count != hashcount) {- qh_fprintf(qh, qh->ferr, 8088, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",- newfacet->id, hashcount, count);- qh_errexit(qh, qh_ERRqhull, newfacet, NULL);- }- }-#endif /* end of trap code */- }- if (hashcount) {- FORALLnew_facets {- if (newfacet->dupridge) {- FOREACHneighbor_i_(qh, newfacet) {- if (neighbor == qh_DUPLICATEridge) {- qh_matchduplicates(qh, newfacet, neighbor_i, hashsize, &hashcount);- /* this may report MERGEfacet */- }- }- }- }- }- if (hashcount) {- qh_fprintf(qh, qh->ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",- hashcount);- qh_printhashtable(qh, qh->ferr);- qh_errexit(qh, qh_ERRqhull, NULL, NULL);- }-#ifndef qh_NOtrace- if (qh->IStracing >= 2) {- FOREACHfacet_i_(qh, qh->hash_table) {- if (!facet)- numfree++;- }- qh_fprintf(qh, qh->ferr, 8089, "qh_matchnewfacets: %d new facets, %d unused hash entries . hashsize %d\n",- numnew, numfree, qh_setsize(qh, qh->hash_table));- }-#endif /* !qh_NOtrace */- qh_setfree(qh, &qh->hash_table);- if (qh->PREmerge || qh->MERGEexact) {- if (qh->IStracing >= 4)- qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);- FORALLnew_facets {- if (newfacet->normal)- qh_checkflipped(qh, newfacet, NULL, qh_ALL);- }- }else if (qh->FORCEoutput)- qh_checkflipped_all(qh, qh->newfacet_list); /* prints warnings for flipped */-} /* matchnewfacets */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="matchvertices">-</a>-- qh_matchvertices(qh, firstindex, verticesA, skipA, verticesB, skipB, same )- tests whether vertices match with a single skip- starts match at firstindex since all new facets have a common vertex-- returns:- true if matched vertices- skip index for each set- sets same iff vertices have the same orientation-- notes:- assumes skipA is in A and both sets are the same size-- design:- set up pointers- scan both sets checking for a match- test orientation-*/-boolT qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,- setT *verticesB, int *skipB, boolT *same) {- vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;-- elemAp= SETelemaddr_(verticesA, firstindex, vertexT);- elemBp= SETelemaddr_(verticesB, firstindex, vertexT);- skipAp= SETelemaddr_(verticesA, skipA, vertexT);- do if (elemAp != skipAp) {- while (*elemAp != *elemBp++) {- if (skipBp)- return False;- skipBp= elemBp; /* one extra like FOREACH */- }- }while (*(++elemAp));- if (!skipBp)- skipBp= ++elemBp;- *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB */- *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */- trace4((qh, qh->ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",- skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));- return(True);-} /* matchvertices */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="newfacet">-</a>-- qh_newfacet(qh)- return a new facet-- returns:- all fields initialized or cleared (NULL)- preallocates neighbors set-*/-facetT *qh_newfacet(qhT *qh) {- facetT *facet;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */-- qh_memalloc_(qh, (int)sizeof(facetT), freelistp, facet, facetT);- memset((char *)facet, (size_t)0, sizeof(facetT));- if (qh->facet_id == qh->tracefacet_id)- qh->tracefacet= facet;- facet->id= qh->facet_id++;- facet->neighbors= qh_setnew(qh, qh->hull_dim);-#if !qh_COMPUTEfurthest- facet->furthestdist= 0.0;-#endif-#if qh_MAXoutside- if (qh->FORCEoutput && qh->APPROXhull)- facet->maxoutside= qh->MINoutside;- else- facet->maxoutside= qh->DISTround;-#endif- facet->simplicial= True;- facet->good= True;- facet->newfacet= True;- trace4((qh, qh->ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));- return(facet);-} /* newfacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="newridge">-</a>-- qh_newridge()- return a new ridge-*/-ridgeT *qh_newridge(qhT *qh) {- ridgeT *ridge;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */-- qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT);- memset((char *)ridge, (size_t)0, sizeof(ridgeT));- zinc_(Ztotridges);- if (qh->ridge_id == UINT_MAX) {- qh_fprintf(qh, qh->ferr, 7074, "\-qhull warning: more than 2^32 ridges. Qhull results are OK. Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n");- }- ridge->id= qh->ridge_id++;- trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));- return(ridge);-} /* newridge */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="pointid">-</a>-- qh_pointid(qh, point )- return id for a point,- returns qh_IDnone(-3) if null, qh_IDinterior(-2) if interior, or qh_IDunknown(-1) if not known-- alternative code if point is in qh.first_point...- unsigned long id;- id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;-- notes:- Valid points are non-negative- WARN64 -- id truncated to 32-bits, at most 2G points- NOerrors returned (QhullPoint::id)- if point not in point array- the code does a comparison of unrelated pointers.-*/-int qh_pointid(qhT *qh, pointT *point) {- ptr_intT offset, id;-- if (!point || !qh)- return qh_IDnone;- else if (point == qh->interior_point)- return qh_IDinterior;- else if (point >= qh->first_point- && point < qh->first_point + qh->num_points * qh->hull_dim) {- offset= (ptr_intT)(point - qh->first_point);- id= offset / qh->hull_dim;- }else if ((id= qh_setindex(qh->other_points, point)) != -1)- id += qh->num_points;- else- return qh_IDunknown;- return (int)id;-} /* pointid */--/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="removefacet">-</a>-- qh_removefacet(qh, facet )- unlinks facet from qh.facet_list,-- returns:- updates qh.facet_list .newfacet_list .facet_next visible_list- decrements qh.num_facets-- see:- qh_appendfacet-*/-void qh_removefacet(qhT *qh, facetT *facet) {- facetT *next= facet->next, *previous= facet->previous;-- if (facet == qh->newfacet_list)- qh->newfacet_list= next;- if (facet == qh->facet_next)- qh->facet_next= next;- if (facet == qh->visible_list)- qh->visible_list= next;- if (previous) {- previous->next= next;- next->previous= previous;- }else { /* 1st facet in qh->facet_list */- qh->facet_list= next;- qh->facet_list->previous= NULL;- }- qh->num_facets--;- trace4((qh, qh->ferr, 4057, "qh_removefacet: remove f%d from facet_list\n", facet->id));-} /* removefacet */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="removevertex">-</a>-- qh_removevertex(qh, vertex )- unlinks vertex from qh.vertex_list,-- returns:- updates qh.vertex_list .newvertex_list- decrements qh.num_vertices-*/-void qh_removevertex(qhT *qh, vertexT *vertex) {- vertexT *next= vertex->next, *previous= vertex->previous;-- if (vertex == qh->newvertex_list)- qh->newvertex_list= next;- if (previous) {- previous->next= next;- next->previous= previous;- }else { /* 1st vertex in qh->vertex_list */- qh->vertex_list= vertex->next;- qh->vertex_list->previous= NULL;- }- qh->num_vertices--;- trace4((qh, qh->ferr, 4058, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));-} /* removevertex */---/*-<a href="qh-poly_r.htm#TOC"- >-------------------------------</a><a name="updatevertices">-</a>-- qh_updatevertices()- update vertex neighbors and delete interior vertices-- returns:- if qh.VERTEXneighbors, updates neighbors for each vertex- if qh.newvertex_list,- removes visible neighbors from vertex neighbors- if qh.newfacet_list- adds new facets to vertex neighbors- if qh.visible_list- interior vertices added to qh.del_vertices for later partitioning-- design:- if qh.VERTEXneighbors- deletes references to visible facets from vertex neighbors- appends new facets to the neighbor list for each vertex- checks all vertices of visible facets- removes visible facets from neighbor lists- marks unused vertices for deletion-*/-void qh_updatevertices(qhT *qh /*qh.newvertex_list, newfacet_list, visible_list*/) {- facetT *newfacet= NULL, *neighbor, **neighborp, *visible;- vertexT *vertex, **vertexp;-- trace3((qh, qh->ferr, 3013, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));- if (qh->VERTEXneighbors) {- FORALLvertex_(qh->newvertex_list) {- FOREACHneighbor_(vertex) {- if (neighbor->visible)- SETref_(neighbor)= NULL;- }- qh_setcompact(qh, vertex->neighbors);- }- FORALLnew_facets {- FOREACHvertex_(newfacet->vertices)- qh_setappend(qh, &vertex->neighbors, newfacet);- }- FORALLvisible_facets {- FOREACHvertex_(visible->vertices) {- if (!vertex->newlist && !vertex->deleted) {- FOREACHneighbor_(vertex) { /* this can happen under merging */- if (!neighbor->visible)- break;- }- if (neighbor)- qh_setdel(vertex->neighbors, visible);- else {- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);- trace2((qh, qh->ferr, 2041, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",- qh_pointid(qh, vertex->point), vertex->id, visible->id));- }- }- }- }- }else { /* !VERTEXneighbors */- FORALLvisible_facets {- FOREACHvertex_(visible->vertices) {- if (!vertex->newlist && !vertex->deleted) {- vertex->deleted= True;- qh_setappend(qh, &qh->del_vertices, vertex);- trace2((qh, qh->ferr, 2042, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",- qh_pointid(qh, vertex->point), vertex->id, visible->id));- }- }- }- }-} /* updatevertices */---
− C/qset_r.c
@@ -1,1340 +0,0 @@-/*<html><pre> -<a href="qh-set_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- qset_r.c- implements set manipulations needed for quickhull-- see qh-set_r.htm and qset_r.h-- Be careful of strict aliasing (two pointers of different types- that reference the same location). The last slot of a set is- either the actual size of the set plus 1, or the NULL terminator- of the set (i.e., setelemT).-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/qset_r.c#3 $$Change: 2062 $- $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $-*/--#include "libqhull_r.h" /* for qhT and QHULL_CRTDBG */-#include "qset_r.h"-#include "mem_r.h"-#include <stdio.h>-#include <string.h>-/*** uncomment here and qhull_ra.h- if string.h does not define memcpy()-#include <memory.h>-*/--#ifndef qhDEFlibqhull-typedef struct ridgeT ridgeT;-typedef struct facetT facetT;-void qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);-void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );-# ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */-# pragma warning( disable : 4127) /* conditional expression is constant */-# pragma warning( disable : 4706) /* assignment within conditional function */-# endif-#endif--/*=============== internal macros ===========================*/--/*============ functions in alphabetical order ===================*/--/*-<a href="qh-set_r.htm#TOC"- >--------------------------------<a name="setaddnth">-</a>-- qh_setaddnth(qh, setp, nth, newelem)- adds newelem as n'th element of sorted or unsorted *setp-- notes:- *setp and newelem must be defined- *setp may be a temp set- nth=0 is first element- errors if nth is out of bounds-- design:- expand *setp if empty or full- move tail of *setp up one- insert newelem-*/-void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {- int oldsize, i;- setelemT *sizep; /* avoid strict aliasing */- setelemT *oldp, *newp;-- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {- qh_setlarger(qh, setp);- sizep= SETsizeaddr_(*setp);- }- oldsize= sizep->i - 1;- if (nth < 0 || nth > oldsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);- qh_setprint(qh, qh->qhmem.ferr, "", *setp);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- sizep->i++;- oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void); /* NULL */- newp= oldp+1;- for (i=oldsize-nth+1; i--; ) /* move at least NULL */- (newp--)->p= (oldp--)->p; /* may overwrite *sizep */- newp->p= newelem;-} /* setaddnth */---/*-<a href="qh-set_r.htm#TOC"- >--------------------------------<a name="setaddsorted">-</a>-- setaddsorted( setp, newelem )- adds an newelem into sorted *setp-- notes:- *setp and newelem must be defined- *setp may be a temp set- nop if newelem already in set-- design:- find newelem's position in *setp- insert newelem-*/-void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {- int newindex=0;- void *elem, **elemp;-- FOREACHelem_(*setp) { /* could use binary search instead */- if (elem < newelem)- newindex++;- else if (elem == newelem)- return;- else- break;- }- qh_setaddnth(qh, setp, newindex, newelem);-} /* setaddsorted */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setappend">-</a>-- qh_setappend(qh, setp, newelem)- append newelem to *setp-- notes:- *setp may be a temp set- *setp and newelem may be NULL-- design:- expand *setp if empty or full- append newelem to *setp--*/-void qh_setappend(qhT *qh, setT **setp, void *newelem) {- setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */- setelemT *endp;- int count;-- if (!newelem)- return;- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {- qh_setlarger(qh, setp);- sizep= SETsizeaddr_(*setp);- }- count= (sizep->i)++ - 1;- endp= (setelemT *)SETelemaddr_(*setp, count, void);- (endp++)->p= newelem;- endp->p= NULL;-} /* setappend */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setappend_set">-</a>-- qh_setappend_set(qh, setp, setA)- appends setA to *setp-- notes:- *setp can not be a temp set- *setp and setA may be NULL-- design:- setup for copy- expand *setp if it is too small- append all elements of setA to *setp-*/-void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {- int sizeA, size;- setT *oldset;- setelemT *sizep;-- if (!setA)- return;- SETreturnsize_(setA, sizeA);- if (!*setp)- *setp= qh_setnew(qh, sizeA);- sizep= SETsizeaddr_(*setp);- if (!(size= sizep->i))- size= (*setp)->maxsize;- else- size--;- if (size + sizeA > (*setp)->maxsize) {- oldset= *setp;- *setp= qh_setcopy(qh, oldset, sizeA);- qh_setfree(qh, &oldset);- sizep= SETsizeaddr_(*setp);- }- if (sizeA > 0) {- sizep->i= size+sizeA+1; /* memcpy may overwrite */- memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);- }-} /* setappend_set */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setappend2ndlast">-</a>-- qh_setappend2ndlast(qh, setp, newelem )- makes newelem the next to the last element in *setp-- notes:- *setp must have at least one element- newelem must be defined- *setp may be a temp set-- design:- expand *setp if empty or full- move last element of *setp up one- insert newelem-*/-void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {- setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */- setelemT *endp, *lastp;- int count;-- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {- qh_setlarger(qh, setp);- sizep= SETsizeaddr_(*setp);- }- count= (sizep->i)++ - 1;- endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */- lastp= endp-1;- *(endp++)= *lastp;- endp->p= NULL; /* may overwrite *sizep */- lastp->p= newelem;-} /* setappend2ndlast */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setcheck">-</a>-- qh_setcheck(qh, set, typename, id )- check set for validity- report errors with typename and id-- design:- checks that maxsize, actual size, and NULL terminator agree-*/-void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned id) {- int maxsize, size;- int waserr= 0;-- if (!set)- return;- SETreturnsize_(set, size);- maxsize= set->maxsize;- if (size > maxsize || !maxsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",- size, tname, id, maxsize);- waserr= 1;- }else if (set->e[size].p) {- qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",- tname, id, size-1, maxsize);- waserr= 1;- }- if (waserr) {- qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }-} /* setcheck */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setcompact">-</a>-- qh_setcompact(qh, set )- remove internal NULLs from an unsorted set-- returns:- updated set-- notes:- set may be NULL- it would be faster to swap tail of set into holes, like qh_setdel-- design:- setup pointers into set- skip NULLs while copying elements to start of set- update the actual size-*/-void qh_setcompact(qhT *qh, setT *set) {- int size;- void **destp, **elemp, **endp, **firstp;-- if (!set)- return;- SETreturnsize_(set, size);- destp= elemp= firstp= SETaddr_(set, void);- endp= destp + size;- while (1) {- if (!(*destp++ = *elemp++)) {- destp--;- if (elemp > endp)- break;- }- }- qh_settruncate(qh, set, (int)(destp-firstp)); /* WARN64 */-} /* setcompact */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setcopy">-</a>-- qh_setcopy(qh, set, extra )- make a copy of a sorted or unsorted set with extra slots-- returns:- new set-- design:- create a newset with extra slots- copy the elements to the newset--*/-setT *qh_setcopy(qhT *qh, setT *set, int extra) {- setT *newset;- int size;-- if (extra < 0)- extra= 0;- SETreturnsize_(set, size);- newset= qh_setnew(qh, size+extra);- SETsizeaddr_(newset)->i= size+1; /* memcpy may overwrite */- memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);- return(newset);-} /* setcopy */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setdel">-</a>-- qh_setdel(set, oldelem )- delete oldelem from an unsorted set-- returns:- returns oldelem if found- returns NULL otherwise-- notes:- set may be NULL- oldelem must not be NULL;- only deletes one copy of oldelem in set-- design:- locate oldelem- update actual size if it was full- move the last element to the oldelem's location-*/-void *qh_setdel(setT *set, void *oldelem) {- setelemT *sizep;- setelemT *elemp;- setelemT *lastp;-- if (!set)- return NULL;- elemp= (setelemT *)SETaddr_(set, void);- while (elemp->p != oldelem && elemp->p)- elemp++;- if (elemp->p) {- sizep= SETsizeaddr_(set);- if (!(sizep->i)--) /* if was a full set */- sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */- lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);- elemp->p= lastp->p; /* may overwrite itself */- lastp->p= NULL;- return oldelem;- }- return NULL;-} /* setdel */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setdellast">-</a>-- qh_setdellast(set)- return last element of set or NULL-- notes:- deletes element from set- set may be NULL-- design:- return NULL if empty- if full set- delete last element and set actual size- else- delete last element and update actual size-*/-void *qh_setdellast(setT *set) {- int setsize; /* actually, actual_size + 1 */- int maxsize;- setelemT *sizep;- void *returnvalue;-- if (!set || !(set->e[0].p))- return NULL;- sizep= SETsizeaddr_(set);- if ((setsize= sizep->i)) {- returnvalue= set->e[setsize - 2].p;- set->e[setsize - 2].p= NULL;- sizep->i--;- }else {- maxsize= set->maxsize;- returnvalue= set->e[maxsize - 1].p;- set->e[maxsize - 1].p= NULL;- sizep->i= maxsize;- }- return returnvalue;-} /* setdellast */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setdelnth">-</a>-- qh_setdelnth(qh, set, nth )- deletes nth element from unsorted set- 0 is first element-- returns:- returns the element (needs type conversion)-- notes:- errors if nth invalid-- design:- setup points and check nth- delete nth element and overwrite with last element-*/-void *qh_setdelnth(qhT *qh, setT *set, int nth) {- void *elem;- setelemT *sizep;- setelemT *elemp, *lastp;-- sizep= SETsizeaddr_(set);- if ((sizep->i--)==0) /* if was a full set */- sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */- if (nth < 0 || nth >= sizep->i) {- qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */- lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);- elem= elemp->p;- elemp->p= lastp->p; /* may overwrite itself */- lastp->p= NULL;- return elem;-} /* setdelnth */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setdelnthsorted">-</a>-- qh_setdelnthsorted(qh, set, nth )- deletes nth element from sorted set-- returns:- returns the element (use type conversion)-- notes:- errors if nth invalid-- see also:- setnew_delnthsorted-- design:- setup points and check nth- copy remaining elements down one- update actual size-*/-void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {- void *elem;- setelemT *sizep;- setelemT *newp, *oldp;-- sizep= SETsizeaddr_(set);- if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- newp= (setelemT *)SETelemaddr_(set, nth, void);- elem= newp->p;- oldp= newp+1;- while (((newp++)->p= (oldp++)->p))- ; /* copy remaining elements and NULL */- if ((sizep->i--)==0) /* if was a full set */- sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */- return elem;-} /* setdelnthsorted */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setdelsorted">-</a>-- qh_setdelsorted(set, oldelem )- deletes oldelem from sorted set-- returns:- returns oldelem if it was deleted-- notes:- set may be NULL-- design:- locate oldelem in set- copy remaining elements down one- update actual size-*/-void *qh_setdelsorted(setT *set, void *oldelem) {- setelemT *sizep;- setelemT *newp, *oldp;-- if (!set)- return NULL;- newp= (setelemT *)SETaddr_(set, void);- while(newp->p != oldelem && newp->p)- newp++;- if (newp->p) {- oldp= newp+1;- while (((newp++)->p= (oldp++)->p))- ; /* copy remaining elements */- sizep= SETsizeaddr_(set);- if ((sizep->i--)==0) /* if was a full set */- sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */- return oldelem;- }- return NULL;-} /* setdelsorted */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setduplicate">-</a>-- qh_setduplicate(qh, set, elemsize )- duplicate a set of elemsize elements-- notes:- use setcopy if retaining old elements-- design:- create a new set- for each elem of the old set- create a newelem- append newelem to newset-*/-setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {- void *elem, **elemp, *newElem;- setT *newSet;- int size;-- if (!(size= qh_setsize(qh, set)))- return NULL;- newSet= qh_setnew(qh, size);- FOREACHelem_(set) {- newElem= qh_memalloc(qh, elemsize);- memcpy(newElem, elem, (size_t)elemsize);- qh_setappend(qh, &newSet, newElem);- }- return newSet;-} /* setduplicate */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setendpointer">-</a>-- qh_setendpointer( set )- Returns pointer to NULL terminator of a set's elements- set can not be NULL--*/-void **qh_setendpointer(setT *set) {-- setelemT *sizep= SETsizeaddr_(set);- int n= sizep->i;- return (n ? &set->e[n-1].p : &sizep->p);-} /* qh_setendpointer */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setequal">-</a>-- qh_setequal( setA, setB )- returns 1 if two sorted sets are equal, otherwise returns 0-- notes:- either set may be NULL-- design:- check size of each set- setup pointers- compare elements of each set-*/-int qh_setequal(setT *setA, setT *setB) {- void **elemAp, **elemBp;- int sizeA= 0, sizeB= 0;-- if (setA) {- SETreturnsize_(setA, sizeA);- }- if (setB) {- SETreturnsize_(setB, sizeB);- }- if (sizeA != sizeB)- return 0;- if (!sizeA)- return 1;- elemAp= SETaddr_(setA, void);- elemBp= SETaddr_(setB, void);- if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))- return 1;- return 0;-} /* setequal */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setequal_except">-</a>-- qh_setequal_except( setA, skipelemA, setB, skipelemB )- returns 1 if sorted setA and setB are equal except for skipelemA & B-- returns:- false if either skipelemA or skipelemB are missing-- notes:- neither set may be NULL-- if skipelemB is NULL,- can skip any one element of setB-- design:- setup pointers- search for skipelemA, skipelemB, and mismatches- check results-*/-int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {- void **elemA, **elemB;- int skip=0;-- elemA= SETaddr_(setA, void);- elemB= SETaddr_(setB, void);- while (1) {- if (*elemA == skipelemA) {- skip++;- elemA++;- }- if (skipelemB) {- if (*elemB == skipelemB) {- skip++;- elemB++;- }- }else if (*elemA != *elemB) {- skip++;- if (!(skipelemB= *elemB++))- return 0;- }- if (!*elemA)- break;- if (*elemA++ != *elemB++)- return 0;- }- if (skip != 2 || *elemB)- return 0;- return 1;-} /* setequal_except */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setequal_skip">-</a>-- qh_setequal_skip( setA, skipA, setB, skipB )- returns 1 if sorted setA and setB are equal except for elements skipA & B-- returns:- false if different size-- notes:- neither set may be NULL-- design:- setup pointers- search for mismatches while skipping skipA and skipB-*/-int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {- void **elemA, **elemB, **skipAp, **skipBp;-- elemA= SETaddr_(setA, void);- elemB= SETaddr_(setB, void);- skipAp= SETelemaddr_(setA, skipA, void);- skipBp= SETelemaddr_(setB, skipB, void);- while (1) {- if (elemA == skipAp)- elemA++;- if (elemB == skipBp)- elemB++;- if (!*elemA)- break;- if (*elemA++ != *elemB++)- return 0;- }- if (*elemB)- return 0;- return 1;-} /* setequal_skip */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setfree">-</a>-- qh_setfree(qh, setp )- frees the space occupied by a sorted or unsorted set-- returns:- sets setp to NULL-- notes:- set may be NULL-- design:- free array- free set-*/-void qh_setfree(qhT *qh, setT **setp) {- int size;- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */-- if (*setp) {- size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;- if (size <= qh->qhmem.LASTsize) {- qh_memfree_(qh, *setp, size, freelistp);- }else- qh_memfree(qh, *setp, size);- *setp= NULL;- }-} /* setfree */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setfree2">-</a>-- qh_setfree2(qh, setp, elemsize )- frees the space occupied by a set and its elements-- notes:- set may be NULL-- design:- free each element- free set-*/-void qh_setfree2(qhT *qh, setT **setp, int elemsize) {- void *elem, **elemp;-- FOREACHelem_(*setp)- qh_memfree(qh, elem, elemsize);- qh_setfree(qh, setp);-} /* setfree2 */----/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setfreelong">-</a>-- qh_setfreelong(qh, setp )- frees a set only if it's in long memory-- returns:- sets setp to NULL if it is freed-- notes:- set may be NULL-- design:- if set is large- free it-*/-void qh_setfreelong(qhT *qh, setT **setp) {- int size;-- if (*setp) {- size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;- if (size > qh->qhmem.LASTsize) {- qh_memfree(qh, *setp, size);- *setp= NULL;- }- }-} /* setfreelong */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setin">-</a>-- qh_setin(set, setelem )- returns 1 if setelem is in a set, 0 otherwise-- notes:- set may be NULL or unsorted-- design:- scans set for setelem-*/-int qh_setin(setT *set, void *setelem) {- void *elem, **elemp;-- FOREACHelem_(set) {- if (elem == setelem)- return 1;- }- return 0;-} /* setin */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setindex">-</a>-- qh_setindex(set, atelem )- returns the index of atelem in set.- returns -1, if not in set or maxsize wrong-- notes:- set may be NULL and may contain nulls.- NOerrors returned (qh_pointid, QhullPoint::id)-- design:- checks maxsize- scans set for atelem-*/-int qh_setindex(setT *set, void *atelem) {- void **elem;- int size, i;-- if (!set)- return -1;- SETreturnsize_(set, size);- if (size > set->maxsize)- return -1;- elem= SETaddr_(set, void);- for (i=0; i < size; i++) {- if (*elem++ == atelem)- return i;- }- return -1;-} /* setindex */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setlarger">-</a>-- qh_setlarger(qh, oldsetp )- returns a larger set that contains all elements of *oldsetp-- notes:- the set is at least twice as large- if temp set, updates qh->qhmem.tempstack-- design:- creates a new set- copies the old set to the new set- updates pointers in tempstack- deletes the old set-*/-void qh_setlarger(qhT *qh, setT **oldsetp) {- int size= 1;- setT *newset, *set, **setp, *oldset;- setelemT *sizep;- setelemT *newp, *oldp;-- if (*oldsetp) {- oldset= *oldsetp;- SETreturnsize_(oldset, size);- qh->qhmem.cntlarger++;- qh->qhmem.totlarger += size+1;- newset= qh_setnew(qh, 2 * size);- oldp= (setelemT *)SETaddr_(oldset, void);- newp= (setelemT *)SETaddr_(newset, void);- memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);- sizep= SETsizeaddr_(newset);- sizep->i= size+1;- FOREACHset_((setT *)qh->qhmem.tempstack) {- if (set == oldset)- *(setp-1)= newset;- }- qh_setfree(qh, oldsetp);- }else- newset= qh_setnew(qh, 3);- *oldsetp= newset;-} /* setlarger */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setlast">-</a>-- qh_setlast( set )- return last element of set or NULL (use type conversion)-- notes:- set may be NULL-- design:- return last element-*/-void *qh_setlast(setT *set) {- int size;-- if (set) {- size= SETsizeaddr_(set)->i;- if (!size)- return SETelem_(set, set->maxsize - 1);- else if (size > 1)- return SETelem_(set, size - 2);- }- return NULL;-} /* setlast */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setnew">-</a>-- qh_setnew(qh, setsize )- creates and allocates space for a set-- notes:- setsize means the number of elements (!including the NULL terminator)- use qh_settemp/qh_setfreetemp if set is temporary-- design:- allocate memory for set- roundup memory if small set- initialize as empty set-*/-setT *qh_setnew(qhT *qh, int setsize) {- setT *set;- int sizereceived; /* used if !qh_NOmem */- int size;- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */-- if (!setsize)- setsize++;- size= sizeof(setT) + setsize * SETelemsize;- if (size>0 && size <= qh->qhmem.LASTsize) {- qh_memalloc_(qh, size, freelistp, set, setT);-#ifndef qh_NOmem- sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];- if (sizereceived > size)- setsize += (sizereceived - size)/SETelemsize;-#endif- }else- set= (setT*)qh_memalloc(qh, size);- set->maxsize= setsize;- set->e[setsize].i= 1;- set->e[0].p= NULL;- return(set);-} /* setnew */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setnew_delnthsorted">-</a>-- qh_setnew_delnthsorted(qh, set, size, nth, prepend )- creates a sorted set not containing nth element- if prepend, the first prepend elements are undefined-- notes:- set must be defined- checks nth- see also: setdelnthsorted-- design:- create new set- setup pointers and allocate room for prepend'ed entries- append head of old set to new set- append tail of old set to new set-*/-setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {- setT *newset;- void **oldp, **newp;- int tailsize= size - nth -1, newsize;-- if (tailsize < 0) {- qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- newsize= size-1 + prepend;- newset= qh_setnew(qh, newsize);- newset->e[newset->maxsize].i= newsize+1; /* may be overwritten */- oldp= SETaddr_(set, void);- newp= SETaddr_(newset, void) + prepend;- switch (nth) {- case 0:- break;- case 1:- *(newp++)= *oldp++;- break;- case 2:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- case 3:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- case 4:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- default:- memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);- newp += nth;- oldp += nth;- break;- }- oldp++;- switch (tailsize) {- case 0:- break;- case 1:- *(newp++)= *oldp++;- break;- case 2:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- case 3:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- case 4:- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- *(newp++)= *oldp++;- break;- default:- memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);- newp += tailsize;- }- *newp= NULL;- return(newset);-} /* setnew_delnthsorted */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setprint">-</a>-- qh_setprint(qh, fp, string, set )- print set elements to fp with identifying string-- notes:- never errors-*/-void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {- int size, k;-- if (!set)- qh_fprintf(qh, fp, 9346, "%s set is null\n", string);- else {- SETreturnsize_(set, size);- qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",- string, set, set->maxsize, size);- if (size > set->maxsize)- size= set->maxsize+1;- for (k=0; k < size; k++)- qh_fprintf(qh, fp, 9348, " %p", set->e[k].p);- qh_fprintf(qh, fp, 9349, "\n");- }-} /* setprint */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setreplace">-</a>-- qh_setreplace(qh, set, oldelem, newelem )- replaces oldelem in set with newelem-- notes:- errors if oldelem not in the set- newelem may be NULL, but it turns the set into an indexed set (no FOREACH)-- design:- find oldelem- replace with newelem-*/-void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {- void **elemp;-- elemp= SETaddr_(set, void);- while (*elemp != oldelem && *elemp)- elemp++;- if (*elemp)- *elemp= newelem;- else {- qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",- oldelem);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }-} /* setreplace */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setsize">-</a>-- qh_setsize(qh, set )- returns the size of a set-- notes:- errors if set's maxsize is incorrect- same as SETreturnsize_(set)- same code for qh_setsize [qset_r.c] and QhullSetBase::count-- design:- determine actual size of set from maxsize-*/-int qh_setsize(qhT *qh, setT *set) {- int size;- setelemT *sizep;-- if (!set)- return(0);- sizep= SETsizeaddr_(set);- if ((size= sizep->i)) {- size--;- if (size > set->maxsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",- size, set->maxsize);- qh_setprint(qh, qh->qhmem.ferr, "set: ", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- }else- size= set->maxsize;- return size;-} /* setsize */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settemp">-</a>-- qh_settemp(qh, setsize )- return a stacked, temporary set of upto setsize elements-- notes:- use settempfree or settempfree_all to release from qh->qhmem.tempstack- see also qh_setnew-- design:- allocate set- append to qh->qhmem.tempstack--*/-setT *qh_settemp(qhT *qh, int setsize) {- setT *newset;-- newset= qh_setnew(qh, setsize);- qh_setappend(qh, &qh->qhmem.tempstack, newset);- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",- newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));- return newset;-} /* settemp */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settempfree">-</a>-- qh_settempfree(qh, set )- free temporary set at top of qh->qhmem.tempstack-- notes:- nop if set is NULL- errors if set not from previous qh_settemp-- to locate errors:- use 'T2' to find source and then find mis-matching qh_settemp-- design:- check top of qh->qhmem.tempstack- free it-*/-void qh_settempfree(qhT *qh, setT **set) {- setT *stackedset;-- if (!*set)- return;- stackedset= qh_settemppop(qh);- if (stackedset != *set) {- qh_settemppush(qh, stackedset);- qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",- *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,- stackedset, qh_setsize(qh, stackedset));- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- qh_setfree(qh, set);-} /* settempfree */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settempfree_all">-</a>-- qh_settempfree_all(qh)- free all temporary sets in qh->qhmem.tempstack-- design:- for each set in tempstack- free set- free qh->qhmem.tempstack-*/-void qh_settempfree_all(qhT *qh) {- setT *set, **setp;-- FOREACHset_(qh->qhmem.tempstack)- qh_setfree(qh, &set);- qh_setfree(qh, &qh->qhmem.tempstack);-} /* settempfree_all */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settemppop">-</a>-- qh_settemppop(qh)- pop and return temporary set from qh->qhmem.tempstack-- notes:- the returned set is permanent-- design:- pop and check top of qh->qhmem.tempstack-*/-setT *qh_settemppop(qhT *qh) {- setT *stackedset;-- stackedset= (setT*)qh_setdellast(qh->qhmem.tempstack);- if (!stackedset) {- qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",- qh_setsize(qh, qh->qhmem.tempstack)+1, stackedset, qh_setsize(qh, stackedset));- return stackedset;-} /* settemppop */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settemppush">-</a>-- qh_settemppush(qh, set )- push temporary set unto qh->qhmem.tempstack (makes it temporary)-- notes:- duplicates settemp() for tracing-- design:- append set to tempstack-*/-void qh_settemppush(qhT *qh, setT *set) {- if (!set) {- qh_fprintf(qh, qh->qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- qh_setappend(qh, &qh->qhmem.tempstack, set);- if (qh->qhmem.IStracing >= 5)- qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",- qh_setsize(qh, qh->qhmem.tempstack), set, qh_setsize(qh, set));-} /* settemppush */---/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="settruncate">-</a>-- qh_settruncate(qh, set, size )- truncate set to size elements-- notes:- set must be defined-- see:- SETtruncate_-- design:- check size- update actual size of set-*/-void qh_settruncate(qhT *qh, setT *set, int size) {-- if (size < 0 || size > set->maxsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- set->e[set->maxsize].i= size+1; /* maybe overwritten */- set->e[size].p= NULL;-} /* settruncate */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setunique">-</a>-- qh_setunique(qh, set, elem )- add elem to unsorted set unless it is already in set-- notes:- returns 1 if it is appended-- design:- if elem not in set- append elem to set-*/-int qh_setunique(qhT *qh, setT **set, void *elem) {-- if (!qh_setin(*set, elem)) {- qh_setappend(qh, set, elem);- return 1;- }- return 0;-} /* setunique */--/*-<a href="qh-set_r.htm#TOC"- >-------------------------------<a name="setzero">-</a>-- qh_setzero(qh, set, index, size )- zero elements from index on- set actual size of set to size-- notes:- set must be defined- the set becomes an indexed set (can not use FOREACH...)-- see also:- qh_settruncate-- design:- check index and size- update actual size- zero elements starting at e[index]-*/-void qh_setzero(qhT *qh, setT *set, int idx, int size) {- int count;-- if (idx < 0 || idx >= size || size > set->maxsize) {- qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);- qh_setprint(qh, qh->qhmem.ferr, "", set);- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);- }- set->e[set->maxsize].i= size+1; /* may be overwritten */- count= size - idx + 1; /* +1 for NULL terminator */- memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);-} /* setzero */--
− C/random_r.c
@@ -1,247 +0,0 @@-/*<html><pre> -<a href="index_r.htm#TOC"- >-------------------------------</a><a name="TOP">-</a>-- random_r.c and utilities- Park & Miller's minimimal standard random number generator- argc/argv conversion-- Used by rbox. Do not use 'qh' -*/--#include "libqhull_r.h"-#include "random_r.h"--#include <string.h>-#include <stdio.h>-#include <stdlib.h>--#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */-#pragma warning( disable : 4706) /* assignment within conditional function */-#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */-#endif--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="argv_to_command">-</a>-- qh_argv_to_command(argc, argv, command, max_size )-- build command from argc/argv- max_size is at least-- returns:- a space-delimited string of options (just as typed)- returns false if max_size is too short-- notes:- silently removes- makes option string easy to input and output- matches qh_argv_to_command_size()-- argc may be 0-*/-int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {- int i, remaining;- char *s;- *command= '\0'; /* max_size > 0 */-- if (argc) {- if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */- || (s= strrchr( argv[0], '/')))- s++;- else- s= argv[0];- if ((int)strlen(s) < max_size) /* WARN64 */- strcpy(command, s);- else- goto error_argv;- if ((s= strstr(command, ".EXE"))- || (s= strstr(command, ".exe")))- *s= '\0';- }- for (i=1; i < argc; i++) {- s= argv[i];- remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2; /* WARN64 */- if (!*s || strchr(s, ' ')) {- char *t= command + strlen(command);- remaining -= 2;- if (remaining < 0) {- goto error_argv;- }- *t++= ' ';- *t++= '"';- while (*s) {- if (*s == '"') {- if (--remaining < 0)- goto error_argv;- *t++= '\\';- }- *t++= *s++;- }- *t++= '"';- *t= '\0';- }else if (remaining < 0) {- goto error_argv;- }else- strcat(command, " ");- strcat(command, s);- }- return 1;--error_argv:- return 0;-} /* argv_to_command */--/*-<a href="qh-globa_r.htm#TOC"->-------------------------------</a><a name="argv_to_command_size">-</a>--qh_argv_to_command_size(argc, argv )-- return size to allocate for qh_argv_to_command()--notes:- argc may be 0- actual size is usually shorter-*/-int qh_argv_to_command_size(int argc, char *argv[]) {- unsigned int count= 1; /* null-terminator if argc==0 */- int i;- char *s;-- for (i=0; i<argc; i++){- count += (int)strlen(argv[i]) + 1; /* WARN64 */- if (i>0 && strchr(argv[i], ' ')) {- count += 2; /* quote delimiters */- for (s=argv[i]; *s; s++) {- if (*s == '"') {- count++;- }- }- }- }- return count;-} /* argv_to_command_size */--/*-<a href="qh-geom_r.htm#TOC"- >-------------------------------</a><a name="rand">-</a>-- qh_rand()- qh_srand(qh, seed )- generate pseudo-random number between 1 and 2^31 -2-- notes:- For qhull and rbox, called from qh_RANDOMint(),etc. [user.h]-- From Park & Miller's minimal standard random number generator- Communications of the ACM, 31:1192-1201, 1988.- Does not use 0 or 2^31 -1- this is silently enforced by qh_srand()- Can make 'Rn' much faster by moving qh_rand to qh_distplane-*/--/* Global variables and constants */--#define qh_rand_a 16807-#define qh_rand_m 2147483647-#define qh_rand_q 127773 /* m div a */-#define qh_rand_r 2836 /* m mod a */--int qh_rand(qhT *qh) {- int lo, hi, test;- int seed = qh->last_random;-- hi = seed / qh_rand_q; /* seed div q */- lo = seed % qh_rand_q; /* seed mod q */- test = qh_rand_a * lo - qh_rand_r * hi;- if (test > 0)- seed= test;- else- seed= test + qh_rand_m;- qh->last_random= seed;- /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */- /* seed = qh_RANDOMmax; for testing */- return seed;-} /* rand */--void qh_srand(qhT *qh, int seed) {- if (seed < 1)- qh->last_random= 1;- else if (seed >= qh_rand_m)- qh->last_random= qh_rand_m - 1;- else- qh->last_random= seed;-} /* qh_srand */--/*-<a href="qh-geom_r.htm#TOC"->-------------------------------</a><a name="randomfactor">-</a>--qh_randomfactor(qh, scale, offset )- return a random factor r * scale + offset--notes:- qh.RANDOMa/b are defined in global_r.c- qh_RANDOMint requires 'qh'-*/-realT qh_randomfactor(qhT *qh, realT scale, realT offset) {- realT randr;-- randr= qh_RANDOMint;- return randr * scale + offset;-} /* randomfactor */--/*-<a href="qh-geom_r.htm#TOC"->-------------------------------</a><a name="randommatrix">-</a>--qh_randommatrix(qh, buffer, dim, rows )- generate a random dim X dim matrix in range [-1,1]- assumes buffer is [dim+1, dim]-- returns:- sets buffer to random numbers- sets rows to rows of buffer- sets row[dim] as scratch row-- notes:- qh_RANDOMint requires 'qh'-*/-void qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **rows) {- int i, k;- realT **rowi, *coord, realr;-- coord= buffer;- rowi= rows;- for (i=0; i < dim; i++) {- *(rowi++)= coord;- for (k=0; k < dim; k++) {- realr= qh_RANDOMint;- *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;- }- }- *rowi= coord;-} /* randommatrix */--/*-<a href="qh-globa_r.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); /* WARN64 */- if (s< (*endp) && (*endp)[-1] == ' ')- (*endp)--;- return result;-} /* strtol */
− C/stat_r.c
@@ -1,682 +0,0 @@-/*<html><pre> -<a href="qh-stat_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- stat_r.c- contains all statistics that are collected for qhull-- see qh-stat_r.htm and stat_r.h-- Copyright (c) 1993-2015 The Geometry Center.- $Id: //main/2015/qhull/src/libqhull_r/stat_r.c#5 $$Change: 2062 $- $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $-*/--#include "qhull_ra.h"--/*========== functions in alphabetic order ================*/--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="allstatA">-</a>-- qh_allstatA()- define statistics in groups of 20-- notes:- (otherwise, 'gcc -O2' uses too much memory)- uses qhstat.next-*/-void qh_allstatA(qhT *qh) {-- /* zdef_(type,name,doc,average) */- zzdef_(zdoc, Zdoc2, "precision statistics", -1);- zdef_(zinc, Znewvertex, NULL, -1);- zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex);- zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);- zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);- zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);- zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);-- qh->qhstat.precision= qh->qhstat.next; /* call qh_precision for each of these */- zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);- zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);- zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);- zzdef_(zinc, Zflippedfacets, "flipped facets", -1);- zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);- zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);- zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);- zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);- zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);- zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);- zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);-}-void qh_allstatB(qhT *qh) {- zzdef_(zdoc, Zdoc1, "summary information", -1);- zdef_(zinc, Zvertices, "number of vertices in output", -1);- zdef_(zinc, Znumfacets, "number of facets in output", -1);- zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);- zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);- zdef_(zinc, Znumridges, "number of ridges in output", -1);- zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);- zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);- zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);- zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);- zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);- zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);- zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);- zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);- zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);- zdef_(zinc, Ztotvertices, "vertices created altogether", -1);- zzdef_(zinc, Zsetplane, "facets created altogether", -1);- zdef_(zinc, Ztotridges, "ridges created altogether", -1);- zdef_(zinc, Zpostfacets, "facets before post merge", -1);- zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets);- zdef_(zmax, Znummergemax, " maximum merges for a facet(at most 511)", -1);- zdef_(zinc, Zangle, NULL, -1);- zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle);- zdef_(wmax, Wanglemax, " maximum angle(cosine) of facet normals across a ridge", -1);- zdef_(wmin, Wanglemin, " minimum angle(cosine) of facet normals across a ridge", -1);- zdef_(wadd, Wareatot, "total area of facets", -1);- zdef_(wmax, Wareamax, " maximum facet area", -1);- zdef_(wmin, Wareamin, " minimum facet area", -1);-}-void qh_allstatC(qhT *qh) {- zdef_(zdoc, Zdoc9, "build hull statistics", -1);- zzdef_(zinc, Zprocessed, "points processed", -1);- zzdef_(zinc, Zretry, "retries due to precision problems", -1);- zdef_(wmax, Wretrymax, " max. random joggle", -1);- zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);- zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);- zdef_(zinc, Zinsidevisible, " ave. visible facets without an horizon neighbor", Zprocessed);- zdef_(zadd, Zvisfacettot, " ave. facets deleted per iteration", Zprocessed);- zdef_(zmax, Zvisfacetmax, " maximum", -1);- zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);- zdef_(zmax, Zvisvertexmax, " maximum", -1);- zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);- zdef_(zadd, Znewfacettot, "ave. new or merged facets per iteration", Zprocessed);- zdef_(zmax, Znewfacetmax, " maximum(includes initial simplex)", -1);- zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);- zdef_(wadd, Wnewbalance2, " standard deviation", -1);- zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);- zdef_(wadd, Wpbalance2, " standard deviation", -1);- zdef_(zinc, Zpbalance, " number of trials", -1);- zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);- zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1);- zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);- zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1);- zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1);- zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1);- zdef_(zinc, Zgoodfacet, "good facets found", -1);- zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);- zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);- zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);- zzdef_(zinc, Zcheckpart, " ave. distance tests per check", Ztotcheck);-}-void qh_allstatD(qhT *qh) {- zdef_(zinc, Zvisit, "resets of visit_id", -1);- zdef_(zinc, Zvvisit, " resets of vertex_visit", -1);- zdef_(zmax, Zvisit2max, " max visit_id/2", -1);- zdef_(zmax, Zvvisit2max, " max vertex_visit/2", -1);-- zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1);- zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);- zdef_(zmax, Zdelvertexmax, " maximum vertices deleted per iteration", -1);- zdef_(zinc, Zfindbest, "calls to findbest", -1);- zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);- zdef_(zmax, Zfindbestmax, " max. facets tested", -1);- zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);- zdef_(zinc, Zfindnew, "calls to findbestnew", -1);- zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);- zdef_(zmax, Zfindnewmax, " max. facets tested", -1);- zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);- zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);- zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);- zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);- zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);- zdef_(zinc, Zfindjump, " ave. clearly better", Zfindhorizon);- zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);- zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);- zdef_(zinc, Zpartflip, " repartitioned coplanar points for flipped orientation", -1);-}-void qh_allstatE(qhT *qh) {- zdef_(zinc, Zpartinside, "inside points", -1);- zdef_(zinc, Zpartnear, " inside points kept with a facet", -1);- zdef_(zinc, Zcoplanarinside, " inside points that were coplanar with a facet", -1);- zdef_(zinc, Zbestlower, "calls to findbestlower", -1);- zdef_(zinc, Zbestlowerv, " with search of vertex neighbors", -1);- zdef_(zinc, Zbestlowerall, " with rare search of all facets", -1);- zdef_(zmax, Zbestloweralln, " facets per search of all facets", -1);- zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);- zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);- zdef_(zinc, Ztotpartition, "partitions of a point", -1);- zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);- zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);- zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);- zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);- zdef_(zinc, Zdistio, "distance tests for output", -1);- zdef_(zinc, Zdiststat, "distance tests for statistics", -1);- zdef_(zinc, Zdistplane, "total number of distance tests", -1);- zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);- zzdef_(zinc, Zpartcoplanar, " distance tests for these partitions", -1);- zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);-}-void qh_allstatE2(qhT *qh) {- zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);- zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);- zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);- zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1);- zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);- zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);- zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);-- zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);- zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);- zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);- zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);- zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);- zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);- zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);- zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);- zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);-}-void qh_allstatF(qhT *qh) {- zdef_(zdoc, Zdoc7, "statistics for merging", -1);- zdef_(zinc, Zpremergetot, "merge iterations", -1);- zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);- zdef_(zadd, Zmergeinitmax, " maximum", -1);- zdef_(zadd, Zmergesettot, " ave. additional non-convex ridges per iteration", Zpremergetot);- zdef_(zadd, Zmergesetmax, " maximum additional in one pass", -1);- zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);- zdef_(zadd, Zmergesettot2, " additional non-convex ridges", -1);- zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1);- zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1);- zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);- zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);- zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);- zdef_(zinc, Zmergesimplex, "merged a simplex", -1);- zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);- zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);- zzdef_(zadd, Zcyclefacettot, " ave. facets per cycle", Zcyclehorizon);- zdef_(zmax, Zcyclefacetmax, " max. facets", -1);- zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);- zdef_(zinc, Zmergenew, "new facets merged", -1);- zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);- zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);- zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);- zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);- zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);- zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);- zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);-}-void qh_allstatG(qhT *qh) {- zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);- zdef_(wadd, Wacoplanartot, " average merge distance", Zacoplanar);- zdef_(wmax, Wacoplanarmax, " maximum merge distance", -1);- zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);- zdef_(wadd, Wcoplanartot, " average merge distance", Zcoplanar);- zdef_(wmax, Wcoplanarmax, " maximum merge distance", -1);- zdef_(zinc, Zconcave, "merges due to concave facets", -1);- zdef_(wadd, Wconcavetot, " average merge distance", Zconcave);- zdef_(wmax, Wconcavemax, " maximum merge distance", -1);- zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);- zdef_(wadd, Wavoidoldtot, " average merge distance", Zavoidold);- zdef_(wmax, Wavoidoldmax, " maximum merge distance", -1);- zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);- zdef_(wadd, Wdegentot, " average merge distance", Zdegen);- zdef_(wmax, Wdegenmax, " maximum merge distance", -1);- zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);- zdef_(wadd, Wflippedtot, " average merge distance", Zflipped);- zdef_(wmax, Wflippedmax, " maximum merge distance", -1);- zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);- zdef_(wadd, Wduplicatetot, " average merge distance", Zduplicate);- zdef_(wmax, Wduplicatemax, " maximum merge distance", -1);-}-void qh_allstatH(qhT *qh) {- zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);- zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);- zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);- zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);- zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);- zdef_(zinc, Zdupridge, " duplicate ridges detected", -1);- zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);- zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);- zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);- zdef_(zinc, Zdelfacetdup, " facets deleted because of no neighbors", -1);- zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);- zdef_(zinc, Zremvertexdel, " deleted", -1);- zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);- zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);- zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);- zdef_(zadd, Zintersecttot, " ave. number found per vertex", Zintersect);- zdef_(zmax, Zintersectmax, " max. found for a vertex", -1);- zdef_(zinc, Zvertexridge, NULL, -1);- zdef_(zadd, Zvertexridgetot, " ave. number of ridges per tested vertex", Zvertexridge);- zdef_(zmax, Zvertexridgemax, " max. number of ridges per tested vertex", -1);-- zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1);- zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);- zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);- zdef_(zadd, Zmempoints, "for input points, outside and coplanar sets, and qhT",-1);- zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);-} /* allstat */--void qh_allstatI(qhT *qh) {- qh->qhstat.vridges= qh->qhstat.next;- zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);- zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);- zzdef_(wadd, Wridge, " ave. distance to ridge", Zridge);- zzdef_(wmax, Wridgemax, " max. distance to ridge", -1);- zzdef_(zinc, Zridgemid, "bounded ridges", -1);- zzdef_(wadd, Wridgemid, " ave. distance of midpoint to ridge", Zridgemid);- zzdef_(wmax, Wridgemidmax, " max. distance of midpoint to ridge", -1);- zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);- zzdef_(wadd, Wridgeok, " ave. angle to ridge", Zridgeok);- zzdef_(wmax, Wridgeokmax, " max. angle to ridge", -1);- zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);- zzdef_(wadd, Wridge0, " ave. angle to ridge", Zridge0);- zzdef_(wmax, Wridge0max, " max. angle to ridge", -1);-- zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1);- zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);- zdef_(zadd, Ztricoplanartot, " ave. new facets created(may be deleted)", Ztricoplanar);- zdef_(zmax, Ztricoplanarmax, " max. new facets created", -1);- zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1);- zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1);- zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1);-} /* allstat */--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="allstatistics">-</a>-- qh_allstatistics()- reset printed flag for all statistics-*/-void qh_allstatistics(qhT *qh) {- int i;-- for(i=ZEND; i--; )- qh->qhstat.printed[i]= False;-} /* allstatistics */--#if qh_KEEPstatistics-/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="collectstatistics">-</a>-- qh_collectstatistics()- collect statistics for qh.facet_list--*/-void qh_collectstatistics(qhT *qh) {- facetT *facet, *neighbor, **neighborp;- vertexT *vertex, **vertexp;- realT dotproduct, dist;- int sizneighbors, sizridges, sizvertices, i;-- qh->old_randomdist= qh->RANDOMdist;- qh->RANDOMdist= False;- zval_(Zmempoints)= qh->num_points * qh->normal_size + sizeof(qhT);- zval_(Zmemfacets)= 0;- zval_(Zmemridges)= 0;- zval_(Zmemvertices)= 0;- zval_(Zangle)= 0;- wval_(Wangle)= 0.0;- zval_(Znumridges)= 0;- zval_(Znumfacets)= 0;- zval_(Znumneighbors)= 0;- zval_(Znumvertices)= 0;- zval_(Znumvneighbors)= 0;- zval_(Znummergetot)= 0;- zval_(Znummergemax)= 0;- zval_(Zvertices)= qh->num_vertices - qh_setsize(qh, qh->del_vertices);- if (qh->MERGING || qh->APPROXhull || qh->JOGGLEmax < REALmax/2)- wmax_(Wmaxoutside, qh->max_outside);- if (qh->MERGING)- wmin_(Wminvertex, qh->min_vertex);- FORALLfacets- facet->seen= False;- if (qh->DELAUNAY) {- FORALLfacets {- if (facet->upperdelaunay != qh->UPPERdelaunay)- facet->seen= True; /* remove from angle statistics */- }- }- FORALLfacets {- if (facet->visible && qh->NEWfacets)- continue;- sizvertices= qh_setsize(qh, facet->vertices);- sizneighbors= qh_setsize(qh, facet->neighbors);- sizridges= qh_setsize(qh, facet->ridges);- zinc_(Znumfacets);- zadd_(Znumvertices, sizvertices);- zmax_(Zmaxvertices, sizvertices);- zadd_(Znumneighbors, sizneighbors);- zmax_(Zmaxneighbors, sizneighbors);- zadd_(Znummergetot, facet->nummerge);- i= facet->nummerge; /* avoid warnings */- zmax_(Znummergemax, i);- if (!facet->simplicial) {- if (sizvertices == qh->hull_dim) {- zinc_(Znowsimplicial);- }else {- zinc_(Znonsimplicial);- }- }- if (sizridges) {- zadd_(Znumridges, sizridges);- zmax_(Zmaxridges, sizridges);- }- zadd_(Zmemfacets, sizeof(facetT) + qh->normal_size + 2*sizeof(setT)- + SETelemsize * (sizneighbors + sizvertices));- if (facet->ridges) {- zadd_(Zmemridges,- sizeof(setT) + SETelemsize * sizridges + sizridges *- (sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh->hull_dim-1))/2);- }- if (facet->outsideset)- zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->outsideset));- if (facet->coplanarset)- zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->coplanarset));- if (facet->seen) /* Delaunay upper envelope */- continue;- facet->seen= True;- FOREACHneighbor_(facet) {- if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge- || neighbor->seen || !facet->normal || !neighbor->normal)- continue;- dotproduct= qh_getangle(qh, facet->normal, neighbor->normal);- zinc_(Zangle);- wadd_(Wangle, dotproduct);- wmax_(Wanglemax, dotproduct)- wmin_(Wanglemin, dotproduct)- }- if (facet->normal) {- FOREACHvertex_(facet->vertices) {- zinc_(Zdiststat);- qh_distplane(qh, vertex->point, facet, &dist);- wmax_(Wvertexmax, dist);- wmin_(Wvertexmin, dist);- }- }- }- FORALLvertices {- if (vertex->deleted)- continue;- zadd_(Zmemvertices, sizeof(vertexT));- if (vertex->neighbors) {- sizneighbors= qh_setsize(qh, vertex->neighbors);- zadd_(Znumvneighbors, sizneighbors);- zmax_(Zmaxvneighbors, sizneighbors);- zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors);- }- }- qh->RANDOMdist= qh->old_randomdist;-} /* collectstatistics */-#endif /* qh_KEEPstatistics */--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="initstatistics">-</a>-- qh_initstatistics(qh)- initialize statistics-- notes:- NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr- On first call, only qhmem.ferr is defined. qh_memalloc is not setup.- Also invoked by QhullQh().-*/-void qh_initstatistics(qhT *qh) {- int i;- realT realx;- int intx;-- qh->qhstat.next= 0;- qh_allstatA(qh);- qh_allstatB(qh);- qh_allstatC(qh);- qh_allstatD(qh);- qh_allstatE(qh);- qh_allstatE2(qh);- qh_allstatF(qh);- qh_allstatG(qh);- qh_allstatH(qh);- qh_allstatI(qh);- if (qh->qhstat.next > (int)sizeof(qh->qhstat.id)) {- qh_fprintf(qh, qh->qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\- qhstat.next %d should be <= sizeof(qh->qhstat.id) %d\n", qh->qhstat.next, (int)sizeof(qh->qhstat.id));-#if 0 /* for locating error, Znumridges should be duplicated */- for(i=0; i < ZEND; i++) {- int j;- for(j=i+1; j < ZEND; j++) {- if (qh->qhstat.id[i] == qh->qhstat.id[j]) {- qh_fprintf(qh, qh->qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",- qh->qhstat.id[i], i, j);- }- }- }-#endif- qh_exit(qh_ERRqhull); /* can not use qh_errexit() */- }- qh->qhstat.init[zinc].i= 0;- qh->qhstat.init[zadd].i= 0;- qh->qhstat.init[zmin].i= INT_MAX;- qh->qhstat.init[zmax].i= INT_MIN;- qh->qhstat.init[wadd].r= 0;- qh->qhstat.init[wmin].r= REALmax;- qh->qhstat.init[wmax].r= -REALmax;- for(i=0; i < ZEND; i++) {- if (qh->qhstat.type[i] > ZTYPEreal) {- realx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r;- qh->qhstat.stats[i].r= realx;- }else if (qh->qhstat.type[i] != zdoc) {- intx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i;- qh->qhstat.stats[i].i= intx;- }- }-} /* initstatistics */--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="newstats">-</a>-- qh_newstats(qh, )- returns True if statistics for zdoc-- returns:- next zdoc-*/-boolT qh_newstats(qhT *qh, int idx, int *nextindex) {- boolT isnew= False;- int start, i;-- if (qh->qhstat.type[qh->qhstat.id[idx]] == zdoc)- start= idx+1;- else- start= idx;- for(i= start; i < qh->qhstat.next && qh->qhstat.type[qh->qhstat.id[i]] != zdoc; i++) {- if (!qh_nostatistic(qh, qh->qhstat.id[i]) && !qh->qhstat.printed[qh->qhstat.id[i]])- isnew= True;- }- *nextindex= i;- return isnew;-} /* newstats */--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="nostatistic">-</a>-- qh_nostatistic(qh, index )- true if no statistic to print-*/-boolT qh_nostatistic(qhT *qh, int i) {-- if ((qh->qhstat.type[i] > ZTYPEreal- &&qh->qhstat.stats[i].r == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r)- || (qh->qhstat.type[i] < ZTYPEreal- &&qh->qhstat.stats[i].i == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i))- return True;- return False;-} /* nostatistic */--#if qh_KEEPstatistics-/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="printallstatistics">-</a>-- qh_printallstatistics(qh, fp, string )- print all statistics with header 'string'-*/-void qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {-- qh_allstatistics(qh);- qh_collectstatistics(qh);- qh_printstatistics(qh, fp, string);- qh_memstatistics(qh, fp);-}---/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="printstatistics">-</a>-- qh_printstatistics(qh, fp, string )- print statistics to a file with header 'string'- skips statistics with qhstat.printed[] (reset with qh_allstatistics)-- see:- qh_printallstatistics()-*/-void qh_printstatistics(qhT *qh, FILE *fp, const char *string) {- int i, k;- realT ave;-- if (qh->num_points != qh->num_vertices) {- wval_(Wpbalance)= 0;- wval_(Wpbalance2)= 0;- }else- wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),- wval_(Wpbalance2), &ave);- wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),- wval_(Wnewbalance2), &ave);- qh_fprintf(qh, fp, 9350, "\n\-%s\n\- qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh->rbox_command,- qh->qhull_command, qh_version, qh->qhull_options);- qh_fprintf(qh, fp, 9351, "\nprecision constants:\n\- %6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\- %6.2g max. roundoff error for distance computation('En')\n\- %6.2g max. roundoff error for angle computations\n\- %6.2g min. distance for outside points ('Wn')\n\- %6.2g min. distance for visible facets ('Vn')\n\- %6.2g max. distance for coplanar facets ('Un')\n\- %6.2g max. facet width for recomputing centrum and area\n\-",- qh->MAXabs_coord, qh->DISTround, qh->ANGLEround, qh->MINoutside,- qh->MINvisible, qh->MAXcoplanar, qh->WIDEfacet);- if (qh->KEEPnearinside)- qh_fprintf(qh, fp, 9352, "\- %6.2g max. distance for near-inside points\n", qh->NEARinside);- if (qh->premerge_cos < REALmax/2) qh_fprintf(qh, fp, 9353, "\- %6.2g max. cosine for pre-merge angle\n", qh->premerge_cos);- if (qh->PREmerge) qh_fprintf(qh, fp, 9354, "\- %6.2g radius of pre-merge centrum\n", qh->premerge_centrum);- if (qh->postmerge_cos < REALmax/2) qh_fprintf(qh, fp, 9355, "\- %6.2g max. cosine for post-merge angle\n", qh->postmerge_cos);- if (qh->POSTmerge) qh_fprintf(qh, fp, 9356, "\- %6.2g radius of post-merge centrum\n", qh->postmerge_centrum);- qh_fprintf(qh, fp, 9357, "\- %6.2g max. distance for merging two simplicial facets\n\- %6.2g max. roundoff error for arithmetic operations\n\- %6.2g min. denominator for divisions\n\- zero diagonal for Gauss: ", qh->ONEmerge, REALepsilon, qh->MINdenom);- for(k=0; k < qh->hull_dim; k++)- qh_fprintf(qh, fp, 9358, "%6.2e ", qh->NEARzero[k]);- qh_fprintf(qh, fp, 9359, "\n\n");- for(i=0 ; i < qh->qhstat.next; )- qh_printstats(qh, fp, i, &i);-} /* printstatistics */-#endif /* qh_KEEPstatistics */--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="printstatlevel">-</a>-- qh_printstatlevel(qh, fp, id )- print level information for a statistic-- notes:- nop if id >= ZEND, printed, or same as initial value-*/-void qh_printstatlevel(qhT *qh, FILE *fp, int id) {-#define NULLfield " "-- if (id >= ZEND || qh->qhstat.printed[id])- return;- if (qh->qhstat.type[id] == zdoc) {- qh_fprintf(qh, fp, 9360, "%s\n", qh->qhstat.doc[id]);- return;- }- if (qh_nostatistic(qh, id) || !qh->qhstat.doc[id])- return;- qh->qhstat.printed[id]= True;- if (qh->qhstat.count[id] != -1- && qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i == 0)- qh_fprintf(qh, fp, 9361, " *0 cnt*");- else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] == -1)- qh_fprintf(qh, fp, 9362, "%7.2g", qh->qhstat.stats[id].r);- else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] != -1)- qh_fprintf(qh, fp, 9363, "%7.2g", qh->qhstat.stats[id].r/ qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);- else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] == -1)- qh_fprintf(qh, fp, 9364, "%7d", qh->qhstat.stats[id].i);- else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] != -1)- qh_fprintf(qh, fp, 9365, "%7.3g", (realT) qh->qhstat.stats[id].i / qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);- qh_fprintf(qh, fp, 9366, " %s\n", qh->qhstat.doc[id]);-} /* printstatlevel */---/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="printstats">-</a>-- qh_printstats(qh, fp, index, nextindex )- print statistics for a zdoc group-- returns:- next zdoc if non-null-*/-void qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex) {- int j, nexti;-- if (qh_newstats(qh, idx, &nexti)) {- qh_fprintf(qh, fp, 9367, "\n");- for (j=idx; j<nexti; j++)- qh_printstatlevel(qh, fp, qh->qhstat.id[j]);- }- if (nextindex)- *nextindex= nexti;-} /* printstats */--#if qh_KEEPstatistics--/*-<a href="qh-stat_r.htm#TOC"- >-------------------------------</a><a name="stddev">-</a>-- qh_stddev(num, tot, tot2, ave )- compute the standard deviation and average from statistics-- tot2 is the sum of the squares- notes:- computes r.m.s.:- (x-ave)^2- == x^2 - 2x tot/num + (tot/num)^2- == tot2 - 2 tot tot/num + tot tot/num- == tot2 - tot ave-*/-realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {- realT stddev;-- *ave= tot/num;- stddev= sqrt(tot2/num - *ave * *ave);- return stddev;-} /* stddev */--#endif /* qh_KEEPstatistics */--#if !qh_KEEPstatistics-void qh_collectstatistics(qhT *qh) {}-void qh_printallstatistics(qhT *qh, FILE *fp, char *string) {};-void qh_printstatistics(qhT *qh, FILE *fp, char *string) {}-#endif-
− C/user_r.c
@@ -1,527 +0,0 @@-/*<html><pre> -<a href="qh-user_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- user.c- user redefinable functions-- see user2_r.c for qh_fprintf, qh_malloc, qh_free-- see README.txt see COPYING.txt for copyright information.-- see libqhull_r.h for data structures, macros, and user-callable functions.-- see user_eg.c, user_eg2.c, and unix.c for examples.-- see user.h for user-definable constants-- use qh_NOmem in mem_r.h to turn off memory management- use qh_NOmerge in user.h to turn off facet merging- set qh_KEEPstatistics in user.h to 0 to turn off statistics-- This is unsupported software. You're welcome to make changes,- but you're on your own if something goes wrong. Use 'Tc' to- check frequently. Usually qhull will report an error if- a data structure becomes inconsistent. If so, it also reports- the last point added to the hull, e.g., 102. You can then trace- the execution of qhull with "T4P102".-- Please report any errors that you fix to qhull@qhull.org-- Qhull-template is a template for calling qhull from within your application-- if you recompile and load this module, then user.o will not be loaded- from qhull.a-- you can add additional quick allocation sizes in qh_user_memsizes-- if the other functions here are redefined to not use qh_print...,- then io.o will not be loaded from qhull.a. See user_eg_r.c for an- example. We recommend keeping io.o for the extra debugging- information it supplies.-*/--#include "qhull_ra.h"--#include <stdarg.h>--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="qhull_template">-</a>-- Qhull-template- Template for calling qhull from inside your program-- returns:- exit code(see qh_ERR... in libqhull_r.h)- all memory freed-- notes:- This can be called any number of times.--*/-#if 0-{- int dim; /* dimension of points */- int numpoints; /* number of points */- coordT *points; /* array of coordinates for each point */- boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */- char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */- FILE *outfile= stdout; /* output from qh_produce_output(qh)- use NULL to skip qh_produce_output(qh) */- FILE *errfile= stderr; /* error messages from qhull code */- int exitcode; /* 0 if no error from qhull */- facetT *facet; /* set by FORALLfacets */- int curlong, totlong; /* memory remaining after qh_memfreeshort */-- qhT qh_qh; /* Qhull's data structure. First argument of most calls */- qhT *qh= &qh_qh; /* Alternatively -- qhT *qh= (qhT*)malloc(sizeof(qhT)) */-- QHULL_LIB_CHECK /* Check for compatible library */-- qh_zero(qh, errfile);-- /* initialize dim, numpoints, points[], ismalloc here */- exitcode= qh_new_qhull(qh, dim, numpoints, points, ismalloc,- flags, outfile, errfile);- if (!exitcode) { /* if no error */- /* 'qh->facet_list' contains the convex hull */- FORALLfacets {- /* ... your code ... */- }- }- qh_freeqhull(qh, !qh_ALL);- qh_memfreeshort(qh, &curlong, &totlong);- if (curlong || totlong)- qh_fprintf(qh, errfile, 7068, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);-}-#endif--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="new_qhull">-</a>-- qh_new_qhull(qh, dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )- Run qhull and return results in qh.- Returns exitcode (0 if no errors).- Before first call, either call qh_zero(qh, errfile), or set qh to all zero.-- notes:- do not modify points until finished with results.- The qhull data structure contains pointers into the points array.- do not call qhull functions before qh_new_qhull().- The qhull data structure is not initialized until qh_new_qhull().- do not call qh_init_A (global_r.c)-- Default errfile is stderr, outfile may be null- qhull_cmd must start with "qhull "- projects points to a new point array for Delaunay triangulations ('d' and 'v')- transforms points into a new point array for halfspace intersection ('H')-- see:- Qhull-template at the beginning of this file.- An example of using qh_new_qhull is user_eg_r.c-*/-int qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,- char *qhull_cmd, FILE *outfile, FILE *errfile) {- /* gcc may issue a "might be clobbered" warning for dim, points, and ismalloc [-Wclobbered].- These parameters are not referenced after a longjmp() and hence not clobbered.- See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */- int exitcode, hulldim;- boolT new_ismalloc;- coordT *new_points;-- if(!errfile){- errfile= stderr;- }- if (!qh->qhmem.ferr) {- qh_meminit(qh, errfile);- } else {- qh_memcheck(qh);- }- if (strncmp(qhull_cmd, "qhull ", (size_t)6)) {- qh_fprintf(qh, errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \"\n");- return qh_ERRinput;- }- qh_initqhull_start(qh, NULL, outfile, errfile);- trace1((qh, qh->ferr, 1044, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));- exitcode = setjmp(qh->errexit);- if (!exitcode)- {- qh->NOerrexit = False;- qh_initflags(qh, qhull_cmd);- if (qh->DELAUNAY)- qh->PROJECTdelaunay= True;- if (qh->HALFspace) {- /* points is an array of halfspaces,- the last coordinate of each halfspace is its offset */- hulldim= dim-1;- qh_setfeasible(qh, hulldim);- new_points= qh_sethalfspace_all(qh, dim, numpoints, points, qh->feasible_point);- new_ismalloc= True;- if (ismalloc)- qh_free(points);- }else {- hulldim= dim;- new_points= points;- new_ismalloc= ismalloc;- }- qh_init_B(qh, new_points, numpoints, hulldim, new_ismalloc);- qh_qhull(qh);- qh_check_output(qh);- if (outfile) {- qh_produce_output(qh);- }else {- qh_prepare_output(qh);- }- if (qh->VERIFYoutput && !qh->STOPpoint && !qh->STOPcone)- qh_check_points(qh);- }- qh->NOerrexit = True;- return exitcode;-} /* new_qhull */--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="errexit">-</a>-- qh_errexit(qh, exitcode, facet, ridge )- report and exit from an error- report facet and ridge if non-NULL- reports useful information such as last point processed- set qh.FORCEoutput to print neighborhood of facet-- see:- qh_errexit2() in libqhull_r.c for printing 2 facets-- design:- check for error within error processing- compute qh.hulltime- print facet and ridge (if any)- report commandString, options, qh.furthest_id- print summary and statistics (including precision statistics)- if qh_ERRsingular- print help text for singular data set- exit program via long jump (if defined) or exit()-*/-void qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge) {-- if (qh->ERREXITcalled) {- qh_fprintf(qh, qh->ferr, 8126, "\nqhull error while processing previous error. Exit program\n");- qh_exit(qh_ERRqhull);- }- qh->ERREXITcalled= True;- if (!qh->QHULLfinished)- qh->hulltime= qh_CPUclock - qh->hulltime;- qh_errprint(qh, "ERRONEOUS", facet, NULL, ridge, NULL);- qh_fprintf(qh, qh->ferr, 8127, "\nWhile executing: %s | %s\n", qh->rbox_command, qh->qhull_command);- qh_fprintf(qh, qh->ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);- if (qh->furthest_id >= 0) {- qh_fprintf(qh, qh->ferr, 8129, "Last point added to hull was p%d.", qh->furthest_id);- if (zzval_(Ztotmerge))- qh_fprintf(qh, qh->ferr, 8130, " Last merge was #%d.", zzval_(Ztotmerge));- if (qh->QHULLfinished)- qh_fprintf(qh, qh->ferr, 8131, "\nQhull has finished constructing the hull.");- else if (qh->POSTmerging)- qh_fprintf(qh, qh->ferr, 8132, "\nQhull has started post-merging.");- qh_fprintf(qh, qh->ferr, 8133, "\n");- }- if (qh->FORCEoutput && (qh->QHULLfinished || (!facet && !ridge)))- qh_produce_output(qh);- else if (exitcode != qh_ERRinput) {- if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh->hull_dim+1) {- qh_fprintf(qh, qh->ferr, 8134, "\nAt error exit:\n");- qh_printsummary(qh, qh->ferr);- if (qh->PRINTstatistics) {- qh_collectstatistics(qh);- qh_printstatistics(qh, qh->ferr, "at error exit");- qh_memstatistics(qh, qh->ferr);- }- }- if (qh->PRINTprecision)- qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);- }- if (!exitcode)- exitcode= qh_ERRqhull;- else if (exitcode == qh_ERRsingular)- qh_printhelp_singular(qh, qh->ferr);- else if (exitcode == qh_ERRprec && !qh->PREmerge)- qh_printhelp_degenerate(qh, qh->ferr);- if (qh->NOerrexit) {- qh_fprintf(qh, qh->ferr, 6187, "qhull error while ending program, or qh->NOerrexit not cleared after setjmp(). Exit program with error.\n");- qh_exit(qh_ERRqhull);- }- qh->ERREXITcalled= False;- qh->NOerrexit= True;- qh->ALLOWrestart= False; /* longjmp will undo qh_build_withrestart */- longjmp(qh->errexit, exitcode);-} /* errexit */---/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="errprint">-</a>-- qh_errprint(qh, fp, string, atfacet, otherfacet, atridge, atvertex )- prints out the information of facets and ridges to fp- also prints neighbors and geomview output-- notes:- except for string, any parameter may be NULL-*/-void qh_errprint(qhT *qh, const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {- int i;-- if (atfacet) {- qh_fprintf(qh, qh->ferr, 8135, "%s FACET:\n", string);- qh_printfacet(qh, qh->ferr, atfacet);- }- if (otherfacet) {- qh_fprintf(qh, qh->ferr, 8136, "%s OTHER FACET:\n", string);- qh_printfacet(qh, qh->ferr, otherfacet);- }- if (atridge) {- qh_fprintf(qh, qh->ferr, 8137, "%s RIDGE:\n", string);- qh_printridge(qh, qh->ferr, atridge);- if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)- qh_printfacet(qh, qh->ferr, atridge->top);- if (atridge->bottom- && atridge->bottom != atfacet && atridge->bottom != otherfacet)- qh_printfacet(qh, qh->ferr, atridge->bottom);- if (!atfacet)- atfacet= atridge->top;- if (!otherfacet)- otherfacet= otherfacet_(atridge, atfacet);- }- if (atvertex) {- qh_fprintf(qh, qh->ferr, 8138, "%s VERTEX:\n", string);- qh_printvertex(qh, qh->ferr, atvertex);- }- if (qh->fout && qh->FORCEoutput && atfacet && !qh->QHULLfinished && !qh->IStracing) {- qh_fprintf(qh, qh->ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n");- for (i=0; i < qh_PRINTEND; i++) /* use fout for geomview output */- qh_printneighborhood(qh, qh->fout, qh->PRINTout[i], atfacet, otherfacet,- !qh_ALL);- }-} /* errprint */---/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="printfacetlist">-</a>-- qh_printfacetlist(qh, fp, facetlist, facets, printall )- print all fields for a facet list and/or set of facets to fp- if !printall,- only prints good facets-- notes:- also prints all vertices-*/-void qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall) {- facetT *facet, **facetp;-- qh_printbegin(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);- FORALLfacet_(facetlist)- qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);- FOREACHfacet_(facets)- qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);- qh_printend(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);-} /* printfacetlist */---/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printhelp_degenerate">-</a>-- qh_printhelp_degenerate(qh, fp )- prints descriptive message for precision error-- notes:- no message if qh_QUICKhelp-*/-void qh_printhelp_degenerate(qhT *qh, FILE *fp) {-- if (qh->MERGEexact || qh->PREmerge || qh->JOGGLEmax < REALmax/2)- qh_fprintf(qh, fp, 9368, "\n\-A Qhull error has occurred. Qhull should have corrected the above\n\-precision error. Please send the input and all of the output to\n\-qhull_bug@qhull.org\n");- else if (!qh_QUICKhelp) {- qh_fprintf(qh, fp, 9369, "\n\-Precision problems were detected during construction of the convex hull.\n\-This occurs because convex hull algorithms assume that calculations are\n\-exact, but floating-point arithmetic has roundoff errors.\n\-\n\-To correct for precision problems, do not use 'Q0'. By default, Qhull\n\-selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\-Qhull joggles the input to prevent precision problems. See \"Imprecision\n\-in Qhull\" (qh-impre.htm).\n\-\n\-If you use 'Q0', the output may include\n\-coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\-Qhull may produce a ridge with four neighbors or two facets with the same \n\-vertices. Qhull reports these events when they occur. It stops when a\n\-concave ridge, flipped facet, or duplicate facet occurs.\n");-#if REALfloat- qh_fprintf(qh, fp, 9370, "\-\n\-Qhull is currently using single precision arithmetic. The following\n\-will probably remove the precision problems:\n\- - recompile qhull for realT precision(#define REALfloat 0 in user.h).\n");-#endif- if (qh->DELAUNAY && !qh->SCALElast && qh->MAXabs_coord > 1e4)- qh_fprintf(qh, fp, 9371, "\-\n\-When computing the Delaunay triangulation of coordinates > 1.0,\n\- - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");- if (qh->DELAUNAY && !qh->ATinfinity)- qh_fprintf(qh, fp, 9372, "\-When computing the Delaunay triangulation:\n\- - use 'Qz' to add a point at-infinity. This reduces precision problems.\n");-- qh_fprintf(qh, fp, 9373, "\-\n\-If you need triangular output:\n\- - use option 'Qt' to triangulate the output\n\- - use option 'QJ' to joggle the input points and remove precision errors\n\- - use option 'Ft'. It triangulates non-simplicial facets with added points.\n\-\n\-If you must use 'Q0',\n\-try one or more of the following options. They can not guarantee an output.\n\- - use 'QbB' to scale the input to a cube.\n\- - use 'Po' to produce output and prevent partitioning for flipped facets\n\- - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\- - use 'En' to specify a maximum roundoff error less than %2.2g.\n\- - options 'Qf', 'Qbb', and 'QR0' may also help\n",- qh->DISTround);- qh_fprintf(qh, fp, 9374, "\-\n\-To guarantee simplicial output:\n\- - use option 'Qt' to triangulate the output\n\- - use option 'QJ' to joggle the input points and remove precision errors\n\- - use option 'Ft' to triangulate the output by adding points\n\- - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\-");- }-} /* printhelp_degenerate */---/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="printhelp_narrowhull">-</a>-- qh_printhelp_narrowhull(qh, minangle )- Warn about a narrow hull-- notes:- Alternatively, reduce qh_WARNnarrow in user.h--*/-void qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle) {-- qh_fprintf(qh, fp, 9375, "qhull precision warning: \n\-The initial hull is narrow (cosine of min. angle is %.16f).\n\-Is the input lower dimensional (e.g., on a plane in 3-d)? Qhull may\n\-produce a wide facet. Options 'QbB' (scale to unit box) or 'Qbb' (scale\n\-last coordinate) may remove this warning. Use 'Pp' to skip this warning.\n\-See 'Limitations' in qh-impre.htm.\n",- -minangle); /* convert from angle between normals to angle between facets */-} /* printhelp_narrowhull */--/*-<a href="qh-io_r.htm#TOC"- >-------------------------------</a><a name="printhelp_singular">-</a>-- qh_printhelp_singular(qh, fp )- prints descriptive message for singular input-*/-void qh_printhelp_singular(qhT *qh, FILE *fp) {- facetT *facet;- vertexT *vertex, **vertexp;- realT min, max, *coord, dist;- int i,k;-- qh_fprintf(qh, fp, 9376, "\n\-The input to qhull appears to be less than %d dimensional, or a\n\-computation has overflowed.\n\n\-Qhull could not construct a clearly convex simplex from points:\n",- qh->hull_dim);- qh_printvertexlist(qh, fp, "", qh->facet_list, NULL, qh_ALL);- if (!qh_QUICKhelp)- qh_fprintf(qh, fp, 9377, "\n\-The center point is coplanar with a facet, or a vertex is coplanar\n\-with a neighboring facet. The maximum round off error for\n\-computing distances is %2.2g. The center point, facets and distances\n\-to the center point are as follows:\n\n", qh->DISTround);- qh_printpointid(qh, fp, "center point", qh->hull_dim, qh->interior_point, qh_IDunknown);- qh_fprintf(qh, fp, 9378, "\n");- FORALLfacets {- qh_fprintf(qh, fp, 9379, "facet");- FOREACHvertex_(facet->vertices)- qh_fprintf(qh, fp, 9380, " p%d", qh_pointid(qh, vertex->point));- zinc_(Zdistio);- qh_distplane(qh, qh->interior_point, facet, &dist);- qh_fprintf(qh, fp, 9381, " distance= %4.2g\n", dist);- }- if (!qh_QUICKhelp) {- if (qh->HALFspace)- qh_fprintf(qh, fp, 9382, "\n\-These points are the dual of the given halfspaces. They indicate that\n\-the intersection is degenerate.\n");- qh_fprintf(qh, fp, 9383,"\n\-These points either have a maximum or minimum x-coordinate, or\n\-they maximize the determinant for k coordinates. Trial points\n\-are first selected from points that maximize a coordinate.\n");- if (qh->hull_dim >= qh_INITIALmax)- qh_fprintf(qh, fp, 9384, "\n\-Because of the high dimension, the min x-coordinate and max-coordinate\n\-points are used if the determinant is non-zero. Option 'Qs' will\n\-do a better, though much slower, job. Instead of 'Qs', you can change\n\-the points by randomly rotating the input with 'QR0'.\n");- }- qh_fprintf(qh, fp, 9385, "\nThe min and max coordinates for each dimension are:\n");- for (k=0; k < qh->hull_dim; k++) {- min= REALmax;- max= -REALmin;- for (i=qh->num_points, coord= qh->first_point+k; i--; coord += qh->hull_dim) {- maximize_(max, *coord);- minimize_(min, *coord);- }- qh_fprintf(qh, fp, 9386, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);- }- if (!qh_QUICKhelp) {- qh_fprintf(qh, fp, 9387, "\n\-If the input should be full dimensional, you have several options that\n\-may determine an initial simplex:\n\- - use 'QJ' to joggle the input and make it full dimensional\n\- - use 'QbB' to scale the points to the unit cube\n\- - use 'QR0' to randomly rotate the input for different maximum points\n\- - use 'Qs' to search all points for the initial simplex\n\- - use 'En' to specify a maximum roundoff error less than %2.2g.\n\- - trace execution with 'T3' to see the determinant for each point.\n",- qh->DISTround);-#if REALfloat- qh_fprintf(qh, fp, 9388, "\- - recompile qhull for realT precision(#define REALfloat 0 in libqhull_r.h).\n");-#endif- qh_fprintf(qh, fp, 9389, "\n\-If the input is lower dimensional:\n\- - use 'QJ' to joggle the input and make it full dimensional\n\- - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\- pick the coordinate with the least range. The hull will have the\n\- correct topology.\n\- - determine the flat containing the points, rotate the points\n\- into a coordinate plane, and delete the other coordinates.\n\- - add one or more points to make the input full dimensional.\n\-");- }-} /* printhelp_singular */--/*-<a href="qh-globa_r.htm#TOC"- >-------------------------------</a><a name="user_memsizes">-</a>-- qh_user_memsizes(qh)- allocate up to 10 additional, quick allocation sizes-- notes:- increase maximum number of allocations in qh_initqhull_mem()-*/-void qh_user_memsizes(qhT *qh) {-- QHULL_UNUSED(qh)- /* qh_memsize(qh, size); */-} /* user_memsizes */--
− C/usermem_r.c
@@ -1,94 +0,0 @@-/*<html><pre> -<a href="qh-user_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- usermem_r.c- qh_exit(), qh_free(), and qh_malloc()-- See README.txt.-- If you redefine one of these functions you must redefine all of them.- If you recompile and load this file, then usermem.o will not be loaded- from qhull.a or qhull.lib-- See libqhull_r.h for data structures, macros, and user-callable functions.- See user_r.c for qhull-related, redefinable functions- see user_r.h for user-definable constants- See userprintf_r.c for qh_fprintf and userprintf_rbox_r.c for qh_fprintf_rbox-- Please report any errors that you fix to qhull@qhull.org-*/--#include "libqhull_r.h"--#include <stdarg.h>-#include <stdlib.h>--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="qh_exit">-</a>-- qh_exit( exitcode )- exit program-- notes:- qh_exit() is called when qh_errexit() and longjmp() are not available.-- This is the only use of exit() in Qhull- To replace qh_exit with 'throw', see libqhullcpp/usermem_r-cpp.cpp-*/-void qh_exit(int exitcode) {- exit(exitcode);-} /* exit */--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="qh_fprintf_stderr">-</a>-- qh_fprintf_stderr( msgcode, format, list of args )- fprintf to stderr with msgcode (non-zero)-- notes:- qh_fprintf_stderr() is called when qh->ferr is not defined, usually due to an initialization error- - It is typically followed by qh_errexit().-- Redefine this function to avoid using stderr-- Use qh_fprintf [userprintf_r.c] for normal printing-*/-void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {- va_list args;-- va_start(args, fmt);- if(msgcode)- fprintf(stderr, "QH%.4d ", msgcode);- vfprintf(stderr, fmt, args);- va_end(args);-} /* fprintf_stderr */--/*-<a href="qh-user_r.htm#TOC"->-------------------------------</a><a name="qh_free">-</a>-- qh_free(qhT *qh, mem )- free memory-- notes:- same as free()- No calls to qh_errexit() -*/-void qh_free(void *mem) {- free(mem);-} /* free */--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="qh_malloc">-</a>-- qh_malloc( mem )- allocate memory-- notes:- same as malloc()-*/-void *qh_malloc(size_t size) {- return malloc(size);-} /* malloc */--
− C/userprintf_r.c
@@ -1,65 +0,0 @@-/*<html><pre> -<a href="qh-user_r.htm"- >-------------------------------</a><a name="TOP">-</a>-- userprintf_r.c- qh_fprintf()-- see README.txt see COPYING.txt for copyright information.-- If you recompile and load this file, then userprintf_r.o will not be loaded- from qhull.a or qhull.lib-- See libqhull_r.h for data structures, macros, and user-callable functions.- See user_r.c for qhull-related, redefinable functions- see user_r.h for user-definable constants- See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()- see Qhull.cpp and RboxPoints.cpp for examples.-- Please report any errors that you fix to qhull@qhull.org-*/--#include "libqhull_r.h"--#include <stdarg.h>-#include <stdio.h>-#include <stdlib.h>--/*-<a href="qh-user_r.htm#TOC"- >-------------------------------</a><a name="qh_fprintf">-</a>-- qh_fprintf(qh, fp, msgcode, format, list of args )- print arguments to *fp according to format- Use qh_fprintf_rbox() for rboxlib_r.c-- notes:- same as fprintf()- fgets() is not trapped like fprintf()- exit qh_fprintf via qh_errexit()- may be called for errors in qh_initstatistics and qh_meminit-*/--void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {- va_list args;-- if (!fp) {- if(!qh){- qh_fprintf_stderr(6241, "userprintf_r.c: fp and qh not defined for qh_fprintf '%s'", fmt);- qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */- }- /* could use qh->qhmem.ferr, but probably better to be cautious */- qh_fprintf_stderr(6232, "Qhull internal error (userprintf_r.c): fp is 0. Wrong qh_fprintf called.\n");- qh_errexit(qh, 6232, NULL, NULL);- }- va_start(args, fmt);- if (qh && qh->ANNOTATEoutput) {- fprintf(fp, "[QH%.4d]", msgcode);- }else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {- fprintf(fp, "QH%.4d ", msgcode);- }- vfprintf(fp, fmt, args);- va_end(args);-- /* Place debugging traps here. Use with option 'Tn' */--} /* qh_fprintf */-
− C/utils.c
@@ -1,91 +0,0 @@-#include <stdlib.h> // to use realloc-#include <math.h> // to use NAN-#include <stdio.h> // to use printf--double* getpoint(double* points, unsigned dim, unsigned id){- double* out = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- out[i] = points[id*dim+i];- }- return out;-}--/* dot product of two vectors */-double dotproduct(double* p1, double* p2, unsigned dim){- double out = 0;- for(unsigned i=0; i < dim; i++){- out += p1[i] * p2[i];- }- return out;-}--/* middle of segment [p1,p2] */-double* middle(double* p1, double* p2, unsigned dim){- double* out = malloc(dim * sizeof(double));- for(unsigned i=0; i<dim; i++){- out[i] = (p1[i] + p2[i])/2;- }- return out;-}--/* vector of NANs */-double* nanvector(int dim){- double* out = malloc(dim * sizeof(double));- for(unsigned i=0; i < dim; i++){- out[i] = NAN;- }- return out;-}--// to use the qsort function-int cmpfunc (const void * a, const void * b) {- return ( *(int*)a - *(int*)b );-}-int cmpfuncdbl (const void * a, const void * b) {- return ( *(double*)a - *(double*)b > 0 ? 1 : -1);-}-void qsortu(unsigned* vector, unsigned length){- qsort(vector, length, sizeof(unsigned), cmpfunc);-}---double square(double x){- return x*x;-}--/* append to a vector of unsigned */-void appendu(unsigned x, unsigned** array, unsigned length, unsigned* flag){- *flag = 1;- for(unsigned i=0; i<length; i++){- if(x==*(*array + i)){- *flag = 0;- break;- }- }- if(*flag==1){- *array = realloc(*array, (length+1)*sizeof(unsigned));- if(*array == NULL){- printf("realloc failure - exiting");- exit(1);- }- *(*array + length) = x;- }-}--/* make a vector of zeros */-unsigned* uzeros(unsigned length){- unsigned* out = malloc(length * sizeof(unsigned));- for(unsigned i=0; i < length; i++){- out[i] = 0;- }- return out;-}--/* squared distance between two points */-double squaredDistance(double* p1, double* p2, unsigned dim){- double out = 0;- for(unsigned i=0; i < dim; i++){- out += square(p1[i] - p2[i]);- }- return out;-}
+ Cdir/convexhull.c view
@@ -0,0 +1,714 @@+#define qh_QHimport+#include "qhull_ra.h"+#include "convexhull.h"+#include "utils.h"++// to use the qsort function - sort vertices according to their ids+int cmpvertices (const void * a, const void * b) {+ return ( (*((VertexT*)a)).id - (*((VertexT*)b)).id );+}+// - sort full vertices+int cmpfullvertices (const void * a, const void * b) {+ return ( (*((FullVertexT*)a)).id - (*((FullVertexT*)b)).id );+}+// - sort edges+int cmpedges (const void * a, const void * b) {+ if((*(unsigned**)a)[0] > (*(unsigned**)b)[0]){+ return 1;+ }else if((*(unsigned**)a)[0] == (*(unsigned**)b)[0]){+ return (*(unsigned**)a)[1] - (*(unsigned**)b)[1];+ }else{+ return -1;+ }+}++/* test equality of two _sorted_ arrays */+unsigned equalarraysu(unsigned* array1, unsigned* array2, unsigned length){+ unsigned i;+ for(i=0; i < length; i++){+ if(array1[i] != array2[i]){+ break;+ }+ }+ return i == length;+}++/* return ids of a vector of VertexT */+unsigned* map_vertexid(VertexT* vertices, unsigned nvertices){+ unsigned* ids = malloc(nvertices * sizeof(unsigned));+ for(unsigned v=0; v < nvertices; v++){+ ids[v] = vertices[v].id;+ }+ return ids;+}++/* return ids of a vector of RidgeT */+unsigned* map_ridgeid(RidgeT* ridges, unsigned nridges){+ unsigned* ids = malloc(nridges * sizeof(unsigned));+ for(unsigned r=0; r < nridges; r++){+ ids[r] = ridges[r].id;+ }+ return ids;+}++// void deepCopyRidge(RidgeT* src, RidgeT* dest) { et dim !+// dest = malloc(sizeof(RidgeT));+// *dest = *src;+// dest->vertices = malloc(src->nvertices * sizeof(VertexT));+// for(unsigned v=0; v<src->nvertices; v++){+// dest->vertices[v].id = src.vertices[v].id;+// memcpy(dest->vertices[v].point, dest->vertices[v].point, dim * sizeof(double));+// }+// }++/* deep copy of a ridge */+RidgeT copyRidge(RidgeT ridge, unsigned dim){+ RidgeT out;+ out.ridgeOf1 = ridge.ridgeOf1;+ out.ridgeOf2 = ridge.ridgeOf2;+ out.nvertices = ridge.nvertices;+ out.nedges = ridge.nedges;+ out.vertices = malloc(out.nvertices * sizeof(VertexT));+ for(unsigned v=0; v < out.nvertices; v++){+ out.vertices[v].id = ridge.vertices[v].id;+ out.vertices[v].point = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ out.vertices[v].point[i] = ridge.vertices[v].point[i];+ }+ }+ // out.edges = malloc(out.nedges * sizeof(unsigned*));+ // for(unsigned e=0; e < out.nedges; e++){+ // out.edges[e] = malloc(2 * sizeof(unsigned));+ // out.edges[e][0] = ridge.edges[e][0];+ // out.edges[e][1] = ridge.edges[e][1];+ // }+ return out;+}++/* append to a vector of VertexT */+void appendv(VertexT x, VertexT** array, unsigned length, unsigned* flag){+ *flag = 1;+ for(unsigned i=0; i < length; i++){+ if(x.id == (*(*array + i)).id){+ *flag = 0;+ break;+ }+ }+ if(*flag == 1){+ *array = realloc(*array, (length+1) * sizeof(VertexT));+ if(*array == NULL){+ printf("realloc failure - exiting\n");+ exit(1);+ }+ *(*array + length) = x;+ }+}++/* union of two vectors of VertexT */+void unionv(VertexT** vs1, VertexT* vs2, unsigned l1, unsigned l2, unsigned* l){+ *l = l1;+ for(unsigned v=0; v < l2; v++){+ unsigned pushed;+ appendv(vs2[v], vs1, *l, &pushed);+ if(pushed){+ (*l)++;+ }+ }+ /* sort vertices according to their ids */+ qsort(*vs1, *l, sizeof(VertexT), cmpvertices);+}++/* merge ridges with same ridgeOf's */+RidgeT* mergeRidges(RidgeT* ridges, unsigned nridges, unsigned* newlength){+ // http://www.c4learn.com/c-programs/to-delete-duplicate-elements-in-array.html+ *newlength = nridges;+ unsigned i,j,k;+ for(i = 0; i < nridges; i++){+ for(j = i+1; j < nridges; ){+ if(ridges[i].ridgeOf1 == ridges[j].ridgeOf1 &&+ ridges[i].ridgeOf2 == ridges[j].ridgeOf2)+ {+ unsigned l;+ unionv(&(ridges[i].vertices), ridges[j].vertices,+ ridges[i].nvertices, ridges[j].nvertices, &l);+ ridges[i].nvertices = l;+ (*newlength)--;+ for(k = j; k+1 < nridges; k++){+ ridges[k] = ridges[k+1];+ }+ nridges--;+ }else{+ j++;+ }+ }+ }+ RidgeT* out = malloc(*newlength * sizeof(RidgeT));+ for(unsigned r=0; r < *newlength; r++){+ out[r] = ridges[r];+ }+ return out;+}++/* all ridges from the ridges stored in the faces */+RidgeT* allRidges(FaceT *faces, unsigned nfaces, unsigned dim, unsigned* length){+ RidgeT* out = malloc(faces[0].nridges * sizeof(RidgeT));+ for(unsigned i=0; i < faces[0].nridges; i++){+ out[i] = copyRidge(faces[0].ridges[i], dim);+ out[i].id = i;+ out[i].nedges = 0;+ // RidgeT out[i];+ // deepCopyRidge(&(faces[0].ridges[i]), &(out[i]));+ }+ *length = faces[0].nridges;+ unsigned n = faces[0].nridges;+ for(unsigned f=1; f < nfaces; f++){+ for(unsigned j=0; j < faces[f].nridges; j++){+ unsigned count = 0;+ for(unsigned i=0; i < n; i++){+ unsigned flag = 0;+ for(unsigned v=0; v < faces[f].ridges[j].nvertices; v++){+ if(faces[f].ridges[j].vertices[v].id != out[i].vertices[v].id){+ flag = 1;+ break;+ }+ }+ if(flag){+ count++;+ }else{+ break;+ }+ }+ if(count == n){+ out = realloc(out, (*length+1) * sizeof(RidgeT));+ if(out == NULL){+ printf("realloc failure - exiting\n");+ exit(1);+ }+ out[*length] = copyRidge(faces[f].ridges[j], dim);+ out[*length].id = *length;+ out[*length].nedges = 0;+ // RidgeT out[*length];+ // deepCopyRidge(&(faces[f].ridges[j]), &(out[*length]));+ (*length)++;+ }+ }+ n = *length;+ }+ return out;+}++/* assign ids to the ridges stored in the faces */+void assignRidgesIds(FaceT** faces, unsigned nfaces, RidgeT* allridges,+ unsigned nallridges)+{+ for(unsigned f=0; f < nfaces; f++){+ for(unsigned fr=0; fr < (*(*faces + f)).nridges; fr++){+ for(unsigned r=0; r < nallridges; r++){+ if((allridges[r].nvertices == (*(*faces + f)).ridges[fr].nvertices) &&+ equalarraysu(map_vertexid(allridges[r].vertices,+ allridges[r].nvertices),+ map_vertexid((*(*faces + f)).ridges[fr].vertices,+ allridges[r].nvertices),+ allridges[r].nvertices))+ {+ (*(*faces + f)).ridges[fr].id = allridges[r].id;+ break;+ }+ }+ }+ }+}++// double* ridgeCentroid(RidgeT ridge, unsigned dim){+// double* out = malloc(dim * sizeof(double));+// for(unsigned i=0; i<dim; i++){+// out[i] = 0;+// for(unsigned v=0; v<dim-1; v++){+// out[i] += ridge.vertices[v].point[i];+// }+// out[i] /= dim - 1;+// }+// return out;+// }++/* the threshold distance to detect neighbor vertices */+double ridgeMaxDistance(RidgeT ridge, unsigned v, unsigned dim){+ double dists[ridge.nvertices-1];+ unsigned count = 0;+ for(unsigned w=0; w < ridge.nvertices; w++){+ if(w != v){+ dists[count] = squaredDistance(ridge.vertices[v].point,+ ridge.vertices[w].point, dim);+ count++;+ }+ }+ qsort(dists, ridge.nvertices-1, sizeof(double), cmpfuncdbl);+ return dists[1];+}++/* neighbor vertices of a vertex from all ridges, for dim>2 */+unsigned* neighVertices(unsigned id, RidgeT* allridges, unsigned nridges,+ unsigned dim, unsigned triangulate, unsigned* lengthout)+{+ unsigned* neighs = malloc(0);+ *lengthout = 0;+ for(unsigned e=0; e < nridges; e++){+ for(unsigned v=0; v < allridges[e].nvertices; v++){+ if(id == allridges[e].vertices[v].id){+ for(unsigned w=0; w < allridges[e].nvertices; w++){+ if(w != v && (triangulate || dim == 3 || // dim3 pas besoin de tester la distance: il n'y a que deux vertices connectés+ squaredDistance(allridges[e].vertices[w].point,+ allridges[e].vertices[v].point, dim) <=+ ridgeMaxDistance(allridges[e], v, dim)))+ {+ unsigned pushed;+ appendu(allridges[e].vertices[w].id, &neighs, *lengthout, &pushed);+ if(pushed){+ (*lengthout)++;+ }+ }+ }+ break;+ }+ }+ }+ return neighs;+}++/* neighbor ridges of a vertex */+unsigned* neighRidges(unsigned id, RidgeT* allridges, unsigned nridges,+ unsigned* length)+{+ unsigned* neighs = malloc(0);+ *length = 0;+ for(unsigned e=0; e < nridges; e++){+ unsigned flag = 0;+ for(unsigned v=0; v < allridges[e].nvertices; v++){+ if(id == allridges[e].vertices[v].id){+ flag = 1;+ break;+ }+ }+ if(flag){+ neighs = realloc(neighs, (*length+1)*sizeof(unsigned));+ if(neighs == NULL){+ printf("realloc failure - exiting\n");+ exit(1);+ }+ neighs[*length] = e;+ (*length)++;+ }+ }+ return neighs;+}++/* whether distinct x1 and x2 belong to array of distinct values */+unsigned areElementsOf(unsigned x1, unsigned x2, unsigned* array,+ unsigned length)+{+ unsigned count = 0;+ for(unsigned i=0; (i < length) && (count < 2); i++){+ if(x1 == array[i] || x2 == array[i]){+ count++;+ }+ }+ return count==2;+}++/* make face/ridge edges from all edges */+unsigned** makeEdges(SetOfVerticesT face, unsigned** alledges,+ unsigned nalledges, unsigned* lengthout)+{+ *lengthout = 0;+ unsigned* faceverticesids = map_vertexid(face.vertices, face.nvertices);+ unsigned flags[nalledges];+ for(unsigned e=0; e < nalledges; e++){+ if(areElementsOf(alledges[e][0], alledges[e][1], faceverticesids,+ face.nvertices))+ {+ flags[e] = 1;+ (*lengthout)++;+ }else{+ flags[e] = 0;+ }+ }+ unsigned** out = malloc(*lengthout * sizeof(unsigned*));+ unsigned count = 0;+ for(unsigned e=0; e < nalledges; e++){+ if(flags[e] == 1){+ out[count] = alledges[e];+ count++;+ }+ }+ return out;+}++/* all edges from all vertices */+unsigned** allEdges(FullVertexT* vertices, unsigned nvertices,+ unsigned outlength)+{+ unsigned** out = malloc(outlength * sizeof(unsigned*));+ for(unsigned i=0; i < vertices[0].nneighsvertices; i++){+ out[i] = malloc(2 * sizeof(unsigned));+ out[i][0] = vertices[0].id;+ out[i][1] = vertices[0].neighvertices[i];+ qsortu(out[i], 2);+ }+ unsigned n = vertices[0].nneighsvertices;+ for(unsigned v=1; v < nvertices; v++){+ unsigned ids[2];+ for(unsigned i=0; i < vertices[v].nneighsvertices; i++){+ ids[0] = vertices[v].id;+ ids[1] = vertices[v].neighvertices[i];+ qsortu(ids, 2);+ unsigned j;+ for(j=0; j < n; j++){+ if(ids[0] == out[j][0] && ids[1] == out[j][1]){+ break;+ }+ }+ if(j == n){+ out[n] = malloc(2 * sizeof(unsigned));+ out[n][0] = ids[0]; out[n][1] = ids[1];+ n++;+ }+ if(n == outlength){+ break;+ }+ }+ if(n == outlength){+ break;+ }+ }+ return out;+}++// ATTENTION avec Qt le center dans facet->center est le centre de l'union des triangles,+// (ainsi que normal et offset mais ça ok)++// un ridge est simplicial ; pour l'hypercube il y a 2 ridges entre 2 faces,+// ils forment le carré à l'intersection++/* main function */+ConvexHullT* convexHull(+ double* points,+ unsigned dim,+ unsigned n,+ unsigned triangulate,+ unsigned print,+ char* summaryFile,+ unsigned* exitcode+)+{+ char opts[250]; /* option flags for qhull, see qh_opt.htm */+ sprintf(opts, "qhull s FF %s", triangulate ? "Qt" : "");+ qhT qh_qh; /* Qhull's data structure */+ qhT *qh= &qh_qh;+ QHULL_LIB_CHECK+ qh_meminit(qh, stderr);+ boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */+ FILE *errfile = NULL;+ FILE* outfile;+ if(print){+ outfile = stdout;+ }else{+ outfile = NULL;+ }+ qh_zero(qh, errfile);+ exitcode[0] = qh_new_qhull(qh, dim, n, points, ismalloc, opts, outfile,+ errfile);+ //fclose(tmpstdout);+ printf("exitcode: %u\n", exitcode[0]);++ ConvexHullT* out = malloc(sizeof(ConvexHullT));++ if (!exitcode[0]) { /* 0 if no error from qhull */++ /* print summary to file */+ if(*summaryFile != 0){+ FILE* sfile = fopen(summaryFile, "w");+ qh_printsummary(qh, sfile);+ fclose(sfile);+ }++ //qh_getarea(qh, qh->facet_list); // no triowner if I do that; do qh_facetarea, not facet->f.area++ unsigned nfaces = qh->num_facets;+ FaceT* faces = malloc(nfaces * sizeof(FaceT));+ {+ facetT *facet; unsigned i_facet = 0;+ FORALLfacets{+ facet->id = i_facet; /* for neighbors and ridgeOf */+ faces[i_facet].area = qh_facetarea(qh, facet);+ double* center = qh_getcenter(qh, facet->vertices);+ faces[i_facet].center = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ faces[i_facet].center[i] = center[i];+ }+ double* normal = facet->normal;+ faces[i_facet].normal = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ faces[i_facet].normal[i] = normal[i];+ }+ faces[i_facet].offset = facet->offset;+ faces[i_facet].nvertices = (unsigned) qh_setsize(qh, facet->vertices);+ { /* face vertices */+ faces[i_facet].vertices =+ (VertexT*) malloc(faces[i_facet].nvertices * sizeof(VertexT));+ vertexT *vertex, **vertexp;+ unsigned i_vertex = 0;+ FOREACHvertex_(facet->vertices){+ faces[i_facet].vertices[i_vertex].id =+ (unsigned) qh_pointid(qh, vertex->point);+ faces[i_facet].vertices[i_vertex].point =+ malloc(dim * sizeof(double));+ faces[i_facet].vertices[i_vertex].point =+ getpoint(points, dim, faces[i_facet].vertices[i_vertex].id);+ // plante dans Haskell: (faces[i_facet].vertices)[i_vertex].point = vertex->point;+ i_vertex++;+ }+ qsort(faces[i_facet].vertices, faces[i_facet].nvertices,+ sizeof(VertexT), cmpvertices);+ }+ if(dim == 3){ /* orientation of the normals */+ pointT* onepoint = ((vertexT*)facet->vertices->e[0].p)->point;+ double thepoint[dim]; /* onepoint+normal */+ for(unsigned i=0; i < dim; i++){+ thepoint[i] = onepoint[i] + faces[i_facet].normal[i];+ }+ /* we check that these two points are on the same side of the ridge */+ double h1 = dotproduct(qh->interior_point,+ faces[i_facet].normal, dim) ++ faces[i_facet].offset;+ double h2 = dotproduct(thepoint, faces[i_facet].normal, dim) ++ faces[i_facet].offset;+ if(h1*h2 > 0){+ for(unsigned i=0; i < dim; i++){+ faces[i_facet].normal[i] *= -1;+ }+ printf("change sign\n"); // seems to never occur+ }else{+ printf("not change sign\n");+ }+ }+ /**/+ i_facet++;+ }+ }++ { /* neighbor faces, faces families, and ridges */+ facetT *facet;+ unsigned i_facet = 0;+ FORALLfacets{+ {+ faces[i_facet].neighborsize = qh_setsize(qh, facet->neighbors);+ faces[i_facet].neighbors =+ malloc(faces[i_facet].neighborsize * sizeof(unsigned));+ unsigned i_neighbor = 0;+ facetT *neighbor, **neighborp;+ FOREACHneighbor_(facet){+ faces[i_facet].neighbors[i_neighbor] = (unsigned) neighbor->id;+ i_neighbor++;+ }+ qsortu(faces[i_facet].neighbors, faces[i_facet].neighborsize);+ }+ { /* face family, when option Qt */+ if(facet->tricoplanar){+ faces[i_facet].family = facet->f.triowner->id;+ }else{+ faces[i_facet].family = -1;+ }+ }+ { /* face ridges */+ qh_makeridges(qh, facet);+ unsigned nridges = qh_setsize(qh, facet->ridges);+ RidgeT* ridges = malloc(nridges * sizeof(RidgeT));+ ridgeT *ridge, **ridgep;+ unsigned i_ridge = 0;+ FOREACHridge_(facet->ridges){+ ridges[i_ridge].nedges = 0;+ unsigned ridgeSize = qh_setsize(qh, ridge->vertices); // dim-1+// printf("ridge size: %u\n", ridgeSize);+ ridges[i_ridge].nvertices = ridgeSize;+ unsigned ids[ridgeSize];+ for(unsigned v=0; v < ridgeSize; v++){+ ids[v] =+ qh_pointid(qh, ((vertexT*)ridge->vertices->e[v].p)->point);+ }+ qsortu(ids, ridgeSize);+ ridges[i_ridge].vertices = malloc(ridgeSize * sizeof(VertexT));+ for(unsigned v=0; v < ridgeSize; v++){+ ridges[i_ridge].vertices[v].id = ids[v];+ ridges[i_ridge].vertices[v].point = getpoint(points, dim, ids[v]);+ }+ unsigned ridgeofs[2];+ ridgeofs[0] = ridge->bottom->id;+ ridgeofs[1] = ridge->top->id;+ qsortu(ridgeofs, 2);+ ridges[i_ridge].ridgeOf1 = ridgeofs[0];+ ridges[i_ridge].ridgeOf2 = ridgeofs[1];+ /**/+ i_ridge++;+ }+ /* merge triangulated ridges */+ if(dim > 3 && !triangulate){+ unsigned l;+ faces[i_facet].ridges = mergeRidges(ridges, nridges, &l);+ faces[i_facet].nridges = l;+ }else{ /* dim 2 or 3, or triangulate option */+ faces[i_facet].ridges = ridges;+ faces[i_facet].nridges = nridges;+ }+ }+ /**/+ i_facet++;+ }+ }++ /* make unique ridges */+ unsigned n_allridges;+ RidgeT* allridges = allRidges(faces, nfaces, dim, &n_allridges);+// printf("nallridges: %u\n", n_allridges);++ /* assign ridges ids to the ridges stored in the faces */+ assignRidgesIds(&faces, nfaces, allridges, n_allridges);++ /* all vertices */+ unsigned nvertices = qh->num_vertices;+ FullVertexT* vertices = malloc(nvertices * sizeof(FullVertexT));+ {+ qh_vertexneighbors(qh); /* make the neighbor facets of the vertices */+ vertexT *vertex;+ unsigned i_vertex=0;+ FORALLvertices{+ /* vertex id and coordinates */+ vertices[i_vertex].id = (unsigned) qh_pointid(qh, vertex->point);+ vertices[i_vertex].point = getpoint(points, dim, vertices[i_vertex].id);++ /* neighbor facets of the vertex */+ vertices[i_vertex].nneighfacets = qh_setsize(qh, vertex->neighbors);+ vertices[i_vertex].neighfacets =+ malloc(vertices[i_vertex].nneighfacets * sizeof(unsigned));+ facetT *neighbor, **neighborp;+ unsigned i_neighbor = 0;+ FOREACHneighbor_(vertex){+ vertices[i_vertex].neighfacets[i_neighbor] = neighbor->id;+ i_neighbor++;+ }+ qsortu(vertices[i_vertex].neighfacets, vertices[i_vertex].nneighfacets);++ /* neighbor vertices of the vertex */+ if(dim > 2){+ unsigned nneighsvertices;+ vertices[i_vertex].neighvertices =+ neighVertices(vertices[i_vertex].id, allridges, n_allridges,+ dim, triangulate, &nneighsvertices);+ vertices[i_vertex].nneighsvertices = nneighsvertices;+ }else{ /* dim=2 */+ vertices[i_vertex].nneighsvertices = 2;+ vertices[i_vertex].neighvertices = malloc(2 * sizeof(unsigned));+ unsigned count = 0;+ for(unsigned f=0; f < nfaces; f++){+ for(unsigned i=0; i < 2; i++){+ if(faces[f].vertices[i].id == vertices[i_vertex].id){+ vertices[i_vertex].neighvertices[count] =+ faces[f].vertices[1-i].id;+ count++;+ break;+ }+ }+ if(count == 2){+ break;+ }+ }+ }+ qsortu(vertices[i_vertex].neighvertices,+ vertices[i_vertex].nneighsvertices);++ /* neighbor ridges of the vertex */+ if(dim > 2){+ unsigned nneighridges;+ vertices[i_vertex].neighridges =+ neighRidges(vertices[i_vertex].id, allridges, n_allridges,+ &nneighridges);+ qsortu(vertices[i_vertex].neighridges, nneighridges);+ vertices[i_vertex].nneighridges = nneighridges;+ }else{ /* dim=2 */+ vertices[i_vertex].nneighridges = 0; /* ridge = vertex singleton */+ }+ /**/+ i_vertex++;+ }+ /* sort vertices according to their ids */+ qsort(vertices, nvertices, sizeof(FullVertexT), cmpfullvertices);+ }++ /* all edges */+ unsigned nalledges = 0;+ for(unsigned v=0; v < nvertices; v++){+ nalledges += vertices[v].nneighsvertices;+ }+ nalledges /= 2;+ unsigned** alledges = allEdges(vertices, nvertices, nalledges);+ qsort(alledges, nalledges, sizeof(unsigned*), cmpedges);++ { /* faces edges and ridges ids */+ facetT *facet; unsigned i_facet=0;+ FORALLfacets{+ /* facet ridges ids */+ faces[i_facet].ridgesids =+ map_ridgeid(faces[i_facet].ridges, faces[i_facet].nridges);+ qsortu(faces[i_facet].ridgesids, faces[i_facet].nridges);+ /* facet edges */+ SetOfVerticesT facet_vset = {.vertices = faces[i_facet].vertices,+ .nvertices = faces[i_facet].nvertices};+ unsigned nfaceedges;+ faces[i_facet].edges =+ makeEdges(facet_vset, alledges, nalledges, &nfaceedges);+ //qsort(faces[i_facet].edges, nfaceedges, sizeof(unsigned*), cmpedges); useless, I think+ faces[i_facet].nedges = nfaceedges;+ /**/+ i_facet++;+ }+ }++ /* ridges edges */+ if(dim > 3){+ for(unsigned r=0; r < n_allridges; r++){+ unsigned facetid = allridges[r].ridgeOf1;+ SetOfVerticesT vset = {.vertices = allridges[r].vertices,+ .nvertices = allridges[r].nvertices};+ unsigned nedges;+ allridges[r].edges =+ makeEdges(vset, faces[facetid].edges, faces[facetid].nedges, &nedges);+ allridges[r].nedges = nedges;+ }+ }++ /* output */+ out->dim = dim;+ out->vertices = vertices;+ out->nvertices = nvertices;+ out->faces = faces;+ out->nfaces = nfaces;+ out->ridges = allridges;+ out->nridges = n_allridges;+ out->edges = alledges;+ out->nedges = nalledges;++ } // end if exitcode++ /* Do cleanup regardless of whether there is an error */+ int curlong, totlong;+ qh_freeqhull(qh, !qh_ALL); /* free long memory */+ qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */++ printf("RETURN\n");+ if(*exitcode){+ free(out);+ return 0;+ }else{+ return out;+ }++}
+ Cdir/delaunay.c view
@@ -0,0 +1,577 @@+#define qh_QHimport+#include "qhull_ra.h"+#include "delaunay.h"+#include "utils.h"+#include <math.h> /* to use NAN */++// void printfacet(qhT* qh, facetT* facet){+// vertexT *vertex, **vertexp;+// FOREACHvertex_(facet->vertices){+// printf("facetid: %d, pointid: %d ", facet->id, qh_pointid(qh, vertex->point));+// }+// }++unsigned facetOK_(facetT* facet, unsigned degenerate){+ return !facet->upperdelaunay && (degenerate || !facet->degenerate);+} // && simplicial, && !facet->redundant - pas de simplicial avec Qt++++TesselationT* tesselation(+ double* sites,+ unsigned dim,+ unsigned n,+ unsigned atinfinity,+ unsigned degenerate,+ double vthreshold,+ unsigned* exitcode+)+{+ char opts[50]; /* option flags for qhull, see qh_opt.htm */+ sprintf(opts, "qhull d Qt Qbb%s%s",+ atinfinity ? " Qz" : "", dim>3 ? " Qx" : "");+ qhT qh_qh; /* Qhull's data structure */+ qhT *qh= &qh_qh;+ QHULL_LIB_CHECK+ qh_meminit(qh, stderr);+ boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */+ FILE *errfile = NULL;+ FILE* outfile = NULL;+ qh_zero(qh, errfile);+ *exitcode = qh_new_qhull(qh, dim, n, sites, ismalloc, opts, outfile, errfile);+ //fclose(tmpstdout);+ printf("exitcode: %u\n", *exitcode);++ TesselationT* out = malloc(sizeof(TesselationT)); /* output */++ if (!(*exitcode)) { /* 0 if no error from qhull */++ /* Count the number of facets we keep */+ unsigned nfacets = 0; /* to store the number of facets */+ {+ facetT *facet; /* set by FORALLfacets */+ FORALLfacets {+ if(facetOK_(facet, degenerate)){+ facet->id = nfacets;+ nfacets++;+ }else{+ qh_removefacet(qh, facet);+ }+ }+ }++ /* Initialize the tiles */+ TileT* allfacets = malloc(nfacets * sizeof(TileT));++ { /* tiles families and volumes, and centers of tiles with >0 volume */+ facetT* facet;+ unsigned i_facet = 0;+ FORALLfacets{+ if(facet->tricoplanar){+ allfacets[i_facet].family = facet->f.triowner->id;+ // if(!facet->degenerate){+ // if(i_facet == 392){+ // printf("area: %f", qh_facetarea(qh, facet));+ // }+ // allfacets[i_facet].simplex.center =+ // qh_facetcenter(qh, facet->vertices);+ // }else{+ // facetT *neighbor, **neighborp;+ // FOREACHneighbor_(facet){+ // if(facetOK_(neighbor,0) && neighbor->f.triowner->id == facet->f.triowner->id){+ // allfacets[i_facet].simplex.center =+ // qh_facetcenter(qh, neighbor->vertices);+ // break;+ // }+ // }+ // }+ }else{+ allfacets[i_facet].family = -1;+ }+ if(facet->degenerate){ // ?+ allfacets[i_facet].simplex.volume = 0;+ }else{+ allfacets[i_facet].simplex.volume = fmax(0, qh_facetarea(qh, facet));+ }+ if(allfacets[i_facet].simplex.volume > vthreshold){+ allfacets[i_facet].simplex.center = malloc(dim * sizeof(double));+ double* center = qh_facetcenter(qh, facet->vertices);+ for(unsigned i=0; i < dim; i++){+ allfacets[i_facet].simplex.center[i] = center[i];+ }+ }+ i_facet++;+ }+ }++ { /* facets ids, orientations, centers, sites ids, neighbors */+ facetT* facet;+ unsigned i_facet = 0; /* facet counter */+ FORALLfacets {+ allfacets[i_facet].id = facet->id;+ allfacets[i_facet].orientation = facet->toporient ? 1 : -1;+ /* center and circumradius */+ if(allfacets[i_facet].simplex.volume <= vthreshold){+ if(facet->tricoplanar){+ unsigned ok = 0;+ vertexT* apex = (vertexT*)facet->vertices->e[0].p;+ facetT *neighbor, **neighborp;+ FOREACHneighbor_(apex){+ if(facetOK_(neighbor,degenerate) &&+ allfacets[neighbor->id].family == allfacets[i_facet].family &&+ allfacets[neighbor->id].simplex.volume > vthreshold)+ {+ allfacets[i_facet].simplex.center =+ allfacets[neighbor->id].simplex.center;+ ok = 1;+ break;+ }+ }+ if(!ok){ /* should not happen */+ allfacets[i_facet].simplex.center = nanvector(dim);+ }+ }else{ /* should not happen */+ allfacets[i_facet].simplex.center = nanvector(dim);+ }+ }+// printf("center facet %u: %f %f %f\n", i_facet, allfacets[i_facet].simplex.center[0], allfacets[i_facet].simplex.center[1], allfacets[i_facet].simplex.center[2]);+ allfacets[i_facet].simplex.radius =+ sqrt(squaredDistance(((vertexT*)facet->vertices->e[0].p)->point,+ allfacets[i_facet].simplex.center, dim));+ // allfacets[i_facet].simplex.center =+ // facet->degenerate ? nanvector(dim)+ // : qh_facetcenter(qh, facet->vertices);+ // if(!facet->degenerate){+ // allfacets[i_facet].simplex.center = //facet->center;+ // qh_facetcenter(qh, facet->vertices);+ // // faire une première passe : calculer les centres des triowner+ // // pour ne pas les calculer pour les facets de la même famille+ // printf("center1: %f %f %f\n", facet->center[0], facet->center[1], facet->center[2]);+ // printf("center2: %f %f %f\n", allfacets[i_facet].simplex.center[0], allfacets[i_facet].simplex.center[1], allfacets[i_facet].simplex.center[2]);+ // pointT* point = ((vertexT*)facet->vertices->e[0].p)->point;+ // allfacets[i_facet].simplex.radius =+ // sqrt(squaredDistance(point, allfacets[i_facet].simplex.center,+ // dim));+ // }// }else{+ // // allfacets[i_facet].simplex.radius = NAN;+ // // }++ { /* vertices ids of the facet */+ allfacets[i_facet].simplex.sitesids =+ malloc((dim+1) * sizeof(unsigned));+ vertexT *vertex, **vertexp;+ unsigned i_vertex = 0;+ FOREACHvertex_(facet->vertices) {+ allfacets[i_facet].simplex.sitesids[i_vertex] =+ qh_pointid(qh, vertex->point);+ i_vertex++;+ }+ qsortu(allfacets[i_facet].simplex.sitesids, dim+1);+ }++ { /* neighbors facets of the facet */+ facetT *neighbor, **neighborp;+ unsigned flag[dim+1];+ allfacets[i_facet].nneighbors = 0;+ unsigned i_neighbor = 0;+ FOREACHneighbor_(facet) {+ if(flag[i_neighbor] = facetOK_(neighbor, degenerate)){+ allfacets[i_facet].nneighbors++;+ }+ i_neighbor++;+ }+ allfacets[i_facet].neighbors =+ malloc(allfacets[i_facet].nneighbors * sizeof(unsigned));+ unsigned countok = 0;+ i_neighbor = 0;+ FOREACHneighbor_(facet) {+ if(flag[i_neighbor]){+ allfacets[i_facet].neighbors[countok] = neighbor->id;+ countok++;+ }+ i_neighbor++;+ }+ }++ // /* facet family */+ // if(facet->tricoplanar){+ // allfacets[i_facet].family = facet->f.triowner->id;+ // }else{+ // allfacets[i_facet].family = -1;+ // }++ /**/+ i_facet++;+ }+ }++ // /* for degenerate facets, take the center of the owner */+ // if(degenerate){+ // facetT *facet;+ // unsigned i_facet = 0;+ // FORALLfacets{+ // if(facet->degenerate){+ // allfacets[i_facet].simplex.center =+ // allfacets[allfacets[i_facet].family].simplex.center;+ // pointT* point = ((vertexT*)facet->vertices->e[0].p)->point;+ // allfacets[i_facet].simplex.radius =+ // sqrt(squaredDistance(point, allfacets[i_facet].simplex.center,+ // dim));+ // }+ // i_facet++;+ // }+ // }++ /* neighbor facets and neighbor vertices per vertex */+ /* --- we will use the following combinations, also used later */+ /* --- combinations[m] contains all k between 0 and dim but m */+ unsigned combinations[dim+1][dim];+ for(unsigned m=0; m < dim+1; m++){+ unsigned kk=0;+ for(unsigned k=0; k < dim+1; k++){+ if(k != m){+ combinations[m][kk] = k;+ kk++;+ }+ }+ }+ /* --- initialize the sites */+ SiteT* allsites = malloc(n * sizeof(SiteT));+ /* --- array to flag neighbors - 0/1 if not neighbour/neighbour */+ unsigned** verticesFacetsNeighbours = malloc(n * sizeof(unsigned*));+ /* unsigned verticesFacetsNeighbours[n][nfacets] => stackoverflow */+ for(unsigned v=0; v < n; v++){+ allsites[v].id = v;+ allsites[v].nneighsites = 0;+ allsites[v].neighsites = malloc(0); /* will be filled by appending */+ allsites[v].nneighridges = 0;+ allsites[v].nneightiles = 0;+ verticesFacetsNeighbours[v] = uzeros(nfacets);+ }+ /* --- fill verticesFacetsNeighbours, derive number of neighbor facets */+ /* --- and derive neighbor sites */+ for(unsigned i_facet=0; i_facet < nfacets; i_facet++){+ for(unsigned j=0; j < dim+1; j++){+ unsigned vertexid = allfacets[i_facet].simplex.sitesids[j];+ if(verticesFacetsNeighbours[vertexid][i_facet] == 0){+ verticesFacetsNeighbours[vertexid][i_facet] = 1;+ allsites[vertexid].nneightiles++;+ }+ for(unsigned k=0; k < dim; k++){+ unsigned vertexid2 =+ allfacets[i_facet].simplex.sitesids[combinations[j][k]];+ unsigned pushed;+ appendu(vertexid2, &allsites[vertexid].neighsites,+ allsites[vertexid].nneighsites, &pushed);+ if(pushed){+ allsites[vertexid].nneighsites++;+ }+ }+ }+ }++ /************************************************************/+ /* second pass on facets: ridges and facet volumes */+ unsigned n_ridges_dup = nfacets * (dim+1); /* number of ridges with duplicates */+ SubTileT* allridges_dup = malloc(n_ridges_dup * sizeof(SubTileT));+ for(unsigned r=0; r < n_ridges_dup; r++){+ allridges_dup[r].simplex.sitesids = malloc(dim * sizeof(unsigned));+ allridges_dup[r].flag = 0;+ }+// qh_getarea(qh, qh->facet_list); /* make facets volumes, available in facet->f.area */+ unsigned n_ridges = 0; /* count distinct ridges */++ { /* loop on facets */+ facetT *facet;+ unsigned i_ridge_dup = 0; /* ridge counter */+ unsigned i_facet = 0; /* facet counter */+ FORALLfacets {++// allfacets[i_facet].simplex.volume = facet->f.area;+ allfacets[i_facet].nridges = dim+1;+ allfacets[i_facet].ridgesids = malloc((dim+1) * sizeof(unsigned));++ /* loop on the combinations - it increments i_ridge_dup */+ for(unsigned m=0; m < dim+1; m++){+ allridges_dup[i_ridge_dup].ridgeOf1 = facet->id;+ allridges_dup[i_ridge_dup].ridgeOf2 = -1; /* this means "nothing" */+ unsigned ids[dim];+ for(unsigned i=0; i < dim; i++){+ ids[i] = allfacets[i_facet].simplex.sitesids[combinations[m][i]];+ }+ unsigned done = 0; /* flag ridge is already done */+ for(unsigned r=0; r < i_ridge_dup; r++){+ if(allridges_dup[r].ridgeOf2 == (int) facet->id &&+ allridges_dup[r].flag==1)+ {+ unsigned ids2[dim];+ unsigned i;+ for(i=0; i < dim; i++){+ ids2[i] = allridges_dup[r].simplex.sitesids[i];+ if(ids2[i] != ids[i]){+ break;+ }+ }+ if(i == dim){+ allfacets[i_facet].ridgesids[m] = allridges_dup[r].id;+ done = 1;+ break;+ }+ }+ }+ if(done == 0){ /* => then do the ridge */+ allridges_dup[i_ridge_dup].flag = 1;+ allridges_dup[i_ridge_dup].id = n_ridges;+ allfacets[i_facet].ridgesids[m] = n_ridges;+ n_ridges++;+ for(unsigned i=0; i < dim; i++){+ allridges_dup[i_ridge_dup].simplex.sitesids[i] = ids[i];+ allsites[ids[i]].nneighridges++;+ }++ { /* loop on facet neighbors to find ridgeOf2 */+ facetT *neighbor, **neighborp;+ FOREACHneighbor_(facet){+ if(facetOK_(neighbor, degenerate)){+ unsigned fnid = neighbor->id;+ unsigned ok;+ for(unsigned mm=0; mm < dim+1; mm++){+ ok = 0;+ for(unsigned i=0; i < dim; i++){+ if(allfacets[fnid].simplex.sitesids[combinations[mm][i]]+ != ids[i])+ {+ break;+ }else{+ ok++;+ }+ }+ if(ok==dim){+ break;+ }+ }+ if(ok==dim){+ allridges_dup[i_ridge_dup].ridgeOf2 = (int) fnid;+ break;+ }+ }+ } /* end FOREACHneighbor_(facet) */+ }++ pointT* points[dim]; /* the points corresponding to the combination */+ for(unsigned i=0; i < dim; i++){+ points[i] = getpoint(sites, dim, ids[i]);+ }+ double normal[dim]; /* to store the ridge normal */+ if(dim == 2){+ double u1 = points[1][0] - points[0][0];+ double v1 = points[1][1] - points[0][1];+ allridges_dup[i_ridge_dup].simplex.volume =+ sqrt(square(u1)+square(v1));+ allridges_dup[i_ridge_dup].simplex.center =+ middle(points[0], points[1], dim);+ allridges_dup[i_ridge_dup].simplex.radius =+ sqrt(squaredDistance(allridges_dup[i_ridge_dup].simplex.center,+ points[0], dim));+ normal[0] = v1; normal[1] = -u1;+ }else{+ int parity=1;+ double squaredNorm = 0;+ for(unsigned i=0; i < dim; i++){+ double** rows = malloc((dim-1) * sizeof(double*));+ for(unsigned j=0; j < dim-1; j++){+ rows[j] = (double*) malloc((dim-1) * sizeof(double));+ for(unsigned k=0; k < dim-1; k++){+ unsigned kk = k<i ? k : k+1;+ rows[j][k] = points[j+1][kk] - points[0][kk];+ }+ }+ boolT nearzero;+ normal[i] = parity * qh_determinant(qh, rows, dim-1, &nearzero);+ squaredNorm += square(normal[i]);+ for(unsigned j=0; j < dim-1; j++){+ free(rows[j]);+ }+ free(rows);+ parity = -parity;+ }+ double surface = sqrt(squaredNorm);+ for(unsigned k=2; k < dim-1; k++){+ surface /= k;+ }+ allridges_dup[i_ridge_dup].simplex.volume = surface;+ }+ qh_normalize2(qh, normal, dim, 1, NULL, NULL);+ allridges_dup[i_ridge_dup].normal =+ malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ allridges_dup[i_ridge_dup].normal[i] = normal[i];+ }+ allridges_dup[i_ridge_dup].offset =+ - dotproduct(points[0], normal, dim);+ if(dim > 2){ /* ridge center is already done if dim 2 */+ // if(facet->degenerate){+ // allridges_dup[i_ridge_dup].simplex.center = nanvector(dim);+ // allridges_dup[i_ridge_dup].simplex.radius = NAN;+ // }else{+ allridges_dup[i_ridge_dup].simplex.center =+ malloc(dim * sizeof(double));+ double scal = 0;+ for(unsigned i=0; i < dim; i++){+ scal += (points[0][i]-allfacets[i_facet].simplex.center[i]) *+ normal[i];+ }+ for(unsigned i=0; i < dim; i++){+ allridges_dup[i_ridge_dup].simplex.center[i] =+ allfacets[i_facet].simplex.center[i] + scal*normal[i];+ }+ allridges_dup[i_ridge_dup].simplex.radius =+ sqrt(squaredDistance(+ allridges_dup[i_ridge_dup].simplex.center,+ points[0], dim));+// }+ }+ /* orient the normal (used for plotting unbounded Voronoi cells) */+ if(allridges_dup[i_ridge_dup].ridgeOf2 == -1)+ //&& (!facet->degenerate || dim==2))+ {+ pointT* otherpoint = /* the remaining vertex of the facet (the one not in the ridge) */+ qh->interior_point; // getpoint(sites, dim, allfacets[facet->id].simplex.sitesids[m]);+ double thepoint[dim]; /* the point center+normal */+ for(unsigned i=0; i < dim; i++){+ thepoint[i] = allridges_dup[i_ridge_dup].simplex.center[i] ++ allridges_dup[i_ridge_dup].normal[i];+ }+ /* we check that these two points are on the same side of the ridge */+ double h1 = dotproduct(otherpoint,+ allridges_dup[i_ridge_dup].normal, dim) ++ allridges_dup[i_ridge_dup].offset;+ double h2 = dotproduct(thepoint,+ allridges_dup[i_ridge_dup].normal, dim) ++ allridges_dup[i_ridge_dup].offset;+ // printf("deg: %u, h1: %f, h2: %f\n", facet->degenerate, h1, h2);+ // printf("offset: %f\n", allridges_dup[i_ridge_dup].offset);+ // printf("normal: %f %f %f\n", allridges_dup[i_ridge_dup].normal[0], allridges_dup[i_ridge_dup].normal[1], allridges_dup[i_ridge_dup].normal[2]);+ if(h1*h2 >= 0){+ for(unsigned i=0; i < dim; i++){+ allridges_dup[i_ridge_dup].normal[i] *= -1;+ }+ }+ }+ for(unsigned i=0; i < dim; i++){+ free(points[i]);+ }+ }+ i_ridge_dup++;+ } // end loop combinations (m)+ qsortu(allfacets[i_facet].ridgesids, dim+1);+ /**/+ i_facet++;+ } // end FORALLfacets+ }++ /* extract unique ridges */+ SubTileT* allridges = malloc(n_ridges * sizeof(SubTileT));+ unsigned inc_ridge = 0;+ for(unsigned l=0; l < n_ridges_dup; l++){+ if(allridges_dup[l].flag){+ allridges[inc_ridge] = allridges_dup[l];+ inc_ridge++;+ }+ }++ /* make neighbor ridges per vertex */+ unsigned* i_ridges_per_vertex = uzeros(n);+ for(unsigned v=0; v < n; v++){+ allsites[v].neighridgesids =+ malloc(allsites[v].nneighridges * sizeof(unsigned));+ }+ for(unsigned l=0; l < n_ridges_dup; l++){+ if(allridges_dup[l].flag){+ for(unsigned i=0; i < dim; i++){+ unsigned v = allridges_dup[l].simplex.sitesids[i];+ allsites[v].neighridgesids[i_ridges_per_vertex[v]] =+ allridges_dup[l].id;+ i_ridges_per_vertex[v]++;+ }+ }+ }++ /* order vertices neighbor sites and make neighbor tiles per vertex */+ for(unsigned v=0; v < n; v++){+ qsortu(allsites[v].neighsites, allsites[v].nneighsites);+ allsites[v].neightiles =+ malloc(allsites[v].nneightiles * sizeof(unsigned));+ unsigned inc_facet = 0; unsigned inc_vfn = 0;+ while(inc_vfn < allsites[v].nneightiles){+ if(verticesFacetsNeighbours[v][inc_facet] == 1){+ allsites[v].neightiles[inc_vfn] = inc_facet;+ inc_vfn++;+ }+ inc_facet++;+ }+ }++ /* make the output */+ out->sites = allsites;+ out->tiles = allfacets;+ out->ntiles = nfacets;+ out->subtiles = allridges;+ out->nsubtiles = n_ridges;++ free(allridges_dup);+ free(i_ridges_per_vertex);+ free(verticesFacetsNeighbours);++ }++ /* Do cleanup regardless of whether there is an error */+ int curlong, totlong;+ qh_freeqhull(qh, !qh_ALL); /* free long memory */+ qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */++ printf("RETURN\n");+ if(*exitcode){+ free(out);+ return 0;+ }else{+ return out;+ }++}+++void testdel2(){+ double sites[27] = {0,0,0, 0,0,1, 0,1,0, 0,1,1, 1,0,0, 1,0,1, 1,1,0, 1,1,1, 0.5,0.5,0.5};+ unsigned exitcode;+ unsigned dim = 3;+ TesselationT* x = tesselation(sites, dim, 9, 0, 0, 0, &exitcode);+ printf("TESTDEL2 - nfacets:%u\n", x->ntiles);+ for(unsigned f=0; f < x->ntiles; f++){+ printf("facet %u - sites:\n", f);+ for(unsigned i=0; i < dim+1; i++){+ printf("%u - ", x->tiles[f].simplex.sitesids[i]);+ }+ printf("\n");+ printf("facet %u - ridges:\n", f);+ for(unsigned i=0; i < dim+1; i++){+ printf("%u - ", x->tiles[f].ridgesids[i]);+ }+ printf("\n");+ printf("facet %u - neighbors:\n", f);+ for(unsigned i=0; i < x->tiles[f].nneighbors; i++){+ printf("%u - ", x->tiles[f].neighbors[i]);+ }+ printf("\n");+ }+ printf("nallridges:%u\n", x->nsubtiles);+ for(unsigned r=0; r < x->nsubtiles; r++){+ printf("ridge %u - id %u:\n", r, x->subtiles[r].id);+ for(unsigned i=0; i < dim; i++){+ printf("%u - ", x->subtiles[r].simplex.sitesids[i]);+ }+ printf("ridgeOf: %u %d", x->subtiles[r].ridgeOf1, x->subtiles[r].ridgeOf2);+ printf("\n");+ }+ free(x);+}
+ Cdir/geom2_r.c view
@@ -0,0 +1,2096 @@+/*<html><pre> -<a href="qh-geom_r.htm"+ >-------------------------------</a><a name="TOP">-</a>+++ geom2_r.c+ infrequently used geometric routines of qhull++ see qh-geom_r.htm and geom_r.h++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/geom2_r.c#6 $$Change: 2065 $+ $DateTime: 2016/01/18 13:51:04 $$Author: bbarber $++ frequently used code goes into geom_r.c+*/++#include "qhull_ra.h"++/*================== functions in alphabetic order ============*/++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="copypoints">-</a>++ qh_copypoints(qh, points, numpoints, dimension)+ return qh_malloc'd copy of points+ + notes:+ qh_free the returned points to avoid a memory leak+*/+coordT *qh_copypoints(qhT *qh, coordT *points, int numpoints, int dimension) {+ int size;+ coordT *newpoints;++ size= numpoints * dimension * (int)sizeof(coordT);+ if (!(newpoints= (coordT*)qh_malloc((size_t)size))) {+ qh_fprintf(qh, qh->ferr, 6004, "qhull error: insufficient memory to copy %d points\n",+ numpoints);+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ memcpy((char *)newpoints, (char *)points, (size_t)size); /* newpoints!=0 by QH6004 */+ return newpoints;+} /* copypoints */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="crossproduct">-</a>++ qh_crossproduct( dim, vecA, vecB, vecC )+ crossproduct of 2 dim vectors+ C= A x B++ notes:+ from Glasner, Graphics Gems I, p. 639+ only defined for dim==3+*/+void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){++ if (dim == 3) {+ vecC[0]= det2_(vecA[1], vecA[2],+ vecB[1], vecB[2]);+ vecC[1]= - det2_(vecA[0], vecA[2],+ vecB[0], vecB[2]);+ vecC[2]= det2_(vecA[0], vecA[1],+ vecB[0], vecB[1]);+ }+} /* vcross */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="determinant">-</a>++ qh_determinant(qh, rows, dim, nearzero )+ compute signed determinant of a square matrix+ uses qh.NEARzero to test for degenerate matrices++ returns:+ determinant+ overwrites rows and the matrix+ if dim == 2 or 3+ nearzero iff determinant < qh->NEARzero[dim-1]+ (!quite correct, not critical)+ if dim >= 4+ nearzero iff diagonal[k] < qh->NEARzero[k]+*/+realT qh_determinant(qhT *qh, realT **rows, int dim, boolT *nearzero) {+ realT det=0;+ int i;+ boolT sign= False;++ *nearzero= False;+ if (dim < 2) {+ qh_fprintf(qh, qh->ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }else if (dim == 2) {+ det= det2_(rows[0][0], rows[0][1],+ rows[1][0], rows[1][1]);+ if (fabs_(det) < 10*qh->NEARzero[1]) /* not really correct, what should this be? */+ *nearzero= True;+ }else if (dim == 3) {+ det= det3_(rows[0][0], rows[0][1], rows[0][2],+ rows[1][0], rows[1][1], rows[1][2],+ rows[2][0], rows[2][1], rows[2][2]);+ if (fabs_(det) < 10*qh->NEARzero[2]) /* what should this be? det 5.5e-12 was flat for qh_maxsimplex of qdelaunay 0,0 27,27 -36,36 -9,63 */+ *nearzero= True;+ }else {+ qh_gausselim(qh, rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/+ det= 1.0;+ for (i=dim; i--; )+ det *= (rows[i])[i];+ if (sign)+ det= -det;+ }+ return det;+} /* determinant */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="detjoggle">-</a>++ qh_detjoggle(qh, points, numpoints, dimension )+ determine default max joggle for point array+ as qh_distround * qh_JOGGLEdefault++ returns:+ initial value for JOGGLEmax from points and REALepsilon++ notes:+ computes DISTround since qh_maxmin not called yet+ if qh->SCALElast, last dimension will be scaled later to MAXwidth++ loop duplicated from qh_maxmin+*/+realT qh_detjoggle(qhT *qh, pointT *points, int numpoints, int dimension) {+ realT abscoord, distround, joggle, maxcoord, mincoord;+ pointT *point, *pointtemp;+ realT maxabs= -REALmax;+ realT sumabs= 0;+ realT maxwidth= 0;+ int k;++ for (k=0; k < dimension; k++) {+ if (qh->SCALElast && k == dimension-1)+ abscoord= maxwidth;+ else if (qh->DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */+ abscoord= 2 * maxabs * maxabs; /* may be low by qh->hull_dim/2 */+ else {+ maxcoord= -REALmax;+ mincoord= REALmax;+ FORALLpoint_(qh, points, numpoints) {+ maximize_(maxcoord, point[k]);+ minimize_(mincoord, point[k]);+ }+ maximize_(maxwidth, maxcoord-mincoord);+ abscoord= fmax_(maxcoord, -mincoord);+ }+ sumabs += abscoord;+ maximize_(maxabs, abscoord);+ } /* for k */+ distround= qh_distround(qh, qh->hull_dim, maxabs, sumabs);+ joggle= distround * qh_JOGGLEdefault;+ maximize_(joggle, REALepsilon * qh_JOGGLEdefault);+ trace2((qh, qh->ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));+ return joggle;+} /* detjoggle */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="detroundoff">-</a>++ qh_detroundoff(qh)+ determine maximum roundoff errors from+ REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord,+ qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1++ accounts for qh.SETroundoff, qh.RANDOMdist, qh->MERGEexact+ qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,+ qh.postmerge_centrum, qh.MINoutside,+ qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar++ returns:+ sets qh.DISTround, etc. (see below)+ appends precision constants to qh.qhull_options++ see:+ qh_maxmin() for qh.NEARzero++ design:+ determine qh.DISTround for distance computations+ determine minimum denominators for qh_divzero+ determine qh.ANGLEround for angle computations+ adjust qh.premerge_cos,... for roundoff error+ determine qh.ONEmerge for maximum error due to a single merge+ determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,+ qh.MINoutside, qh.WIDEfacet+ initialize qh.max_vertex and qh.minvertex+*/+void qh_detroundoff(qhT *qh) {++ qh_option(qh, "_max-width", NULL, &qh->MAXwidth);+ if (!qh->SETroundoff) {+ qh->DISTround= qh_distround(qh, qh->hull_dim, qh->MAXabs_coord, qh->MAXsumcoord);+ if (qh->RANDOMdist)+ qh->DISTround += qh->RANDOMfactor * qh->MAXabs_coord;+ qh_option(qh, "Error-roundoff", NULL, &qh->DISTround);+ }+ qh->MINdenom= qh->MINdenom_1 * qh->MAXabs_coord;+ qh->MINdenom_1_2= sqrt(qh->MINdenom_1 * qh->hull_dim) ; /* if will be normalized */+ qh->MINdenom_2= qh->MINdenom_1_2 * qh->MAXabs_coord;+ /* for inner product */+ qh->ANGLEround= 1.01 * qh->hull_dim * REALepsilon;+ if (qh->RANDOMdist)+ qh->ANGLEround += qh->RANDOMfactor;+ if (qh->premerge_cos < REALmax/2) {+ qh->premerge_cos -= qh->ANGLEround;+ if (qh->RANDOMdist)+ qh_option(qh, "Angle-premerge-with-random", NULL, &qh->premerge_cos);+ }+ if (qh->postmerge_cos < REALmax/2) {+ qh->postmerge_cos -= qh->ANGLEround;+ if (qh->RANDOMdist)+ qh_option(qh, "Angle-postmerge-with-random", NULL, &qh->postmerge_cos);+ }+ qh->premerge_centrum += 2 * qh->DISTround; /*2 for centrum and distplane()*/+ qh->postmerge_centrum += 2 * qh->DISTround;+ if (qh->RANDOMdist && (qh->MERGEexact || qh->PREmerge))+ qh_option(qh, "Centrum-premerge-with-random", NULL, &qh->premerge_centrum);+ if (qh->RANDOMdist && qh->POSTmerge)+ qh_option(qh, "Centrum-postmerge-with-random", NULL, &qh->postmerge_centrum);+ { /* compute ONEmerge, max vertex offset for merging simplicial facets */+ realT maxangle= 1.0, maxrho;++ minimize_(maxangle, qh->premerge_cos);+ minimize_(maxangle, qh->postmerge_cos);+ /* max diameter * sin theta + DISTround for vertex to its hyperplane */+ qh->ONEmerge= sqrt((realT)qh->hull_dim) * qh->MAXwidth *+ sqrt(1.0 - maxangle * maxangle) + qh->DISTround;+ maxrho= qh->hull_dim * qh->premerge_centrum + qh->DISTround;+ maximize_(qh->ONEmerge, maxrho);+ maxrho= qh->hull_dim * qh->postmerge_centrum + qh->DISTround;+ maximize_(qh->ONEmerge, maxrho);+ if (qh->MERGING)+ qh_option(qh, "_one-merge", NULL, &qh->ONEmerge);+ }+ qh->NEARinside= qh->ONEmerge * qh_RATIOnearinside; /* only used if qh->KEEPnearinside */+ if (qh->JOGGLEmax < REALmax/2 && (qh->KEEPcoplanar || qh->KEEPinside)) {+ realT maxdist; /* adjust qh.NEARinside for joggle */+ qh->KEEPnearinside= True;+ maxdist= sqrt((realT)qh->hull_dim) * qh->JOGGLEmax + qh->DISTround;+ maxdist= 2*maxdist; /* vertex and coplanar point can joggle in opposite directions */+ maximize_(qh->NEARinside, maxdist); /* must agree with qh_nearcoplanar() */+ }+ if (qh->KEEPnearinside)+ qh_option(qh, "_near-inside", NULL, &qh->NEARinside);+ if (qh->JOGGLEmax < qh->DISTround) {+ qh_fprintf(qh, qh->ferr, 6006, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",+ qh->JOGGLEmax, qh->DISTround);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->MINvisible > REALmax/2) {+ if (!qh->MERGING)+ qh->MINvisible= qh->DISTround;+ else if (qh->hull_dim <= 3)+ qh->MINvisible= qh->premerge_centrum;+ else+ qh->MINvisible= qh_COPLANARratio * qh->premerge_centrum;+ if (qh->APPROXhull && qh->MINvisible > qh->MINoutside)+ qh->MINvisible= qh->MINoutside;+ qh_option(qh, "Visible-distance", NULL, &qh->MINvisible);+ }+ if (qh->MAXcoplanar > REALmax/2) {+ qh->MAXcoplanar= qh->MINvisible;+ qh_option(qh, "U-coplanar-distance", NULL, &qh->MAXcoplanar);+ }+ if (!qh->APPROXhull) { /* user may specify qh->MINoutside */+ qh->MINoutside= 2 * qh->MINvisible;+ if (qh->premerge_cos < REALmax/2)+ maximize_(qh->MINoutside, (1- qh->premerge_cos) * qh->MAXabs_coord);+ qh_option(qh, "Width-outside", NULL, &qh->MINoutside);+ }+ qh->WIDEfacet= qh->MINoutside;+ maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MAXcoplanar);+ maximize_(qh->WIDEfacet, qh_WIDEcoplanar * qh->MINvisible);+ qh_option(qh, "_wide-facet", NULL, &qh->WIDEfacet);+ if (qh->MINvisible > qh->MINoutside + 3 * REALepsilon+ && !qh->BESToutside && !qh->FORCEoutput)+ qh_fprintf(qh, qh->ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n",+ qh->MINvisible, qh->MINoutside);+ qh->max_vertex= qh->DISTround;+ qh->min_vertex= -qh->DISTround;+ /* numeric constants reported in printsummary */+} /* detroundoff */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="detsimplex">-</a>++ qh_detsimplex(qh, apex, points, dim, nearzero )+ compute determinant of a simplex with point apex and base points++ returns:+ signed determinant and nearzero from qh_determinant++ notes:+ uses qh.gm_matrix/qh.gm_row (assumes they're big enough)++ design:+ construct qm_matrix by subtracting apex from points+ compute determinate+*/+realT qh_detsimplex(qhT *qh, pointT *apex, setT *points, int dim, boolT *nearzero) {+ pointT *coorda, *coordp, *gmcoord, *point, **pointp;+ coordT **rows;+ int k, i=0;+ realT det;++ zinc_(Zdetsimplex);+ gmcoord= qh->gm_matrix;+ rows= qh->gm_row;+ FOREACHpoint_(points) {+ if (i == dim)+ break;+ rows[i++]= gmcoord;+ coordp= point;+ coorda= apex;+ for (k=dim; k--; )+ *(gmcoord++)= *coordp++ - *coorda++;+ }+ if (i < dim) {+ qh_fprintf(qh, qh->ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n",+ i, dim);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ det= qh_determinant(qh, rows, dim, nearzero);+ trace2((qh, qh->ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",+ det, qh_pointid(qh, apex), dim, *nearzero));+ return det;+} /* detsimplex */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="distnorm">-</a>++ qh_distnorm( dim, point, normal, offset )+ return distance from point to hyperplane at normal/offset++ returns:+ dist++ notes:+ dist > 0 if point is outside of hyperplane++ see:+ qh_distplane in geom_r.c+*/+realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) {+ coordT *normalp= normal, *coordp= point;+ realT dist;+ int k;++ dist= *offsetp;+ for (k=dim; k--; )+ dist += *(coordp++) * *(normalp++);+ return dist;+} /* distnorm */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="distround">-</a>++ qh_distround(qh, dimension, maxabs, maxsumabs )+ compute maximum round-off error for a distance computation+ to a normalized hyperplane+ maxabs is the maximum absolute value of a coordinate+ maxsumabs is the maximum possible sum of absolute coordinate values++ returns:+ max dist round for REALepsilon++ notes:+ calculate roundoff error according to Golub & van Loan, 1983, Lemma 3.2-1, "Rounding Errors"+ use sqrt(dim) since one vector is normalized+ or use maxsumabs since one vector is < 1+*/+realT qh_distround(qhT *qh, int dimension, realT maxabs, realT maxsumabs) {+ realT maxdistsum, maxround;++ maxdistsum= sqrt((realT)dimension) * maxabs;+ minimize_( maxdistsum, maxsumabs);+ maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);+ /* adds maxabs for offset */+ trace4((qh, qh->ferr, 4008, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",+ maxround, maxabs, maxsumabs, maxdistsum));+ return maxround;+} /* distround */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="divzero">-</a>++ qh_divzero( numer, denom, mindenom1, zerodiv )+ divide by a number that's nearly zero+ mindenom1= minimum denominator for dividing into 1.0++ returns:+ quotient+ sets zerodiv and returns 0.0 if it would overflow++ design:+ if numer is nearly zero and abs(numer) < abs(denom)+ return numer/denom+ else if numer is nearly zero+ return 0 and zerodiv+ else if denom/numer non-zero+ return numer/denom+ else+ return 0 and zerodiv+*/+realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) {+ realT temp, numerx, denomx;+++ if (numer < mindenom1 && numer > -mindenom1) {+ numerx= fabs_(numer);+ denomx= fabs_(denom);+ if (numerx < denomx) {+ *zerodiv= False;+ return numer/denom;+ }else {+ *zerodiv= True;+ return 0.0;+ }+ }+ temp= denom/numer;+ if (temp > mindenom1 || temp < -mindenom1) {+ *zerodiv= False;+ return numer/denom;+ }else {+ *zerodiv= True;+ return 0.0;+ }+} /* divzero */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="facetarea">-</a>++ qh_facetarea(qh, facet )+ return area for a facet++ notes:+ if non-simplicial,+ uses centrum to triangulate facet and sums the projected areas.+ if (qh->DELAUNAY),+ computes projected area instead for last coordinate+ assumes facet->normal exists+ projecting tricoplanar facets to the hyperplane does not appear to make a difference++ design:+ if simplicial+ compute area+ else+ for each ridge+ compute area from centrum to ridge+ negate area if upper Delaunay facet+*/+realT qh_facetarea(qhT *qh, facetT *facet) {+ vertexT *apex;+ pointT *centrum;+ realT area= 0.0;+ ridgeT *ridge, **ridgep;++ if (facet->simplicial) {+ apex= SETfirstt_(facet->vertices, vertexT);+ area= qh_facetarea_simplex(qh, qh->hull_dim, apex->point, facet->vertices,+ apex, facet->toporient, facet->normal, &facet->offset);+ }else {+ if (qh->CENTERtype == qh_AScentrum)+ centrum= facet->center;+ else+ centrum= qh_getcentrum(qh, facet);+ FOREACHridge_(facet->ridges)+ area += qh_facetarea_simplex(qh, qh->hull_dim, centrum, ridge->vertices,+ NULL, (boolT)(ridge->top == facet), facet->normal, &facet->offset);+ if (qh->CENTERtype != qh_AScentrum)+ qh_memfree(qh, centrum, qh->normal_size);+ }+ if (facet->upperdelaunay && qh->DELAUNAY)+ area= -area; /* the normal should be [0,...,1] */+ trace4((qh, qh->ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area));+ return area;+} /* facetarea */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="facetarea_simplex">-</a>++ qh_facetarea_simplex(qh, dim, apex, vertices, notvertex, toporient, normal, offset )+ return area for a simplex defined by+ an apex, a base of vertices, an orientation, and a unit normal+ if simplicial or tricoplanar facet,+ notvertex is defined and it is skipped in vertices++ returns:+ computes area of simplex projected to plane [normal,offset]+ returns 0 if vertex too far below plane (qh->WIDEfacet)+ vertex can't be apex of tricoplanar facet++ notes:+ if (qh->DELAUNAY),+ computes projected area instead for last coordinate+ uses qh->gm_matrix/gm_row and qh->hull_dim+ helper function for qh_facetarea++ design:+ if Notvertex+ translate simplex to apex+ else+ project simplex to normal/offset+ translate simplex to apex+ if Delaunay+ set last row/column to 0 with -1 on diagonal+ else+ set last row to Normal+ compute determinate+ scale and flip sign for area+*/+realT qh_facetarea_simplex(qhT *qh, int dim, coordT *apex, setT *vertices,+ vertexT *notvertex, boolT toporient, coordT *normal, realT *offset) {+ pointT *coorda, *coordp, *gmcoord;+ coordT **rows, *normalp;+ int k, i=0;+ realT area, dist;+ vertexT *vertex, **vertexp;+ boolT nearzero;++ gmcoord= qh->gm_matrix;+ rows= qh->gm_row;+ FOREACHvertex_(vertices) {+ if (vertex == notvertex)+ continue;+ rows[i++]= gmcoord;+ coorda= apex;+ coordp= vertex->point;+ normalp= normal;+ if (notvertex) {+ for (k=dim; k--; )+ *(gmcoord++)= *coordp++ - *coorda++;+ }else {+ dist= *offset;+ for (k=dim; k--; )+ dist += *coordp++ * *normalp++;+ if (dist < -qh->WIDEfacet) {+ zinc_(Znoarea);+ return 0.0;+ }+ coordp= vertex->point;+ normalp= normal;+ for (k=dim; k--; )+ *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;+ }+ }+ if (i != dim-1) {+ qh_fprintf(qh, qh->ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n",+ i, dim);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ rows[i]= gmcoord;+ if (qh->DELAUNAY) {+ for (i=0; i < dim-1; i++)+ rows[i][dim-1]= 0.0;+ for (k=dim; k--; )+ *(gmcoord++)= 0.0;+ rows[dim-1][dim-1]= -1.0;+ }else {+ normalp= normal;+ for (k=dim; k--; )+ *(gmcoord++)= *normalp++;+ }+ zinc_(Zdetsimplex);+ area= qh_determinant(qh, rows, dim, &nearzero);+ if (toporient)+ area= -area;+ area *= qh->AREAfactor;+ trace4((qh, qh->ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",+ area, qh_pointid(qh, apex), toporient, nearzero));+ return area;+} /* facetarea_simplex */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="facetcenter">-</a>++ qh_facetcenter(qh, vertices )+ return Voronoi center (Voronoi vertex) for a facet's vertices++ returns:+ return temporary point equal to the center++ see:+ qh_voronoi_center()+*/+pointT *qh_facetcenter(qhT *qh, setT *vertices) {+ setT *points= qh_settemp(qh, qh_setsize(qh, vertices));+ vertexT *vertex, **vertexp;+ pointT *center;++ FOREACHvertex_(vertices)+ qh_setappend(qh, &points, vertex->point);+ center= qh_voronoi_center(qh, qh->hull_dim-1, points);+ qh_settempfree(qh, &points);+ return center;+} /* facetcenter */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="findgooddist">-</a>++ qh_findgooddist(qh, point, facetA, dist, facetlist )+ find best good facet visible for point from facetA+ assumes facetA is visible from point++ returns:+ best facet, i.e., good facet that is furthest from point+ distance to best facet+ NULL if none++ moves good, visible facets (and some other visible facets)+ to end of qh->facet_list++ notes:+ uses qh->visit_id++ design:+ initialize bestfacet if facetA is good+ move facetA to end of facetlist+ for each facet on facetlist+ for each unvisited neighbor of facet+ move visible neighbors to end of facetlist+ update best good neighbor+ if no good neighbors, update best facet+*/+facetT *qh_findgooddist(qhT *qh, pointT *point, facetT *facetA, realT *distp,+ facetT **facetlist) {+ realT bestdist= -REALmax, dist;+ facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;+ boolT goodseen= False;++ if (facetA->good) {+ zzinc_(Zcheckpart); /* calls from check_bestdist occur after print stats */+ qh_distplane(qh, point, facetA, &bestdist);+ bestfacet= facetA;+ goodseen= True;+ }+ qh_removefacet(qh, facetA);+ qh_appendfacet(qh, facetA);+ *facetlist= facetA;+ facetA->visitid= ++qh->visit_id;+ FORALLfacet_(*facetlist) {+ FOREACHneighbor_(facet) {+ if (neighbor->visitid == qh->visit_id)+ continue;+ neighbor->visitid= qh->visit_id;+ if (goodseen && !neighbor->good)+ continue;+ zzinc_(Zcheckpart);+ qh_distplane(qh, point, neighbor, &dist);+ if (dist > 0) {+ qh_removefacet(qh, neighbor);+ qh_appendfacet(qh, neighbor);+ if (neighbor->good) {+ goodseen= True;+ if (dist > bestdist) {+ bestdist= dist;+ bestfacet= neighbor;+ }+ }+ }+ }+ }+ if (bestfacet) {+ *distp= bestdist;+ trace2((qh, qh->ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",+ qh_pointid(qh, point), bestdist, bestfacet->id));+ return bestfacet;+ }+ trace4((qh, qh->ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n",+ qh_pointid(qh, point), facetA->id));+ return NULL;+} /* findgooddist */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="getarea">-</a>++ qh_getarea(qh, facetlist )+ set area of all facets in facetlist+ collect statistics+ nop if hasAreaVolume++ returns:+ sets qh->totarea/totvol to total area and volume of convex hull+ for Delaunay triangulation, computes projected area of the lower or upper hull+ ignores upper hull if qh->ATinfinity++ notes:+ could compute outer volume by expanding facet area by rays from interior+ the following attempt at perpendicular projection underestimated badly:+ qh.totoutvol += (-dist + facet->maxoutside + qh->DISTround)+ * area/ qh->hull_dim;+ design:+ for each facet on facetlist+ compute facet->area+ update qh.totarea and qh.totvol+*/+void qh_getarea(qhT *qh, facetT *facetlist) {+ realT area;+ realT dist;+ facetT *facet;++ if (qh->hasAreaVolume)+ return;+ if (qh->REPORTfreq)+ qh_fprintf(qh, qh->ferr, 8020, "computing area of each facet and volume of the convex hull\n");+ else+ trace1((qh, qh->ferr, 1001, "qh_getarea: computing volume and area for each facet\n"));+ qh->totarea= qh->totvol= 0.0;+ FORALLfacet_(facetlist) {+ if (!facet->normal)+ continue;+ if (facet->upperdelaunay && qh->ATinfinity)+ continue;+ if (!facet->isarea) {+ facet->f.area= qh_facetarea(qh, facet);+ facet->isarea= True;+ }+ area= facet->f.area;+ if (qh->DELAUNAY) {+ if (facet->upperdelaunay == qh->UPPERdelaunay)+ qh->totarea += area;+ }else {+ qh->totarea += area;+ qh_distplane(qh, qh->interior_point, facet, &dist);+ qh->totvol += -dist * area/ qh->hull_dim;+ }+ if (qh->PRINTstatistics) {+ wadd_(Wareatot, area);+ wmax_(Wareamax, area);+ wmin_(Wareamin, area);+ }+ }+ qh->hasAreaVolume= True;+} /* getarea */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="gram_schmidt">-</a>++ qh_gram_schmidt(qh, dim, row )+ implements Gram-Schmidt orthogonalization by rows++ returns:+ false if zero norm+ overwrites rows[dim][dim]++ notes:+ see Golub & van Loan, 1983, Algorithm 6.2-2, "Modified Gram-Schmidt"+ overflow due to small divisors not handled++ design:+ for each row+ compute norm for row+ if non-zero, normalize row+ for each remaining rowA+ compute inner product of row and rowA+ reduce rowA by row * inner product+*/+boolT qh_gram_schmidt(qhT *qh, int dim, realT **row) {+ realT *rowi, *rowj, norm;+ int i, j, k;++ for (i=0; i < dim; i++) {+ rowi= row[i];+ for (norm= 0.0, k= dim; k--; rowi++)+ norm += *rowi * *rowi;+ norm= sqrt(norm);+ wmin_(Wmindenom, norm);+ if (norm == 0.0) /* either 0 or overflow due to sqrt */+ return False;+ for (k=dim; k--; )+ *(--rowi) /= norm;+ for (j=i+1; j < dim; j++) {+ rowj= row[j];+ for (norm= 0.0, k=dim; k--; )+ norm += *rowi++ * *rowj++;+ for (k=dim; k--; )+ *(--rowj) -= *(--rowi) * norm;+ }+ }+ return True;+} /* gram_schmidt */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="inthresholds">-</a>++ qh_inthresholds(qh, normal, angle )+ return True if normal within qh.lower_/upper_threshold++ returns:+ estimate of angle by summing of threshold diffs+ angle may be NULL+ smaller "angle" is better++ notes:+ invalid if qh.SPLITthresholds++ see:+ qh.lower_threshold in qh_initbuild()+ qh_initthresholds()++ design:+ for each dimension+ test threshold+*/+boolT qh_inthresholds(qhT *qh, coordT *normal, realT *angle) {+ boolT within= True;+ int k;+ realT threshold;++ if (angle)+ *angle= 0.0;+ for (k=0; k < qh->hull_dim; k++) {+ threshold= qh->lower_threshold[k];+ if (threshold > -REALmax/2) {+ if (normal[k] < threshold)+ within= False;+ if (angle) {+ threshold -= normal[k];+ *angle += fabs_(threshold);+ }+ }+ if (qh->upper_threshold[k] < REALmax/2) {+ threshold= qh->upper_threshold[k];+ if (normal[k] > threshold)+ within= False;+ if (angle) {+ threshold -= normal[k];+ *angle += fabs_(threshold);+ }+ }+ }+ return within;+} /* inthresholds */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="joggleinput">-</a>++ qh_joggleinput(qh)+ randomly joggle input to Qhull by qh.JOGGLEmax+ initial input is qh.first_point/qh.num_points of qh.hull_dim+ repeated calls use qh.input_points/qh.num_points++ returns:+ joggles points at qh.first_point/qh.num_points+ copies data to qh.input_points/qh.input_malloc if first time+ determines qh.JOGGLEmax if it was zero+ if qh.DELAUNAY+ computes the Delaunay projection of the joggled points++ notes:+ if qh.DELAUNAY, unnecessarily joggles the last coordinate+ the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease++ design:+ if qh.DELAUNAY+ set qh.SCALElast for reduced precision errors+ if first call+ initialize qh.input_points to the original input points+ if qh.JOGGLEmax == 0+ determine default qh.JOGGLEmax+ else+ increase qh.JOGGLEmax according to qh.build_cnt+ joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]+ if qh.DELAUNAY+ sets the Delaunay projection+*/+void qh_joggleinput(qhT *qh) {+ int i, seed, size;+ coordT *coordp, *inputp;+ realT randr, randa, randb;++ if (!qh->input_points) { /* first call */+ qh->input_points= qh->first_point;+ qh->input_malloc= qh->POINTSmalloc;+ size= qh->num_points * qh->hull_dim * sizeof(coordT);+ if (!(qh->first_point=(coordT*)qh_malloc((size_t)size))) {+ qh_fprintf(qh, qh->ferr, 6009, "qhull error: insufficient memory to joggle %d points\n",+ qh->num_points);+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ qh->POINTSmalloc= True;+ if (qh->JOGGLEmax == 0.0) {+ qh->JOGGLEmax= qh_detjoggle(qh, qh->input_points, qh->num_points, qh->hull_dim);+ qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);+ }+ }else { /* repeated call */+ if (!qh->RERUN && qh->build_cnt > qh_JOGGLEretry) {+ if (((qh->build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {+ realT maxjoggle= qh->MAXwidth * qh_JOGGLEmaxincrease;+ if (qh->JOGGLEmax < maxjoggle) {+ qh->JOGGLEmax *= qh_JOGGLEincrease;+ minimize_(qh->JOGGLEmax, maxjoggle);+ }+ }+ }+ qh_option(qh, "QJoggle", NULL, &qh->JOGGLEmax);+ }+ if (qh->build_cnt > 1 && qh->JOGGLEmax > fmax_(qh->MAXwidth/4, 0.1)) {+ qh_fprintf(qh, qh->ferr, 6010, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input. If possible, recompile Qhull with higher-precision reals.\n",+ qh->JOGGLEmax);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ /* for some reason, using qh->ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */+ seed= qh_RANDOMint;+ qh_option(qh, "_joggle-seed", &seed, NULL);+ trace0((qh, qh->ferr, 6, "qh_joggleinput: joggle input by %2.2g with seed %d\n",+ qh->JOGGLEmax, seed));+ inputp= qh->input_points;+ coordp= qh->first_point;+ randa= 2.0 * qh->JOGGLEmax/qh_RANDOMmax;+ randb= -qh->JOGGLEmax;+ size= qh->num_points * qh->hull_dim;+ for (i=size; i--; ) {+ randr= qh_RANDOMint;+ *(coordp++)= *(inputp++) + (randr * randa + randb);+ }+ if (qh->DELAUNAY) {+ qh->last_low= qh->last_high= qh->last_newhigh= REALmax;+ qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);+ }+} /* joggleinput */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="maxabsval">-</a>++ qh_maxabsval( normal, dim )+ return pointer to maximum absolute value of a dim vector+ returns NULL if dim=0+*/+realT *qh_maxabsval(realT *normal, int dim) {+ realT maxval= -REALmax;+ realT *maxp= NULL, *colp, absval;+ int k;++ for (k=dim, colp= normal; k--; colp++) {+ absval= fabs_(*colp);+ if (absval > maxval) {+ maxval= absval;+ maxp= colp;+ }+ }+ return maxp;+} /* maxabsval */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="maxmin">-</a>++ qh_maxmin(qh, points, numpoints, dimension )+ return max/min points for each dimension+ determine max and min coordinates++ returns:+ returns a temporary set of max and min points+ may include duplicate points. Does not include qh.GOODpoint+ sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth+ qh.MAXlastcoord, qh.MINlastcoord+ initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok++ notes:+ loop duplicated in qh_detjoggle()++ design:+ initialize global precision variables+ checks definition of REAL...+ for each dimension+ for each point+ collect maximum and minimum point+ collect maximum of maximums and minimum of minimums+ determine qh.NEARzero for Gaussian Elimination+*/+setT *qh_maxmin(qhT *qh, pointT *points, int numpoints, int dimension) {+ int k;+ realT maxcoord, temp;+ pointT *minimum, *maximum, *point, *pointtemp;+ setT *set;++ qh->max_outside= 0.0;+ qh->MAXabs_coord= 0.0;+ qh->MAXwidth= -REALmax;+ qh->MAXsumcoord= 0.0;+ qh->min_vertex= 0.0;+ qh->WAScoplanar= False;+ if (qh->ZEROcentrum)+ qh->ZEROall_ok= True;+ if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax+ && REALmax > 0.0 && -REALmax < 0.0)+ ; /* all ok */+ else {+ qh_fprintf(qh, qh->ferr, 6011, "qhull error: floating point constants in user.h are wrong\n\+REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",+ REALepsilon, REALmin, REALmax, -REALmax);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ set= qh_settemp(qh, 2*dimension);+ for (k=0; k < dimension; k++) {+ if (points == qh->GOODpointp)+ minimum= maximum= points + dimension;+ else+ minimum= maximum= points;+ FORALLpoint_(qh, points, numpoints) {+ if (point == qh->GOODpointp)+ continue;+ if (maximum[k] < point[k])+ maximum= point;+ else if (minimum[k] > point[k])+ minimum= point;+ }+ if (k == dimension-1) {+ qh->MINlastcoord= minimum[k];+ qh->MAXlastcoord= maximum[k];+ }+ if (qh->SCALElast && k == dimension-1)+ maxcoord= qh->MAXwidth;+ else {+ maxcoord= fmax_(maximum[k], -minimum[k]);+ if (qh->GOODpointp) {+ temp= fmax_(qh->GOODpointp[k], -qh->GOODpointp[k]);+ maximize_(maxcoord, temp);+ }+ temp= maximum[k] - minimum[k];+ maximize_(qh->MAXwidth, temp);+ }+ maximize_(qh->MAXabs_coord, maxcoord);+ qh->MAXsumcoord += maxcoord;+ qh_setappend(qh, &set, maximum);+ qh_setappend(qh, &set, minimum);+ /* calculation of qh NEARzero is based on Golub & van Loan, 1983,+ Eq. 4.4-13 for "Gaussian elimination with complete pivoting".+ Golub & van Loan say that n^3 can be ignored and 10 be used in+ place of rho */+ qh->NEARzero[k]= 80 * qh->MAXsumcoord * REALepsilon;+ }+ if (qh->IStracing >=1)+ qh_printpoints(qh, qh->ferr, "qh_maxmin: found the max and min points(by dim):", set);+ return(set);+} /* maxmin */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="maxouter">-</a>++ qh_maxouter(qh)+ return maximum distance from facet to outer plane+ normally this is qh.max_outside+qh.DISTround+ does not include qh.JOGGLEmax++ see:+ qh_outerinner()++ notes:+ need to add another qh.DISTround if testing actual point with computation++ for joggle:+ qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)+ need to use Wnewvertexmax since could have a coplanar point for a high+ facet that is replaced by a low facet+ need to add qh.JOGGLEmax if testing input points+*/+realT qh_maxouter(qhT *qh) {+ realT dist;++ dist= fmax_(qh->max_outside, qh->DISTround);+ dist += qh->DISTround;+ trace4((qh, qh->ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh->max_outside));+ return dist;+} /* maxouter */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="maxsimplex">-</a>++ qh_maxsimplex(qh, dim, maxpoints, points, numpoints, simplex )+ determines maximum simplex for a set of points+ starts from points already in simplex+ skips qh.GOODpointp (assumes that it isn't in maxpoints)++ returns:+ simplex with dim+1 points++ notes:+ assumes at least pointsneeded points in points+ maximizes determinate for x,y,z,w, etc.+ uses maxpoints as long as determinate is clearly non-zero++ design:+ initialize simplex with at least two points+ (find points with max or min x coordinate)+ for each remaining dimension+ add point that maximizes the determinate+ (use points from maxpoints first)+*/+void qh_maxsimplex(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {+ pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;+ boolT nearzero, maxnearzero= False;+ int k, sizinit;+ realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;++ sizinit= qh_setsize(qh, *simplex);+ if (sizinit < 2) {+ if (qh_setsize(qh, maxpoints) >= 2) {+ FOREACHpoint_(maxpoints) {+ if (maxcoord < point[0]) {+ maxcoord= point[0];+ maxx= point;+ }+ if (mincoord > point[0]) {+ mincoord= point[0];+ minx= point;+ }+ }+ }else {+ FORALLpoint_(qh, points, numpoints) {+ if (point == qh->GOODpointp)+ continue;+ if (maxcoord < point[0]) {+ maxcoord= point[0];+ maxx= point;+ }+ if (mincoord > point[0]) {+ mincoord= point[0];+ minx= point;+ }+ }+ }+ qh_setunique(qh, simplex, minx);+ if (qh_setsize(qh, *simplex) < 2)+ qh_setunique(qh, simplex, maxx);+ sizinit= qh_setsize(qh, *simplex);+ if (sizinit < 2) {+ qh_precision(qh, "input has same x coordinate");+ if (zzval_(Zsetplane) > qh->hull_dim+1) {+ qh_fprintf(qh, qh->ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",+ qh_setsize(qh, maxpoints)+numpoints);+ qh_errexit(qh, qh_ERRprec, NULL, NULL);+ }else {+ qh_fprintf(qh, qh->ferr, 6013, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh->hull_dim);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ }+ }+ for (k=sizinit; k < dim+1; k++) {+ maxpoint= NULL;+ maxdet= -REALmax;+ FOREACHpoint_(maxpoints) {+ if (!qh_setin(*simplex, point)) {+ det= qh_detsimplex(qh, point, *simplex, k, &nearzero);+ if ((det= fabs_(det)) > maxdet) {+ maxdet= det;+ maxpoint= point;+ maxnearzero= nearzero;+ }+ }+ }+ if (!maxpoint || maxnearzero) {+ zinc_(Zsearchpoints);+ if (!maxpoint) {+ trace0((qh, qh->ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));+ }else {+ trace0((qh, qh->ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",+ k+1, qh_pointid(qh, maxpoint), maxdet));+ }+ FORALLpoint_(qh, points, numpoints) {+ if (point == qh->GOODpointp)+ continue;+ if (!qh_setin(*simplex, point)) {+ det= qh_detsimplex(qh, point, *simplex, k, &nearzero);+ if ((det= fabs_(det)) > maxdet) {+ maxdet= det;+ maxpoint= point;+ maxnearzero= nearzero;+ }+ }+ }+ } /* !maxpoint */+ if (!maxpoint) {+ qh_fprintf(qh, qh->ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ qh_setappend(qh, simplex, maxpoint);+ trace1((qh, qh->ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",+ qh_pointid(qh, maxpoint), k+1, maxdet));+ } /* k */+} /* maxsimplex */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="minabsval">-</a>++ qh_minabsval( normal, dim )+ return minimum absolute value of a dim vector+*/+realT qh_minabsval(realT *normal, int dim) {+ realT minval= 0;+ realT maxval= 0;+ realT *colp;+ int k;++ for (k=dim, colp=normal; k--; colp++) {+ maximize_(maxval, *colp);+ minimize_(minval, *colp);+ }+ return fmax_(maxval, -minval);+} /* minabsval */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="mindiff">-</a>++ qh_mindif(qh, vecA, vecB, dim )+ return index of min abs. difference of two vectors+*/+int qh_mindiff(realT *vecA, realT *vecB, int dim) {+ realT mindiff= REALmax, diff;+ realT *vecAp= vecA, *vecBp= vecB;+ int k, mink= 0;++ for (k=0; k < dim; k++) {+ diff= *vecAp++ - *vecBp++;+ diff= fabs_(diff);+ if (diff < mindiff) {+ mindiff= diff;+ mink= k;+ }+ }+ return mink;+} /* mindiff */++++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="orientoutside">-</a>++ qh_orientoutside(qh, facet )+ make facet outside oriented via qh.interior_point++ returns:+ True if facet reversed orientation.+*/+boolT qh_orientoutside(qhT *qh, facetT *facet) {+ int k;+ realT dist;++ qh_distplane(qh, qh->interior_point, facet, &dist);+ if (dist > 0) {+ for (k=qh->hull_dim; k--; )+ facet->normal[k]= -facet->normal[k];+ facet->offset= -facet->offset;+ return True;+ }+ return False;+} /* orientoutside */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="outerinner">-</a>++ qh_outerinner(qh, facet, outerplane, innerplane )+ if facet and qh.maxoutdone (i.e., qh_check_maxout)+ returns outer and inner plane for facet+ else+ returns maximum outer and inner plane+ accounts for qh.JOGGLEmax++ see:+ qh_maxouter(qh), qh_check_bestdist(), qh_check_points()++ notes:+ outerplaner or innerplane may be NULL+ facet is const+ Does not error (QhullFacet)++ includes qh.DISTround for actual points+ adds another qh.DISTround if testing with floating point arithmetic+*/+void qh_outerinner(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {+ realT dist, mindist;+ vertexT *vertex, **vertexp;++ if (outerplane) {+ if (!qh_MAXoutside || !facet || !qh->maxoutdone) {+ *outerplane= qh_maxouter(qh); /* includes qh.DISTround */+ }else { /* qh_MAXoutside ... */+#if qh_MAXoutside+ *outerplane= facet->maxoutside + qh->DISTround;+#endif++ }+ if (qh->JOGGLEmax < REALmax/2)+ *outerplane += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);+ }+ if (innerplane) {+ if (facet) {+ mindist= REALmax;+ FOREACHvertex_(facet->vertices) {+ zinc_(Zdistio);+ qh_distplane(qh, vertex->point, facet, &dist);+ minimize_(mindist, dist);+ }+ *innerplane= mindist - qh->DISTround;+ }else+ *innerplane= qh->min_vertex - qh->DISTround;+ if (qh->JOGGLEmax < REALmax/2)+ *innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);+ }+} /* outerinner */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="pointdist">-</a>++ qh_pointdist( point1, point2, dim )+ return distance between two points++ notes:+ returns distance squared if 'dim' is negative+*/+coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {+ coordT dist, diff;+ int k;++ dist= 0.0;+ for (k= (dim > 0 ? dim : -dim); k--; ) {+ diff= *point1++ - *point2++;+ dist += diff * diff;+ }+ if (dim > 0)+ return(sqrt(dist));+ return dist;+} /* pointdist */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="printmatrix">-</a>++ qh_printmatrix(qh, fp, string, rows, numrow, numcol )+ print matrix to fp given by row vectors+ print string as header+ qh may be NULL if fp is defined++ notes:+ print a vector by qh_printmatrix(qh, fp, "", &vect, 1, len)+*/+void qh_printmatrix(qhT *qh, FILE *fp, const char *string, realT **rows, int numrow, int numcol) {+ realT *rowp;+ realT r; /*bug fix*/+ int i,k;++ qh_fprintf(qh, fp, 9001, "%s\n", string);+ for (i=0; i < numrow; i++) {+ rowp= rows[i];+ for (k=0; k < numcol; k++) {+ r= *rowp++;+ qh_fprintf(qh, fp, 9002, "%6.3g ", r);+ }+ qh_fprintf(qh, fp, 9003, "\n");+ }+} /* printmatrix */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="printpoints">-</a>++ qh_printpoints(qh, fp, string, points )+ print pointids to fp for a set of points+ if string, prints string and 'p' point ids+*/+void qh_printpoints(qhT *qh, FILE *fp, const char *string, setT *points) {+ pointT *point, **pointp;++ if (string) {+ qh_fprintf(qh, fp, 9004, "%s", string);+ FOREACHpoint_(points)+ qh_fprintf(qh, fp, 9005, " p%d", qh_pointid(qh, point));+ qh_fprintf(qh, fp, 9006, "\n");+ }else {+ FOREACHpoint_(points)+ qh_fprintf(qh, fp, 9007, " %d", qh_pointid(qh, point));+ qh_fprintf(qh, fp, 9008, "\n");+ }+} /* printpoints */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="projectinput">-</a>++ qh_projectinput(qh)+ project input points using qh.lower_bound/upper_bound and qh->DELAUNAY+ if qh.lower_bound[k]=qh.upper_bound[k]= 0,+ removes dimension k+ if halfspace intersection+ removes dimension k from qh.feasible_point+ input points in qh->first_point, num_points, input_dim++ returns:+ new point array in qh->first_point of qh->hull_dim coordinates+ sets qh->POINTSmalloc+ if qh->DELAUNAY+ projects points to paraboloid+ lowbound/highbound is also projected+ if qh->ATinfinity+ adds point "at-infinity"+ if qh->POINTSmalloc+ frees old point array++ notes:+ checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY+++ design:+ sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)+ determines newdim and newnum for qh->hull_dim and qh->num_points+ projects points to newpoints+ projects qh.lower_bound to itself+ projects qh.upper_bound to itself+ if qh->DELAUNAY+ if qh->ATINFINITY+ projects points to paraboloid+ computes "infinity" point as vertex average and 10% above all points+ else+ uses qh_setdelaunay to project points to paraboloid+*/+void qh_projectinput(qhT *qh) {+ int k,i;+ int newdim= qh->input_dim, newnum= qh->num_points;+ signed char *project;+ int projectsize= (qh->input_dim+1)*sizeof(*project);+ pointT *newpoints, *coord, *infinity;+ realT paraboloid, maxboloid= 0;++ project= (signed char*)qh_memalloc(qh, projectsize);+ memset((char*)project, 0, (size_t)projectsize);+ for (k=0; k < qh->input_dim; k++) { /* skip Delaunay bound */+ if (qh->lower_bound[k] == 0 && qh->upper_bound[k] == 0) {+ project[k]= -1;+ newdim--;+ }+ }+ if (qh->DELAUNAY) {+ project[k]= 1;+ newdim++;+ if (qh->ATinfinity)+ newnum++;+ }+ if (newdim != qh->hull_dim) {+ qh_memfree(qh, project, projectsize);+ qh_fprintf(qh, qh->ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh->hull_dim);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ if (!(newpoints= qh->temp_malloc= (coordT*)qh_malloc(newnum*newdim*sizeof(coordT)))){+ qh_memfree(qh, project, projectsize);+ qh_fprintf(qh, qh->ferr, 6016, "qhull error: insufficient memory to project %d points\n",+ qh->num_points);+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ /* qh_projectpoints throws error if mismatched dimensions */+ qh_projectpoints(qh, project, qh->input_dim+1, qh->first_point,+ qh->num_points, qh->input_dim, newpoints, newdim);+ trace1((qh, qh->ferr, 1003, "qh_projectinput: updating lower and upper_bound\n"));+ qh_projectpoints(qh, project, qh->input_dim+1, qh->lower_bound,+ 1, qh->input_dim+1, qh->lower_bound, newdim+1);+ qh_projectpoints(qh, project, qh->input_dim+1, qh->upper_bound,+ 1, qh->input_dim+1, qh->upper_bound, newdim+1);+ if (qh->HALFspace) {+ if (!qh->feasible_point) {+ qh_memfree(qh, project, projectsize);+ qh_fprintf(qh, qh->ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ qh_projectpoints(qh, project, qh->input_dim, qh->feasible_point,+ 1, qh->input_dim, qh->feasible_point, newdim);+ }+ qh_memfree(qh, project, projectsize);+ if (qh->POINTSmalloc)+ qh_free(qh->first_point);+ qh->first_point= newpoints;+ qh->POINTSmalloc= True;+ qh->temp_malloc= NULL;+ if (qh->DELAUNAY && qh->ATinfinity) {+ coord= qh->first_point;+ infinity= qh->first_point + qh->hull_dim * qh->num_points;+ for (k=qh->hull_dim-1; k--; )+ infinity[k]= 0.0;+ for (i=qh->num_points; i--; ) {+ paraboloid= 0.0;+ for (k=0; k < qh->hull_dim-1; k++) {+ paraboloid += *coord * *coord;+ infinity[k] += *coord;+ coord++;+ }+ *(coord++)= paraboloid;+ maximize_(maxboloid, paraboloid);+ }+ /* coord == infinity */+ for (k=qh->hull_dim-1; k--; )+ *(coord++) /= qh->num_points;+ *(coord++)= maxboloid * 1.1;+ qh->num_points++;+ trace0((qh, qh->ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n"));+ }else if (qh->DELAUNAY) /* !qh->ATinfinity */+ qh_setdelaunay(qh, qh->hull_dim, qh->num_points, qh->first_point);+} /* projectinput */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="projectpoints">-</a>++ qh_projectpoints(qh, project, n, points, numpoints, dim, newpoints, newdim )+ project points/numpoints/dim to newpoints/newdim+ if project[k] == -1+ delete dimension k+ if project[k] == 1+ add dimension k by duplicating previous column+ n is size of project++ notes:+ newpoints may be points if only adding dimension at end++ design:+ check that 'project' and 'newdim' agree+ for each dimension+ if project == -1+ skip dimension+ else+ determine start of column in newpoints+ determine start of column in points+ if project == +1, duplicate previous column+ copy dimension (column) from points to newpoints+*/+void qh_projectpoints(qhT *qh, signed char *project, int n, realT *points,+ int numpoints, int dim, realT *newpoints, int newdim) {+ int testdim= dim, oldk=0, newk=0, i,j=0,k;+ realT *newp, *oldp;++ for (k=0; k < n; k++)+ testdim += project[k];+ if (testdim != newdim) {+ qh_fprintf(qh, qh->ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",+ newdim, testdim);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ for (j=0; j<n; j++) {+ if (project[j] == -1)+ oldk++;+ else {+ newp= newpoints+newk++;+ if (project[j] == +1) {+ if (oldk >= dim)+ continue;+ oldp= points+oldk;+ }else+ oldp= points+oldk++;+ for (i=numpoints; i--; ) {+ *newp= *oldp;+ newp += newdim;+ oldp += dim;+ }+ }+ if (oldk >= dim)+ break;+ }+ trace1((qh, qh->ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n",+ numpoints, dim, newdim));+} /* projectpoints */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="rotateinput">-</a>++ qh_rotateinput(qh, rows )+ rotate input using row matrix+ input points given by qh->first_point, num_points, hull_dim+ assumes rows[dim] is a scratch buffer+ if qh->POINTSmalloc, overwrites input points, else mallocs a new array++ returns:+ rotated input+ sets qh->POINTSmalloc++ design:+ see qh_rotatepoints+*/+void qh_rotateinput(qhT *qh, realT **rows) {++ if (!qh->POINTSmalloc) {+ qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);+ qh->POINTSmalloc= True;+ }+ qh_rotatepoints(qh, qh->first_point, qh->num_points, qh->hull_dim, rows);+} /* rotateinput */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="rotatepoints">-</a>++ qh_rotatepoints(qh, points, numpoints, dim, row )+ rotate numpoints points by a d-dim row matrix+ assumes rows[dim] is a scratch buffer++ returns:+ rotated points in place++ design:+ for each point+ for each coordinate+ use row[dim] to compute partial inner product+ for each coordinate+ rotate by partial inner product+*/+void qh_rotatepoints(qhT *qh, realT *points, int numpoints, int dim, realT **row) {+ realT *point, *rowi, *coord= NULL, sum, *newval;+ int i,j,k;++ if (qh->IStracing >= 1)+ qh_printmatrix(qh, qh->ferr, "qh_rotatepoints: rotate points by", row, dim, dim);+ for (point= points, j= numpoints; j--; point += dim) {+ newval= row[dim];+ for (i=0; i < dim; i++) {+ rowi= row[i];+ coord= point;+ for (sum= 0.0, k= dim; k--; )+ sum += *rowi++ * *coord++;+ *(newval++)= sum;+ }+ for (k=dim; k--; )+ *(--coord)= *(--newval);+ }+} /* rotatepoints */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="scaleinput">-</a>++ qh_scaleinput(qh)+ scale input points using qh->low_bound/high_bound+ input points given by qh->first_point, num_points, hull_dim+ if qh->POINTSmalloc, overwrites input points, else mallocs a new array++ returns:+ scales coordinates of points to low_bound[k], high_bound[k]+ sets qh->POINTSmalloc++ design:+ see qh_scalepoints+*/+void qh_scaleinput(qhT *qh) {++ if (!qh->POINTSmalloc) {+ qh->first_point= qh_copypoints(qh, qh->first_point, qh->num_points, qh->hull_dim);+ qh->POINTSmalloc= True;+ }+ qh_scalepoints(qh, qh->first_point, qh->num_points, qh->hull_dim,+ qh->lower_bound, qh->upper_bound);+} /* scaleinput */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="scalelast">-</a>++ qh_scalelast(qh, points, numpoints, dim, low, high, newhigh )+ scale last coordinate to [0,m] for Delaunay triangulations+ input points given by points, numpoints, dim++ returns:+ changes scale of last coordinate from [low, high] to [0, newhigh]+ overwrites last coordinate of each point+ saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()++ notes:+ when called by qh_setdelaunay, low/high may not match actual data++ design:+ compute scale and shift factors+ apply to last coordinate of each point+*/+void qh_scalelast(qhT *qh, coordT *points, int numpoints, int dim, coordT low,+ coordT high, coordT newhigh) {+ realT scale, shift;+ coordT *coord;+ int i;+ boolT nearzero= False;++ trace4((qh, qh->ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",+ low, high, newhigh));+ qh->last_low= low;+ qh->last_high= high;+ qh->last_newhigh= newhigh;+ scale= qh_divzero(newhigh, high - low,+ qh->MINdenom_1, &nearzero);+ if (nearzero) {+ if (qh->DELAUNAY)+ qh_fprintf(qh, qh->ferr, 6019, "qhull input error: can not scale last coordinate. Input is cocircular\n or cospherical. Use option 'Qz' to add a point at infinity.\n");+ else+ qh_fprintf(qh, qh->ferr, 6020, "qhull input error: can not scale last coordinate. New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",+ newhigh, low, high, high-low);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ shift= - low * newhigh / (high-low);+ coord= points + dim - 1;+ for (i=numpoints; i--; coord += dim)+ *coord= *coord * scale + shift;+} /* scalelast */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="scalepoints">-</a>++ qh_scalepoints(qh, points, numpoints, dim, newlows, newhighs )+ scale points to new lowbound and highbound+ retains old bound when newlow= -REALmax or newhigh= +REALmax++ returns:+ scaled points+ overwrites old points++ design:+ for each coordinate+ compute current low and high bound+ compute scale and shift factors+ scale all points+ enforce new low and high bound for all points+*/+void qh_scalepoints(qhT *qh, pointT *points, int numpoints, int dim,+ realT *newlows, realT *newhighs) {+ int i,k;+ realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;+ boolT nearzero= False;++ for (k=0; k < dim; k++) {+ newhigh= newhighs[k];+ newlow= newlows[k];+ if (newhigh > REALmax/2 && newlow < -REALmax/2)+ continue;+ low= REALmax;+ high= -REALmax;+ for (i=numpoints, coord=points+k; i--; coord += dim) {+ minimize_(low, *coord);+ maximize_(high, *coord);+ }+ if (newhigh > REALmax/2)+ newhigh= high;+ if (newlow < -REALmax/2)+ newlow= low;+ if (qh->DELAUNAY && k == dim-1 && newhigh < newlow) {+ qh_fprintf(qh, qh->ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",+ k, k, newhigh, newlow);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ scale= qh_divzero(newhigh - newlow, high - low,+ qh->MINdenom_1, &nearzero);+ if (nearzero) {+ qh_fprintf(qh, qh->ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",+ k, newlow, newhigh, low, high);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ shift= (newlow * high - low * newhigh)/(high-low);+ coord= points+k;+ for (i=numpoints; i--; coord += dim)+ *coord= *coord * scale + shift;+ coord= points+k;+ if (newlow < newhigh) {+ mincoord= newlow;+ maxcoord= newhigh;+ }else {+ mincoord= newhigh;+ maxcoord= newlow;+ }+ for (i=numpoints; i--; coord += dim) {+ minimize_(*coord, maxcoord); /* because of roundoff error */+ maximize_(*coord, mincoord);+ }+ trace0((qh, qh->ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",+ k, low, high, newlow, newhigh, numpoints, scale, shift));+ }+} /* scalepoints */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="setdelaunay">-</a>++ qh_setdelaunay(qh, dim, count, points )+ project count points to dim-d paraboloid for Delaunay triangulation++ dim is one more than the dimension of the input set+ assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)++ points is a dim*count realT array. The first dim-1 coordinates+ are the coordinates of the first input point. array[dim] is+ the first coordinate of the second input point. array[2*dim] is+ the first coordinate of the third input point.++ if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)+ calls qh_scalelast to scale the last coordinate the same as the other points++ returns:+ for each point+ sets point[dim-1] to sum of squares of coordinates+ scale points to 'Qbb' if needed++ notes:+ to project one point, use+ qh_setdelaunay(qh, qh->hull_dim, 1, point)++ Do not use options 'Qbk', 'QBk', or 'QbB' since they scale+ the coordinates after the original projection.++*/+void qh_setdelaunay(qhT *qh, int dim, int count, pointT *points) {+ int i, k;+ coordT *coordp, coord;+ realT paraboloid;++ trace0((qh, qh->ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));+ coordp= points;+ for (i=0; i < count; i++) {+ coord= *coordp++;+ paraboloid= coord*coord;+ for (k=dim-2; k--; ) {+ coord= *coordp++;+ paraboloid += coord*coord;+ }+ *coordp++ = paraboloid;+ }+ if (qh->last_low < REALmax/2)+ qh_scalelast(qh, points, count, dim, qh->last_low, qh->last_high, qh->last_newhigh);+} /* setdelaunay */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="sethalfspace">-</a>++ qh_sethalfspace(qh, dim, coords, nextp, normal, offset, feasible )+ set point to dual of halfspace relative to feasible point+ halfspace is normal coefficients and offset.++ returns:+ false and prints error if feasible point is outside of hull+ overwrites coordinates for point at dim coords+ nextp= next point (coords)+ does not call qh_errexit++ design:+ compute distance from feasible point to halfspace+ divide each normal coefficient by -dist+*/+boolT qh_sethalfspace(qhT *qh, int dim, coordT *coords, coordT **nextp,+ coordT *normal, coordT *offset, coordT *feasible) {+ coordT *normp= normal, *feasiblep= feasible, *coordp= coords;+ realT dist;+ realT r; /*bug fix*/+ int k;+ boolT zerodiv;++ dist= *offset;+ for (k=dim; k--; )+ dist += *(normp++) * *(feasiblep++);+ if (dist > 0)+ goto LABELerroroutside;+ normp= normal;+ if (dist < -qh->MINdenom) {+ for (k=dim; k--; )+ *(coordp++)= *(normp++) / -dist;+ }else {+ for (k=dim; k--; ) {+ *(coordp++)= qh_divzero(*(normp++), -dist, qh->MINdenom_1, &zerodiv);+ if (zerodiv)+ goto LABELerroroutside;+ }+ }+ *nextp= coordp;+ if (qh->IStracing >= 4) {+ qh_fprintf(qh, qh->ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);+ for (k=dim, coordp=coords; k--; ) {+ r= *coordp++;+ qh_fprintf(qh, qh->ferr, 8022, " %6.2g", r);+ }+ qh_fprintf(qh, qh->ferr, 8023, "\n");+ }+ return True;+LABELerroroutside:+ feasiblep= feasible;+ normp= normal;+ qh_fprintf(qh, qh->ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");+ for (k=dim; k--; )+ qh_fprintf(qh, qh->ferr, 8024, qh_REAL_1, r=*(feasiblep++));+ qh_fprintf(qh, qh->ferr, 8025, "\n halfspace: ");+ for (k=dim; k--; )+ qh_fprintf(qh, qh->ferr, 8026, qh_REAL_1, r=*(normp++));+ qh_fprintf(qh, qh->ferr, 8027, "\n at offset: ");+ qh_fprintf(qh, qh->ferr, 8028, qh_REAL_1, *offset);+ qh_fprintf(qh, qh->ferr, 8029, " and distance: ");+ qh_fprintf(qh, qh->ferr, 8030, qh_REAL_1, dist);+ qh_fprintf(qh, qh->ferr, 8031, "\n");+ return False;+} /* sethalfspace */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="sethalfspace_all">-</a>++ qh_sethalfspace_all(qh, dim, count, halfspaces, feasible )+ generate dual for halfspace intersection with feasible point+ array of count halfspaces+ each halfspace is normal coefficients followed by offset+ the origin is inside the halfspace if the offset is negative+ feasible is a point inside all halfspaces (http://www.qhull.org/html/qhalf.htm#notes)++ returns:+ malloc'd array of count X dim-1 points++ notes:+ call before qh_init_B or qh_initqhull_globals+ free memory when done+ unused/untested code: please email bradb@shore.net if this works ok for you+ if using option 'Fp', qh->feasible_point must be set (e.g., to 'feasible')+ qh->feasible_point is a malloc'd array that is freed by qh_freebuffers.++ design:+ see qh_sethalfspace+*/+coordT *qh_sethalfspace_all(qhT *qh, int dim, int count, coordT *halfspaces, pointT *feasible) {+ int i, newdim;+ pointT *newpoints;+ coordT *coordp, *normalp, *offsetp;++ trace0((qh, qh->ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));+ newdim= dim - 1;+ if (!(newpoints=(coordT*)qh_malloc(count*newdim*sizeof(coordT)))){+ qh_fprintf(qh, qh->ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n",+ count);+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ coordp= newpoints;+ normalp= halfspaces;+ for (i=0; i < count; i++) {+ offsetp= normalp + newdim;+ if (!qh_sethalfspace(qh, newdim, coordp, &coordp, normalp, offsetp, feasible)) {+ qh_free(newpoints); /* feasible is not inside halfspace as reported by qh_sethalfspace */+ qh_fprintf(qh, qh->ferr, 8032, "The halfspace was at index %d\n", i);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ normalp= offsetp + 1;+ }+ return newpoints;+} /* sethalfspace_all */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="sharpnewfacets">-</a>++ qh_sharpnewfacets(qh)++ returns:+ true if could be an acute angle (facets in different quadrants)++ notes:+ for qh_findbest++ design:+ for all facets on qh.newfacet_list+ if two facets are in different quadrants+ set issharp+*/+boolT qh_sharpnewfacets(qhT *qh) {+ facetT *facet;+ boolT issharp = False;+ int *quadrant, k;++ quadrant= (int*)qh_memalloc(qh, qh->hull_dim * sizeof(int));+ FORALLfacet_(qh->newfacet_list) {+ if (facet == qh->newfacet_list) {+ for (k=qh->hull_dim; k--; )+ quadrant[ k]= (facet->normal[ k] > 0);+ }else {+ for (k=qh->hull_dim; k--; ) {+ if (quadrant[ k] != (facet->normal[ k] > 0)) {+ issharp= True;+ break;+ }+ }+ }+ if (issharp)+ break;+ }+ qh_memfree(qh, quadrant, qh->hull_dim * sizeof(int));+ trace3((qh, qh->ferr, 3001, "qh_sharpnewfacets: %d\n", issharp));+ return issharp;+} /* sharpnewfacets */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="voronoi_center">-</a>++ qh_voronoi_center(qh, dim, points )+ return Voronoi center for a set of points+ dim is the orginal dimension of the points+ gh.gm_matrix/qh.gm_row are scratch buffers++ returns:+ center as a temporary point (qh_memalloc)+ if non-simplicial,+ returns center for max simplex of points++ notes:+ only called by qh_facetcenter+ from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65++ design:+ if non-simplicial+ determine max simplex for points+ translate point0 of simplex to origin+ compute sum of squares of diagonal+ compute determinate+ compute Voronoi center (see Bowyer & Woodwark)+*/+pointT *qh_voronoi_center(qhT *qh, int dim, setT *points) {+ pointT *point, **pointp, *point0;+ pointT *center= (pointT*)qh_memalloc(qh, qh->center_size);+ setT *simplex;+ int i, j, k, size= qh_setsize(qh, points);+ coordT *gmcoord;+ realT *diffp, sum2, *sum2row, *sum2p, det, factor;+ boolT nearzero, infinite;++ if (size == dim+1)+ simplex= points;+ else if (size < dim+1) {+ qh_memfree(qh, center, qh->center_size);+ qh_fprintf(qh, qh->ferr, 6025, "qhull internal error (qh_voronoi_center):\n need at least %d points to construct a Voronoi center\n",+ dim+1);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ simplex= points; /* never executed -- avoids warning */+ }else {+ simplex= qh_settemp(qh, dim+1);+ qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);+ }+ point0= SETfirstt_(simplex, pointT);+ gmcoord= qh->gm_matrix;+ for (k=0; k < dim; k++) {+ qh->gm_row[k]= gmcoord;+ FOREACHpoint_(simplex) {+ if (point != point0)+ *(gmcoord++)= point[k] - point0[k];+ }+ }+ sum2row= gmcoord;+ for (i=0; i < dim; i++) {+ sum2= 0.0;+ for (k=0; k < dim; k++) {+ diffp= qh->gm_row[k] + i;+ sum2 += *diffp * *diffp;+ }+ *(gmcoord++)= sum2;+ }+ det= qh_determinant(qh, qh->gm_row, dim, &nearzero);+ factor= qh_divzero(0.5, det, qh->MINdenom, &infinite);+ if (infinite) {+ for (k=dim; k--; )+ center[k]= qh_INFINITE;+ if (qh->IStracing)+ qh_printpoints(qh, qh->ferr, "qh_voronoi_center: at infinity for ", simplex);+ }else {+ for (i=0; i < dim; i++) {+ gmcoord= qh->gm_matrix;+ sum2p= sum2row;+ for (k=0; k < dim; k++) {+ qh->gm_row[k]= gmcoord;+ if (k == i) {+ for (j=dim; j--; )+ *(gmcoord++)= *sum2p++;+ }else {+ FOREACHpoint_(simplex) {+ if (point != point0)+ *(gmcoord++)= point[k] - point0[k];+ }+ }+ }+ center[i]= qh_determinant(qh, qh->gm_row, dim, &nearzero)*factor + point0[i];+ }+#ifndef qh_NOtrace+ if (qh->IStracing >= 3) {+ qh_fprintf(qh, qh->ferr, 8033, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);+ qh_printmatrix(qh, qh->ferr, "center:", ¢er, 1, dim);+ if (qh->IStracing >= 5) {+ qh_printpoints(qh, qh->ferr, "points", simplex);+ FOREACHpoint_(simplex)+ qh_fprintf(qh, qh->ferr, 8034, "p%d dist %.2g, ", qh_pointid(qh, point),+ qh_pointdist(point, center, dim));+ qh_fprintf(qh, qh->ferr, 8035, "\n");+ }+ }+#endif+ }+ if (simplex != points)+ qh_settempfree(qh, &simplex);+ return center;+} /* voronoi_center */+
+ Cdir/geom_r.c view
@@ -0,0 +1,1234 @@+/*<html><pre> -<a href="qh-geom_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ geom_r.c+ geometric routines of qhull++ see qh-geom_r.htm and geom_r.h++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/geom_r.c#2 $$Change: 1995 $+ $DateTime: 2015/10/13 21:59:42 $$Author: bbarber $++ infrequent code goes into geom2_r.c+*/++#include "qhull_ra.h"++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="distplane">-</a>++ qh_distplane(qh, point, facet, dist )+ return distance from point to facet++ returns:+ dist+ if qh.RANDOMdist, joggles result++ notes:+ dist > 0 if point is above facet (i.e., outside)+ does not error (for qh_sortfacets, qh_outerinner)++ see:+ qh_distnorm in geom2_r.c+ qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies+*/+void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {+ coordT *normal= facet->normal, *coordp, randr;+ int k;++ switch (qh->hull_dim){+ case 2:+ *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];+ break;+ case 3:+ *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];+ break;+ case 4:+ *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];+ break;+ case 5:+ *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];+ break;+ case 6:+ *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];+ break;+ case 7:+ *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];+ break;+ case 8:+ *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];+ break;+ default:+ *dist= facet->offset;+ coordp= point;+ for (k=qh->hull_dim; k--; )+ *dist += *coordp++ * *normal++;+ break;+ }+ zinc_(Zdistplane);+ if (!qh->RANDOMdist && qh->IStracing < 4)+ return;+ if (qh->RANDOMdist) {+ randr= qh_RANDOMint;+ *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *+ qh->RANDOMfactor * qh->MAXabs_coord;+ }+ if (qh->IStracing >= 4) {+ qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");+ qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);+ qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);+ }+ return;+} /* distplane */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="findbest">-</a>++ qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )+ find facet that is furthest below a point+ for upperDelaunay facets+ returns facet only if !qh_NOupper and clearly above++ input:+ starts search at 'startfacet' (can not be flipped)+ if !bestoutside(qh_ALL), stops at qh.MINoutside++ returns:+ best facet (reports error if NULL)+ early out if isoutside defined and bestdist > qh.MINoutside+ dist is distance to facet+ isoutside is true if point is outside of facet+ numpart counts the number of distance tests++ see also:+ qh_findbestnew()++ notes:+ If merging (testhorizon), searches horizon facets of coplanar best facets because+ after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d+ avoid calls to distplane, function calls, and real number operations.+ caller traces result+ Optimized for outside points. Tried recording a search set for qh_findhorizon.+ Made code more complicated.++ when called by qh_partitionvisible():+ indicated by qh_ISnewfacets+ qh.newfacet_list is list of simplicial, new facets+ qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)+ qh.bestfacet_notsharp set if qh_sharpnewfacets returns False++ when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),+ qh_check_bestdist(), qh_addpoint()+ indicated by !qh_ISnewfacets+ returns best facet in neighborhood of given facet+ this is best facet overall if dist > - qh.MAXcoplanar+ or hull has at least a "spherical" curvature++ design:+ initialize and test for early exit+ repeat while there are better facets+ for each neighbor of facet+ exit if outside facet found+ test for better facet+ if point is inside and partitioning+ test for new facets with a "sharp" intersection+ if so, future calls go to qh_findbestnew()+ test horizon facets+*/+facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,+ boolT bestoutside, boolT isnewfacets, boolT noupper,+ realT *dist, boolT *isoutside, int *numpart) {+ realT bestdist= -REALmax/2 /* avoid underflow */;+ facetT *facet, *neighbor, **neighborp;+ facetT *bestfacet= NULL, *lastfacet= NULL;+ int oldtrace= qh->IStracing;+ unsigned int visitid= ++qh->visit_id;+ int numpartnew=0;+ boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */++ zinc_(Zfindbest);+ if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {+ if (qh->TRACElevel > qh->IStracing)+ qh->IStracing= qh->TRACElevel;+ qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",+ qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);+ qh_fprintf(qh, qh->ferr, 8005, " testhorizon? %d noupper? %d", testhorizon, noupper);+ qh_fprintf(qh, qh->ferr, 8006, " Last point added was p%d.", qh->furthest_id);+ qh_fprintf(qh, qh->ferr, 8007, " Last merge was #%d. max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);+ }+ if (isoutside)+ *isoutside= True;+ if (!startfacet->flipped) { /* test startfacet */+ *numpart= 1;+ qh_distplane(qh, point, startfacet, dist); /* this code is duplicated below */+ if (!bestoutside && *dist >= qh->MINoutside+ && (!startfacet->upperdelaunay || !noupper)) {+ bestfacet= startfacet;+ goto LABELreturn_best;+ }+ bestdist= *dist;+ if (!startfacet->upperdelaunay) {+ bestfacet= startfacet;+ }+ }else+ *numpart= 0;+ startfacet->visitid= visitid;+ facet= startfacet;+ while (facet) {+ trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",+ facet->id, bestdist, getid_(bestfacet)));+ lastfacet= facet;+ FOREACHneighbor_(facet) {+ if (!neighbor->newfacet && isnewfacets)+ continue;+ if (neighbor->visitid == visitid)+ continue;+ neighbor->visitid= visitid;+ if (!neighbor->flipped) { /* code duplicated above */+ (*numpart)++;+ qh_distplane(qh, point, neighbor, dist);+ if (*dist > bestdist) {+ if (!bestoutside && *dist >= qh->MINoutside+ && (!neighbor->upperdelaunay || !noupper)) {+ bestfacet= neighbor;+ goto LABELreturn_best;+ }+ if (!neighbor->upperdelaunay) {+ bestfacet= neighbor;+ bestdist= *dist;+ break; /* switch to neighbor */+ }else if (!bestfacet) {+ bestdist= *dist;+ break; /* switch to neighbor */+ }+ } /* end of *dist>bestdist */+ } /* end of !flipped */+ } /* end of FOREACHneighbor */+ facet= neighbor; /* non-NULL only if *dist>bestdist */+ } /* end of while facet (directed search) */+ if (isnewfacets) {+ if (!bestfacet) {+ bestdist= -REALmax/2;+ bestfacet= qh_findbestnew(qh, point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);+ testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */+ }else if (!qh->findbest_notsharp && bestdist < - qh->DISTround) {+ if (qh_sharpnewfacets(qh)) {+ /* seldom used, qh_findbestnew will retest all facets */+ zinc_(Zfindnewsharp);+ bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);+ testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */+ qh->findbestnew= True;+ }else+ qh->findbest_notsharp= True;+ }+ }+ if (!bestfacet)+ bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart);+ if (testhorizon)+ bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);+ *dist= bestdist;+ if (isoutside && bestdist < qh->MINoutside)+ *isoutside= False;+LABELreturn_best:+ zadd_(Zfindbesttot, *numpart);+ zmax_(Zfindbestmax, *numpart);+ (*numpart) += numpartnew;+ qh->IStracing= oldtrace;+ return bestfacet;+} /* findbest */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="findbesthorizon">-</a>++ qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )+ search coplanar and better horizon facets from startfacet/bestdist+ ischeckmax turns off statistics and minsearch update+ all arguments must be initialized+ returns(ischeckmax):+ best facet+ returns(!ischeckmax):+ best facet that is not upperdelaunay+ allows upperdelaunay that is clearly outside+ returns:+ bestdist is distance to bestfacet+ numpart -- updates number of distance tests++ notes:+ no early out -- use qh_findbest() or qh_findbestnew()+ Searches coplanar or better horizon facets++ when called by qh_check_maxout() (qh_IScheckmax)+ startfacet must be closest to the point+ Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum+ even though other facets are below the point.+ updates facet->maxoutside for good, visited facets+ may return NULL++ searchdist is qh.max_outside + 2 * DISTround+ + max( MINvisible('Vn'), MAXcoplanar('Un'));+ This setting is a guess. It must be at least max_outside + 2*DISTround+ because a facet may have a geometric neighbor across a vertex++ design:+ for each horizon facet of coplanar best facets+ continue if clearly inside+ unless upperdelaunay or clearly outside+ update best facet+*/+facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {+ facetT *bestfacet= startfacet;+ realT dist;+ facetT *neighbor, **neighborp, *facet;+ facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */+ int numpartinit= *numpart, coplanarfacetset_size;+ unsigned int visitid= ++qh->visit_id;+ boolT newbest= False; /* for tracing */+ realT minsearch, searchdist; /* skip facets that are too far from point */++ if (!ischeckmax) {+ zinc_(Zfindhorizon);+ }else {+#if qh_MAXoutside+ if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)+ startfacet->maxoutside= *bestdist;+#endif+ }+ searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */+ minsearch= *bestdist - searchdist;+ if (ischeckmax) {+ /* Always check coplanar facets. Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */+ minimize_(minsearch, -searchdist);+ }+ coplanarfacetset_size= 0;+ facet= startfacet;+ while (True) {+ trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n",+ facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,+ minsearch, searchdist));+ FOREACHneighbor_(facet) {+ if (neighbor->visitid == visitid)+ continue;+ neighbor->visitid= visitid;+ if (!neighbor->flipped) {+ qh_distplane(qh, point, neighbor, &dist);+ (*numpart)++;+ if (dist > *bestdist) {+ if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {+ bestfacet= neighbor;+ *bestdist= dist;+ newbest= True;+ if (!ischeckmax) {+ minsearch= dist - searchdist;+ if (dist > *bestdist + searchdist) {+ zinc_(Zfindjump); /* everything in qh.coplanarfacetset at least searchdist below */+ coplanarfacetset_size= 0;+ }+ }+ }+ }else if (dist < minsearch)+ continue; /* if ischeckmax, dist can't be positive */+#if qh_MAXoutside+ if (ischeckmax && dist > neighbor->maxoutside)+ neighbor->maxoutside= dist;+#endif+ } /* end of !flipped */+ if (nextfacet) {+ if (!coplanarfacetset_size++) {+ SETfirst_(qh->coplanarfacetset)= nextfacet;+ SETtruncate_(qh->coplanarfacetset, 1);+ }else+ qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv+ and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv */+ }+ nextfacet= neighbor;+ } /* end of EACHneighbor */+ facet= nextfacet;+ if (facet)+ nextfacet= NULL;+ else if (!coplanarfacetset_size)+ break;+ else if (!--coplanarfacetset_size) {+ facet= SETfirstt_(qh->coplanarfacetset, facetT);+ SETtruncate_(qh->coplanarfacetset, 0);+ }else+ facet= (facetT*)qh_setdellast(qh->coplanarfacetset);+ } /* while True, for each facet in qh.coplanarfacetset */+ if (!ischeckmax) {+ zadd_(Zfindhorizontot, *numpart - numpartinit);+ zmax_(Zfindhorizonmax, *numpart - numpartinit);+ if (newbest)+ zinc_(Zparthorizon);+ }+ trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));+ return bestfacet;+} /* findbesthorizon */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="findbestnew">-</a>++ qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )+ find best newfacet for point+ searches all of qh.newfacet_list starting at startfacet+ searches horizon facets of coplanar best newfacets+ searches all facets if startfacet == qh.facet_list+ returns:+ best new or horizon facet that is not upperdelaunay+ early out if isoutside and not 'Qf'+ dist is distance to facet+ isoutside is true if point is outside of facet+ numpart is number of distance tests++ notes:+ Always used for merged new facets (see qh_USEfindbestnew)+ Avoids upperdelaunay facet unless (isoutside and outside)++ Uses qh.visit_id, qh.coplanarfacetset.+ If share visit_id with qh_findbest, coplanarfacetset is incorrect.++ If merging (testhorizon), searches horizon facets of coplanar best facets because+ a point maybe coplanar to the bestfacet, below its horizon facet,+ and above a horizon facet of a coplanar newfacet. For example,+ rbox 1000 s Z1 G1e-13 | qhull+ rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc++ qh_findbestnew() used if+ qh_sharpnewfacets -- newfacets contains a sharp angle+ if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)++ see also:+ qh_partitionall() and qh_findbest()++ design:+ for each new facet starting from startfacet+ test distance from point to facet+ return facet if clearly outside+ unless upperdelaunay and a lowerdelaunay exists+ update best facet+ test horizon facets+*/+facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,+ realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {+ realT bestdist= -REALmax/2;+ facetT *bestfacet= NULL, *facet;+ int oldtrace= qh->IStracing, i;+ unsigned int visitid= ++qh->visit_id;+ realT distoutside= 0.0;+ boolT isdistoutside; /* True if distoutside is defined */+ boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */++ if (!startfacet) {+ if (qh->MERGING)+ qh_fprintf(qh, qh->ferr, 6001, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets. Can not continue.\n");+ else+ qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",+ qh->furthest_id);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ zinc_(Zfindnew);+ if (qh->BESToutside || bestoutside)+ isdistoutside= False;+ else {+ isdistoutside= True;+ distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */+ }+ if (isoutside)+ *isoutside= True;+ *numpart= 0;+ if (qh->IStracing >= 3 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {+ if (qh->TRACElevel > qh->IStracing)+ qh->IStracing= qh->TRACElevel;+ qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",+ qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);+ qh_fprintf(qh, qh->ferr, 8009, " Last point added p%d visitid %d.", qh->furthest_id, visitid);+ qh_fprintf(qh, qh->ferr, 8010, " Last merge was #%d.\n", zzval_(Ztotmerge));+ }+ /* visit all new facets starting with startfacet, maybe qh->facet_list */+ for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {+ FORALLfacet_(facet) {+ if (facet == startfacet && i)+ break;+ facet->visitid= visitid;+ if (!facet->flipped) {+ qh_distplane(qh, point, facet, dist);+ (*numpart)++;+ if (*dist > bestdist) {+ if (!facet->upperdelaunay || *dist >= qh->MINoutside) {+ bestfacet= facet;+ if (isdistoutside && *dist >= distoutside)+ goto LABELreturn_bestnew;+ bestdist= *dist;+ }+ }+ } /* end of !flipped */+ } /* FORALLfacet from startfacet or qh->newfacet_list */+ }+ if (testhorizon || !bestfacet) /* testhorizon is always True. Keep the same code as qh_findbest */+ bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,+ !qh_NOupper, &bestdist, numpart);+ *dist= bestdist;+ if (isoutside && *dist < qh->MINoutside)+ *isoutside= False;+LABELreturn_bestnew:+ zadd_(Zfindnewtot, *numpart);+ zmax_(Zfindnewmax, *numpart);+ trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));+ qh->IStracing= oldtrace;+ return bestfacet;+} /* findbestnew */++/* ============ hyperplane functions -- keep code together [?] ============ */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="backnormal">-</a>++ qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )+ given an upper-triangular rows array and a sign,+ solve for normal equation x using back substitution over rows U++ returns:+ normal= x++ if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),+ if fails on last row+ this means that the hyperplane intersects [0,..,1]+ sets last coordinate of normal to sign+ otherwise+ sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]+ sets nearzero++ notes:+ assumes numrow == numcol-1++ see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"++ solves Ux=b where Ax=b and PA=LU+ b= [0,...,0,sign or 0] (sign is either -1 or +1)+ last row of A= [0,...,0,1]++ 1) Ly=Pb == y=b since P only permutes the 0's of b++ design:+ for each row from end+ perform back substitution+ if near zero+ use qh_divzero for division+ if zero divide and not last row+ set tail of normal to 0+*/+void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,+ coordT *normal, boolT *nearzero) {+ int i, j;+ coordT *normalp, *normal_tail, *ai, *ak;+ realT diagonal;+ boolT waszero;+ int zerocol= -1;++ normalp= normal + numcol - 1;+ *normalp--= (sign ? -1.0 : 1.0);+ for (i=numrow; i--; ) {+ *normalp= 0.0;+ ai= rows[i] + i + 1;+ ak= normalp+1;+ for (j=i+1; j < numcol; j++)+ *normalp -= *ai++ * *ak++;+ diagonal= (rows[i])[i];+ if (fabs_(diagonal) > qh->MINdenom_2)+ *(normalp--) /= diagonal;+ else {+ waszero= False;+ *normalp= qh_divzero(*normalp, diagonal, qh->MINdenom_1_2, &waszero);+ if (waszero) {+ zerocol= i;+ *(normalp--)= (sign ? -1.0 : 1.0);+ for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)+ *normal_tail= 0.0;+ }else+ normalp--;+ }+ }+ if (zerocol != -1) {+ zzinc_(Zback0);+ *nearzero= True;+ trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));+ qh_precision(qh, "zero diagonal on back substitution");+ }+} /* backnormal */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="gausselim">-</a>++ qh_gausselim(qh, rows, numrow, numcol, sign )+ Gaussian elimination with partial pivoting++ returns:+ rows is upper triangular (includes row exchanges)+ flips sign for each row exchange+ sets nearzero if pivot[k] < qh.NEARzero[k], else clears it++ notes:+ if nearzero, the determinant's sign may be incorrect.+ assumes numrow <= numcol++ design:+ for each row+ determine pivot and exchange rows if necessary+ test for near zero+ perform gaussian elimination step+*/+void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {+ realT *ai, *ak, *rowp, *pivotrow;+ realT n, pivot, pivot_abs= 0.0, temp;+ int i, j, k, pivoti, flip=0;++ *nearzero= False;+ for (k=0; k < numrow; k++) {+ pivot_abs= fabs_((rows[k])[k]);+ pivoti= k;+ for (i=k+1; i < numrow; i++) {+ if ((temp= fabs_((rows[i])[k])) > pivot_abs) {+ pivot_abs= temp;+ pivoti= i;+ }+ }+ if (pivoti != k) {+ rowp= rows[pivoti];+ rows[pivoti]= rows[k];+ rows[k]= rowp;+ *sign ^= 1;+ flip ^= 1;+ }+ if (pivot_abs <= qh->NEARzero[k]) {+ *nearzero= True;+ if (pivot_abs == 0.0) { /* remainder of column == 0 */+ if (qh->IStracing >= 4) {+ qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);+ qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);+ }+ zzinc_(Zgauss0);+ qh_precision(qh, "zero pivot for Gaussian elimination");+ goto LABELnextcol;+ }+ }+ pivotrow= rows[k] + k;+ pivot= *pivotrow++; /* signed value of pivot, and remainder of row */+ for (i=k+1; i < numrow; i++) {+ ai= rows[i] + k;+ ak= pivotrow;+ n= (*ai++)/pivot; /* divzero() not needed since |pivot| >= |*ai| */+ for (j= numcol - (k+1); j--; )+ *ai++ -= n * *ak++;+ }+ LABELnextcol:+ ;+ }+ wmin_(Wmindenom, pivot_abs); /* last pivot element */+ if (qh->IStracing >= 5)+ qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);+} /* gausselim */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="getangle">-</a>++ qh_getangle(qh, vect1, vect2 )+ returns the dot product of two vectors+ if qh.RANDOMdist, joggles result++ notes:+ the angle may be > 1.0 or < -1.0 because of roundoff errors++*/+realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {+ realT angle= 0, randr;+ int k;++ for (k=qh->hull_dim; k--; )+ angle += *vect1++ * *vect2++;+ if (qh->RANDOMdist) {+ randr= qh_RANDOMint;+ angle += (2.0 * randr / qh_RANDOMmax - 1.0) *+ qh->RANDOMfactor;+ }+ trace4((qh, qh->ferr, 4006, "qh_getangle: %2.2g\n", angle));+ return(angle);+} /* getangle */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="getcenter">-</a>++ qh_getcenter(qh, vertices )+ returns arithmetic center of a set of vertices as a new point++ notes:+ allocates point array for center+*/+pointT *qh_getcenter(qhT *qh, setT *vertices) {+ int k;+ pointT *center, *coord;+ vertexT *vertex, **vertexp;+ int count= qh_setsize(qh, vertices);++ if (count < 2) {+ qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ center= (pointT *)qh_memalloc(qh, qh->normal_size);+ for (k=0; k < qh->hull_dim; k++) {+ coord= center+k;+ *coord= 0.0;+ FOREACHvertex_(vertices)+ *coord += vertex->point[k];+ *coord /= count; /* count>=2 by QH6003 */+ }+ return(center);+} /* getcenter */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="getcentrum">-</a>++ qh_getcentrum(qh, facet )+ returns the centrum for a facet as a new point++ notes:+ allocates the centrum+*/+pointT *qh_getcentrum(qhT *qh, facetT *facet) {+ realT dist;+ pointT *centrum, *point;++ point= qh_getcenter(qh, facet->vertices);+ zzinc_(Zcentrumtests);+ qh_distplane(qh, point, facet, &dist);+ centrum= qh_projectpoint(qh, point, facet, dist);+ qh_memfree(qh, point, qh->normal_size);+ trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",+ facet->id, qh_setsize(qh, facet->vertices), dist));+ return centrum;+} /* getcentrum */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="getdistance">-</a>++ qh_getdistance(qh, facet, neighbor, mindist, maxdist )+ returns the maxdist and mindist distance of any vertex from neighbor++ returns:+ the max absolute value++ design:+ for each vertex of facet that is not in neighbor+ test the distance from vertex to neighbor+*/+realT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {+ vertexT *vertex, **vertexp;+ realT dist, maxd, mind;++ FOREACHvertex_(facet->vertices)+ vertex->seen= False;+ FOREACHvertex_(neighbor->vertices)+ vertex->seen= True;+ mind= 0.0;+ maxd= 0.0;+ FOREACHvertex_(facet->vertices) {+ if (!vertex->seen) {+ zzinc_(Zbestdist);+ qh_distplane(qh, vertex->point, neighbor, &dist);+ if (dist < mind)+ mind= dist;+ else if (dist > maxd)+ maxd= dist;+ }+ }+ *mindist= mind;+ *maxdist= maxd;+ mind= -mind;+ if (maxd > mind)+ return maxd;+ else+ return mind;+} /* getdistance */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="normalize">-</a>++ qh_normalize(qh, normal, dim, toporient )+ normalize a vector and report if too small+ does not use min norm++ see:+ qh_normalize2+*/+void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {+ qh_normalize2(qh, normal, dim, toporient, NULL, NULL);+} /* normalize */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="normalize2">-</a>++ qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )+ normalize a vector and report if too small+ qh.MINdenom/MINdenom1 are the upper limits for divide overflow++ returns:+ normalized vector+ flips sign if !toporient+ if minnorm non-NULL,+ sets ismin if normal < minnorm++ notes:+ if zero norm+ sets all elements to sqrt(1.0/dim)+ if divide by zero (divzero())+ sets largest element to +/-1+ bumps Znearlysingular++ design:+ computes norm+ test for minnorm+ if not near zero+ normalizes normal+ else if zero norm+ sets normal to standard value+ else+ uses qh_divzero to normalize+ if nearzero+ sets norm to direction of maximum value+*/+void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,+ realT *minnorm, boolT *ismin) {+ int k;+ realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;+ boolT zerodiv;++ norm1= normal+1;+ norm2= normal+2;+ norm3= normal+3;+ if (dim == 2)+ norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));+ else if (dim == 3)+ norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));+ else if (dim == 4) {+ norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)+ + (*norm3)*(*norm3));+ }else if (dim > 4) {+ norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)+ + (*norm3)*(*norm3);+ for (k=dim-4, colp=normal+4; k--; colp++)+ norm += (*colp) * (*colp);+ norm= sqrt(norm);+ }+ if (minnorm) {+ if (norm < *minnorm)+ *ismin= True;+ else+ *ismin= False;+ }+ wmin_(Wmindenom, norm);+ if (norm > qh->MINdenom) {+ if (!toporient)+ norm= -norm;+ *normal /= norm;+ *norm1 /= norm;+ if (dim == 2)+ ; /* all done */+ else if (dim == 3)+ *norm2 /= norm;+ else if (dim == 4) {+ *norm2 /= norm;+ *norm3 /= norm;+ }else if (dim >4) {+ *norm2 /= norm;+ *norm3 /= norm;+ for (k=dim-4, colp=normal+4; k--; )+ *colp++ /= norm;+ }+ }else if (norm == 0.0) {+ temp= sqrt(1.0/dim);+ for (k=dim, colp=normal; k--; )+ *colp++ = temp;+ }else {+ if (!toporient)+ norm= -norm;+ for (k=dim, colp=normal; k--; colp++) { /* k used below */+ temp= qh_divzero(*colp, norm, qh->MINdenom_1, &zerodiv);+ if (!zerodiv)+ *colp= temp;+ else {+ maxp= qh_maxabsval(normal, dim);+ temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);+ for (k=dim, colp=normal; k--; colp++)+ *colp= 0.0;+ *maxp= temp;+ zzinc_(Znearlysingular);+ trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",+ norm, qh->furthest_id));+ return;+ }+ }+ }+} /* normalize */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="projectpoint">-</a>++ qh_projectpoint(qh, point, facet, dist )+ project point onto a facet by dist++ returns:+ returns a new point++ notes:+ if dist= distplane(point,facet)+ this projects point to hyperplane+ assumes qh_memfree_() is valid for normal_size+*/+pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {+ pointT *newpoint, *np, *normal;+ int normsize= qh->normal_size;+ int k;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */++ qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);+ np= newpoint;+ normal= facet->normal;+ for (k=qh->hull_dim; k--; )+ *(np++)= *point++ - dist * *normal++;+ return(newpoint);+} /* projectpoint */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="setfacetplane">-</a>++ qh_setfacetplane(qh, facet )+ sets the hyperplane for a facet+ if qh.RANDOMdist, joggles hyperplane++ notes:+ uses global buffers qh.gm_matrix and qh.gm_row+ overwrites facet->normal if already defined+ updates Wnewvertex if PRINTstatistics+ sets facet->upperdelaunay if upper envelope of Delaunay triangulation++ design:+ copy vertex coordinates to qh.gm_matrix/gm_row+ compute determinate+ if nearzero+ recompute determinate with gaussian elimination+ if nearzero+ force outside orientation by testing interior point+*/+void qh_setfacetplane(qhT *qh, facetT *facet) {+ pointT *point;+ vertexT *vertex, **vertexp;+ int normsize= qh->normal_size;+ int k,i, oldtrace= 0;+ realT dist;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */+ coordT *coord, *gmcoord;+ pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;+ boolT nearzero= False;++ zzinc_(Zsetplane);+ if (!facet->normal)+ qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);+ if (facet == qh->tracefacet) {+ oldtrace= qh->IStracing;+ qh->IStracing= 5;+ qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);+ qh_fprintf(qh, qh->ferr, 8013, " Last point added to hull was p%d.", qh->furthest_id);+ if (zzval_(Ztotmerge))+ qh_fprintf(qh, qh->ferr, 8014, " Last merge was #%d.", zzval_(Ztotmerge));+ qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");+ qh_printsummary(qh, qh->ferr);+ }+ if (qh->hull_dim <= 4) {+ i= 0;+ if (qh->RANDOMdist) {+ gmcoord= qh->gm_matrix;+ FOREACHvertex_(facet->vertices) {+ qh->gm_row[i++]= gmcoord;+ coord= vertex->point;+ for (k=qh->hull_dim; k--; )+ *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);+ }+ }else {+ FOREACHvertex_(facet->vertices)+ qh->gm_row[i++]= vertex->point;+ }+ qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,+ facet->normal, &facet->offset, &nearzero);+ }+ if (qh->hull_dim > 4 || nearzero) {+ i= 0;+ gmcoord= qh->gm_matrix;+ FOREACHvertex_(facet->vertices) {+ if (vertex->point != point0) {+ qh->gm_row[i++]= gmcoord;+ coord= vertex->point;+ point= point0;+ for (k=qh->hull_dim; k--; )+ *(gmcoord++)= *coord++ - *point++;+ }+ }+ qh->gm_row[i]= gmcoord; /* for areasimplex */+ if (qh->RANDOMdist) {+ gmcoord= qh->gm_matrix;+ for (i=qh->hull_dim-1; i--; ) {+ for (k=qh->hull_dim; k--; )+ *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);+ }+ }+ qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,+ facet->normal, &facet->offset, &nearzero);+ if (nearzero) {+ if (qh_orientoutside(qh, facet)) {+ trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh->furthest_id));+ /* this is part of using Gaussian Elimination. For example in 5-d+ 1 1 1 1 0+ 1 1 1 1 1+ 0 0 0 1 0+ 0 1 0 0 0+ 1 0 0 0 0+ norm= 0.38 0.38 -0.76 0.38 0+ has a determinate of 1, but g.e. after subtracting pt. 0 has+ 0's in the diagonal, even with full pivoting. It does work+ if you subtract pt. 4 instead. */+ }+ }+ }+ facet->upperdelaunay= False;+ if (qh->DELAUNAY) {+ if (qh->UPPERdelaunay) { /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */+ if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)+ facet->upperdelaunay= True;+ }else {+ if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)+ facet->upperdelaunay= True;+ }+ }+ if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {+ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ FOREACHvertex_(facet->vertices) {+ if (vertex->point != point0) {+ boolT istrace= False;+ zinc_(Zdiststat);+ qh_distplane(qh, vertex->point, facet, &dist);+ dist= fabs_(dist);+ zinc_(Znewvertex);+ wadd_(Wnewvertex, dist);+ if (dist > wwval_(Wnewvertexmax)) {+ wwval_(Wnewvertexmax)= dist;+ if (dist > qh->max_outside) {+ qh->max_outside= dist; /* used by qh_maxouter(qh) */+ if (dist > qh->TRACEdist)+ istrace= True;+ }+ }else if (-dist > qh->TRACEdist)+ istrace= True;+ if (istrace) {+ qh_fprintf(qh, qh->ferr, 8016, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",+ qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);+ qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);+ }+ }+ }+ qh->RANDOMdist= qh->old_randomdist;+ }+ if (qh->IStracing >= 3) {+ qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",+ facet->id, facet->offset);+ for (k=0; k < qh->hull_dim; k++)+ qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);+ qh_fprintf(qh, qh->ferr, 8019, "\n");+ }+ if (facet == qh->tracefacet)+ qh->IStracing= oldtrace;+} /* setfacetplane */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="sethyperplane_det">-</a>++ qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )+ given dim X dim array indexed by rows[], one row per point,+ toporient(flips all signs),+ and point0 (any row)+ set normalized hyperplane equation from oriented simplex++ returns:+ normal (normalized)+ offset (places point0 on the hyperplane)+ sets nearzero if hyperplane not through points++ notes:+ only defined for dim == 2..4+ rows[] is not modified+ solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane+ see Bower & Woodworth, A programmer's geometry, Butterworths 1983.++ derivation of 3-d minnorm+ Goal: all vertices V_i within qh.one_merge of hyperplane+ Plan: exactly translate the facet so that V_0 is the origin+ exactly rotate the facet so that V_1 is on the x-axis and y_2=0.+ exactly rotate the effective perturbation to only effect n_0+ this introduces a factor of sqrt(3)+ n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm+ Let M_d be the max coordinate difference+ Let M_a be the greater of M_d and the max abs. coordinate+ Let u be machine roundoff and distround be max error for distance computation+ The max error for n_0 is sqrt(3) u M_a M_d / norm. n_1 is approx. 1 and n_2 is approx. 0+ The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm. Offset=0 at origin+ Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge+ Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d++ derivation of 4-d minnorm+ same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0+ [if two vertices fixed on x-axis, can rotate the other two in yzw.]+ n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3+ [all other terms contain at least two factors nearly zero.]+ The max error for n_0 is sqrt(4) u M_a M_d M_d / norm+ Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge+ Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d+*/+void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,+ boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {+ realT maxround, dist;+ int i;+ pointT *point;+++ if (dim == 2) {+ normal[0]= dY(1,0);+ normal[1]= dX(0,1);+ qh_normalize2(qh, normal, dim, toporient, NULL, NULL);+ *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);+ *nearzero= False; /* since nearzero norm => incident points */+ }else if (dim == 3) {+ normal[0]= det2_(dY(2,0), dZ(2,0),+ dY(1,0), dZ(1,0));+ normal[1]= det2_(dX(1,0), dZ(1,0),+ dX(2,0), dZ(2,0));+ normal[2]= det2_(dX(2,0), dY(2,0),+ dX(1,0), dY(1,0));+ qh_normalize2(qh, normal, dim, toporient, NULL, NULL);+ *offset= -(point0[0]*normal[0] + point0[1]*normal[1]+ + point0[2]*normal[2]);+ maxround= qh->DISTround;+ for (i=dim; i--; ) {+ point= rows[i];+ if (point != point0) {+ dist= *offset + (point[0]*normal[0] + point[1]*normal[1]+ + point[2]*normal[2]);+ if (dist > maxround || dist < -maxround) {+ *nearzero= True;+ break;+ }+ }+ }+ }else if (dim == 4) {+ normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),+ dY(1,0), dZ(1,0), dW(1,0),+ dY(3,0), dZ(3,0), dW(3,0));+ normal[1]= det3_(dX(2,0), dZ(2,0), dW(2,0),+ dX(1,0), dZ(1,0), dW(1,0),+ dX(3,0), dZ(3,0), dW(3,0));+ normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),+ dX(1,0), dY(1,0), dW(1,0),+ dX(3,0), dY(3,0), dW(3,0));+ normal[3]= det3_(dX(2,0), dY(2,0), dZ(2,0),+ dX(1,0), dY(1,0), dZ(1,0),+ dX(3,0), dY(3,0), dZ(3,0));+ qh_normalize2(qh, normal, dim, toporient, NULL, NULL);+ *offset= -(point0[0]*normal[0] + point0[1]*normal[1]+ + point0[2]*normal[2] + point0[3]*normal[3]);+ maxround= qh->DISTround;+ for (i=dim; i--; ) {+ point= rows[i];+ if (point != point0) {+ dist= *offset + (point[0]*normal[0] + point[1]*normal[1]+ + point[2]*normal[2] + point[3]*normal[3]);+ if (dist > maxround || dist < -maxround) {+ *nearzero= True;+ break;+ }+ }+ }+ }+ if (*nearzero) {+ zzinc_(Zminnorm);+ trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh->furthest_id));+ zzinc_(Znearlysingular);+ }+} /* sethyperplane_det */+++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="sethyperplane_gauss">-</a>++ qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )+ given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)+ set normalized hyperplane equation from oriented simplex++ returns:+ normal (normalized)+ offset (places point0 on the hyperplane)++ notes:+ if nearzero+ orientation may be incorrect because of incorrect sign flips in gausselim+ solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]+ or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]+ i.e., N is normal to the hyperplane, and the unnormalized+ distance to [0 .. 1] is either 1 or 0++ design:+ perform gaussian elimination+ flip sign for negative values+ perform back substitution+ normalize result+ compute offset+*/+void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,+ boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {+ coordT *pointcoord, *normalcoef;+ int k;+ boolT sign= toporient, nearzero2= False;++ qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);+ for (k=dim-1; k--; ) {+ if ((rows[k])[k] < 0)+ sign ^= 1;+ }+ if (*nearzero) {+ zzinc_(Znearlysingular);+ trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));+ qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);+ }else {+ qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);+ if (nearzero2) {+ zzinc_(Znearlysingular);+ trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));+ }+ }+ if (nearzero2)+ *nearzero= True;+ qh_normalize2(qh, normal, dim, True, NULL, NULL);+ pointcoord= point0;+ normalcoef= normal;+ *offset= -(*pointcoord++ * *normalcoef++);+ for (k=dim-1; k--; )+ *offset -= *pointcoord++ * *normalcoef++;+} /* sethyperplane_gauss */+++
+ Cdir/global_r.c view
@@ -0,0 +1,2100 @@++/*<html><pre> -<a href="qh-globa_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ global_r.c+ initializes all the globals of the qhull application++ see README++ see libqhull_r.h for qh.globals and function prototypes++ see qhull_ra.h for internal functions++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/global_r.c#16 $$Change: 2066 $+ $DateTime: 2016/01/18 19:29:17 $$Author: bbarber $+ */++#include "qhull_ra.h"++/*========= qh->definition -- globals defined in libqhull_r.h =======================*/++/*-<a href ="qh-globa_r.htm#TOC"+ >--------------------------------</a><a name="qh_version">-</a>++ qh_version+ version string by year and date+ qh_version2 for Unix users and -V++ the revision increases on code changes only++ notes:+ change date: Changes.txt, Announce.txt, index.htm, README.txt,+ qhull-news.html, Eudora signatures, CMakeLists.txt+ change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt+ check that CmakeLists @version is the same as qh_version2+ change year: Copying.txt+ check download size+ 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+*/++const char qh_version[]= "2015.2.r 2016/01/18";+const char qh_version2[]= "qhull_r 7.2.0 (2015.2.r 2016/01/18)";++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="appendprint">-</a>++ qh_appendprint(qh, printFormat )+ append printFormat to qh.PRINTout unless already defined+*/+void qh_appendprint(qhT *qh, 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_r.htm#TOC"+ >-------------------------------</a><a name="checkflags">-</a>++ qh_checkflags(qh, commandStr, hiddenFlags )+ errors if commandStr contains hiddenFlags+ hiddenFlags starts and ends with a space and is space delimited (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(qhT *qh, char *command, char *hiddenflags) {+ char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */+ char key, opt, prevopt;+ char chkkey[]= " ";+ char chkopt[]= " ";+ char chkopt2[]= " ";+ boolT waserr= False;++ if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {+ qh_fprintf(qh, qh->ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (strpbrk(hiddenflags, ",\n\r\t")) {+ qh_fprintf(qh, qh->ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);+ qh_errexit(qh, 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 == 'T' && (*s == 'I' || *s == 'O')) { /* TI or TO 'file name' */+ s= qh_skipfilename(qh, ++s);+ 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]= '\'';+ 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);+ waserr= True;+ }+ }+ if (waserr)+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+} /* checkflags */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="qh_clear_outputflags">-</a>++ qh_clear_outputflags(qh)+ Clear output flags for QhullPoints+*/+void qh_clear_outputflags(qhT *qh) {+ int i,k;++ qh->ANNOTATEoutput= False;+ qh->DOintersections= False;+ qh->DROPdim= -1;+ qh->FORCEoutput= False;+ qh->GETarea= False;+ qh->GOODpoint= 0;+ qh->GOODpointp= NULL;+ qh->GOODthreshold= False;+ qh->GOODvertex= 0;+ qh->GOODvertexp= NULL;+ qh->IStracing= 0;+ qh->KEEParea= False;+ qh->KEEPmerge= False;+ qh->KEEPminArea= REALmax;+ qh->PRINTcentrums= False;+ qh->PRINTcoplanar= False;+ qh->PRINTdots= False;+ qh->PRINTgood= False;+ qh->PRINTinner= False;+ qh->PRINTneighbors= False;+ qh->PRINTnoplanes= False;+ qh->PRINToptions1st= False;+ qh->PRINTouter= False;+ qh->PRINTprecision= True;+ qh->PRINTridges= False;+ qh->PRINTspheres= False;+ qh->PRINTstatistics= False;+ qh->PRINTsummary= False;+ qh->PRINTtransparent= False;+ qh->SPLITthresholds= False;+ qh->TRACElevel= 0;+ qh->TRInormals= False;+ qh->USEstdout= False;+ qh->VERIFYoutput= False;+ for (k=qh->input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */+ qh->lower_threshold[k]= -REALmax;+ qh->upper_threshold[k]= REALmax;+ qh->lower_bound[k]= -REALmax;+ qh->upper_bound[k]= REALmax;+ }++ for (i=0; i < qh_PRINTEND; i++) {+ qh->PRINTout[i]= qh_PRINTnone;+ }++ if (!qh->qhull_commandsiz2)+ qh->qhull_commandsiz2= (int)strlen(qh->qhull_command); /* WARN64 */+ else {+ qh->qhull_command[qh->qhull_commandsiz2]= '\0';+ }+ if (!qh->qhull_optionsiz2)+ qh->qhull_optionsiz2= (int)strlen(qh->qhull_options); /* WARN64 */+ else {+ qh->qhull_options[qh->qhull_optionsiz2]= '\0';+ qh->qhull_optionlen= qh_OPTIONline; /* start a new line */+ }+} /* clear_outputflags */++/*-<a href="qh-globa_r.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(qhT *qh) {++#if (qh_CLOCKtype == 2)+ struct tms time;+ static long clktck; /* initialized first call and never updated */+ double ratio, cpu;+ unsigned long ticks;++ if (!clktck) {+ if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {+ qh_fprintf(qh, qh->ferr, 6030, "qhull internal error (qh_clock): sysconf() failed. Use qh_CLOCKtype 1 in user.h\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ }+ if (times(&time) == -1) {+ qh_fprintf(qh, qh->ferr, 6031, "qhull internal error (qh_clock): times() failed. Use qh_CLOCKtype 1 in user.h\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ ratio= qh_SECticks / (double)clktck;+ ticks= time.tms_utime * ratio;+ return ticks;+#else+ qh_fprintf(qh, qh->ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* never returns */+ return 0;+#endif+} /* clock */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="freebuffers">-</a>++ qh_freebuffers()+ free up global memory buffers++ notes:+ must match qh_initbuffers()+*/+void qh_freebuffers(qhT *qh) {++ trace5((qh, qh->ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));+ /* allocated by qh_initqhull_buffers */+ qh_memfree(qh, qh->NEARzero, qh->hull_dim * sizeof(realT));+ qh_memfree(qh, qh->lower_threshold, (qh->input_dim+1) * sizeof(realT));+ qh_memfree(qh, qh->upper_threshold, (qh->input_dim+1) * sizeof(realT));+ qh_memfree(qh, qh->lower_bound, (qh->input_dim+1) * sizeof(realT));+ qh_memfree(qh, qh->upper_bound, (qh->input_dim+1) * sizeof(realT));+ qh_memfree(qh, qh->gm_matrix, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));+ qh_memfree(qh, 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, &qh->other_points);+ qh_setfree(qh, &qh->del_vertices);+ qh_setfree(qh, &qh->coplanarfacetset);+ if (qh->line) /* allocated by qh_readinput, freed if no error */+ qh_free(qh->line);+ if (qh->half_space)+ qh_free(qh->half_space);+ if (qh->temp_malloc)+ qh_free(qh->temp_malloc);+ if (qh->feasible_point) /* allocated by qh_readfeasible */+ qh_free(qh->feasible_point);+ if (qh->feasible_string) /* allocated by qh_initflags */+ qh_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) {+ qh_free(qh->first_point);+ qh->first_point= NULL;+ }+ if (qh->input_points && qh->input_malloc) { /* set by qh_joggleinput */+ qh_free(qh->input_points);+ qh->input_points= NULL;+ }+ trace5((qh, qh->ferr, 5002, "qh_freebuffers: finished\n"));+} /* freebuffers */+++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="freebuild">-</a>++ qh_freebuild(qh, allmem )+ free global memory used by qh_initbuild and qh_buildhull+ if !allmem,+ does not free short memory (e.g., facetT, 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(qhT *qh, boolT allmem) {+ facetT *facet;+ vertexT *vertex;+ ridgeT *ridge, **ridgep;+ mergeT *merge, **mergep;++ trace1((qh, qh->ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));+ if (qh->del_vertices)+ qh_settruncate(qh, qh->del_vertices, 0);+ if (allmem) {+ while ((vertex= qh->vertex_list)) {+ if (vertex->next)+ qh_delvertex(qh, vertex);+ else {+ qh_memfree(qh, vertex, (int)sizeof(vertexT));+ qh->newvertex_list= qh->vertex_list= NULL;+ }+ }+ }else if (qh->VERTEXneighbors) {+ FORALLvertices+ qh_setfreelong(qh, &(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(qh, &(ridge->vertices));+ qh_memfree(qh, ridge, (int)sizeof(ridgeT));+ }else+ ridge->seen= True;+ }+ qh_setfree(qh, &(facet->outsideset));+ qh_setfree(qh, &(facet->coplanarset));+ qh_setfree(qh, &(facet->neighbors));+ qh_setfree(qh, &(facet->ridges));+ qh_setfree(qh, &(facet->vertices));+ if (facet->next)+ qh_delfacet(qh, facet);+ else {+ qh_memfree(qh, facet, (int)sizeof(facetT));+ qh->visible_list= qh->newfacet_list= qh->facet_list= NULL;+ }+ }+ }else {+ FORALLfacets {+ qh_setfreelong(qh, &(facet->outsideset));+ qh_setfreelong(qh, &(facet->coplanarset));+ if (!facet->simplicial) {+ qh_setfreelong(qh, &(facet->neighbors));+ qh_setfreelong(qh, &(facet->ridges));+ qh_setfreelong(qh, &(facet->vertices));+ }+ }+ }+ qh_setfree(qh, &(qh->hash_table));+ qh_memfree(qh, qh->interior_point, qh->normal_size);+ qh->interior_point= NULL;+ FOREACHmerge_(qh->facet_mergeset) /* usually empty */+ qh_memfree(qh, merge, (int)sizeof(mergeT));+ qh->facet_mergeset= NULL; /* temp set */+ qh->degen_mergeset= NULL; /* temp set */+ qh_settempfree_all(qh);+} /* freebuild */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="freeqhull">-</a>++ qh_freeqhull(qh, allmem )++ free global memory and set qhT to 0+ if !allmem,+ does not free short memory (freed by qh_memfreeshort unless qh_NOmem)++notes:+ sets qh.NOerrexit in case caller forgets to+ Does not throw errors++see:+ see qh_initqhull_start2()+ For libqhull_r, qhstatT is part of qhT++design:+ free global and temporary memory from qh_initbuild and qh_buildhull+ free buffers+*/+void qh_freeqhull(qhT *qh, boolT allmem) {++ qh->NOerrexit= True; /* no more setjmp since called at exit and ~QhullQh */+ trace1((qh, qh->ferr, 1006, "qh_freeqhull: free global memory\n"));+ qh_freebuild(qh, allmem);+ qh_freebuffers(qh);+ /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */+ memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT));+ qh->NOerrexit= True;+} /* freeqhull2 */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="init_A">-</a>++ qh_init_A(qh, 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(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {+ qh_meminit(qh, errfile);+ qh_initqhull_start(qh, infile, outfile, errfile);+ qh_init_qhull_command(qh, argc, argv);+} /* init_A */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="init_B">-</a>++ qh_init_B(qh, 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 qh_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(qh)++ 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(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {+ qh_initqhull_globals(qh, points, numpoints, dim, ismalloc);+ if (qh->qhmem.LASTsize == 0)+ qh_initqhull_mem(qh);+ /* mem_r.c and qset_r.c are initialized */+ qh_initqhull_buffers(qh);+ qh_initthresholds(qh, qh->qhull_command);+ if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay))+ qh_projectinput(qh);+ if (qh->SCALEinput)+ qh_scaleinput(qh);+ if (qh->ROTATErandom >= 0) {+ qh_randommatrix(qh, 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, qh->hull_dim, qh->gm_row);+ qh_rotateinput(qh, qh->gm_row);+ }+} /* init_B */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="init_qhull_command">-</a>++ qh_init_qhull_command(qh, argc, argv )+ build qh.qhull_command from argc/argv+ Calls qh_exit if qhull_command is too short++ returns:+ a space-delimited 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(qhT *qh, int argc, char *argv[]) {++ if (!qh_argv_to_command(argc, argv, qh->qhull_command, (int)sizeof(qh->qhull_command))){+ /* Assumes qh.ferr is defined. */+ qh_fprintf(qh, qh->ferr, 6033, "qhull input error: more than %d characters in command line.\n",+ (int)sizeof(qh->qhull_command));+ qh_exit(qh_ERRinput); /* error reported, can not use qh_errexit */+ }+} /* init_qhull_command */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initflags">-</a>++ qh_initflags(qh, commandStr )+ set flags and initialized constants from commandStr+ calls qh_exit() if qh->NOerrexit++ 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_r.c for documentation++ design:+ for each space-delimited option group+ if top-level option+ check syntax+ append appropriate option to option string+ set appropriate global variable or append printFormat to print options+ else+ for each sub-option+ check syntax+ append appropriate option to option string+ set appropriate global variable or append printFormat to print options+*/+void qh_initflags(qhT *qh, char *command) {+ int k, i, lastproject;+ char *s= command, *t, *prev_s, *start, key;+ boolT isgeom= False, wasproject;+ realT r;++ if(qh->NOerrexit){+ 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.");+ qh_exit(6245);+ }+ if (command <= &qh->qhull_command[0] || command > &qh->qhull_command[0] + sizeof(qh->qhull_command)) {+ if (command != &qh->qhull_command[0]) {+ *qh->qhull_command= '\0';+ strncat(qh->qhull_command, command, sizeof(qh->qhull_command)-strlen(qh->qhull_command)-1);+ }+ 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(qh, "delaunay", NULL, NULL);+ qh->DELAUNAY= True;+ break;+ case 'f':+ qh_option(qh, "facets", NULL, NULL);+ qh_appendprint(qh, qh_PRINTfacets);+ break;+ case 'i':+ qh_option(qh, "incidence", NULL, NULL);+ qh_appendprint(qh, qh_PRINTincidences);+ break;+ case 'm':+ qh_option(qh, "mathematica", NULL, NULL);+ qh_appendprint(qh, qh_PRINTmathematica);+ break;+ case 'n':+ qh_option(qh, "normals", NULL, NULL);+ qh_appendprint(qh, qh_PRINTnormals);+ break;+ case 'o':+ qh_option(qh, "offFile", NULL, NULL);+ qh_appendprint(qh, qh_PRINToff);+ break;+ case 'p':+ qh_option(qh, "points", NULL, NULL);+ qh_appendprint(qh, qh_PRINTpoints);+ break;+ case 's':+ qh_option(qh, "summary", NULL, NULL);+ qh->PRINTsummary= True;+ break;+ case 'v':+ qh_option(qh, "voronoi", NULL, NULL);+ qh->VORONOI= True;+ qh->DELAUNAY= True;+ break;+ case 'A':+ if (!isdigit(*s) && *s != '.' && *s != '-')+ qh_fprintf(qh, qh->ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'. Ignored.\n");+ else {+ if (*s == '-') {+ qh->premerge_cos= -qh_strtod(s, &s);+ qh_option(qh, "Angle-premerge-", NULL, &qh->premerge_cos);+ qh->PREmerge= True;+ }else {+ qh->postmerge_cos= qh_strtod(s, &s);+ qh_option(qh, "Angle-postmerge", NULL, &qh->postmerge_cos);+ qh->POSTmerge= True;+ }+ qh->MERGING= True;+ }+ break;+ case 'C':+ if (!isdigit(*s) && *s != '.' && *s != '-')+ qh_fprintf(qh, qh->ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'. Ignored.\n");+ else {+ if (*s == '-') {+ qh->premerge_centrum= -qh_strtod(s, &s);+ qh_option(qh, "Centrum-premerge-", NULL, &qh->premerge_centrum);+ qh->PREmerge= True;+ }else {+ qh->postmerge_centrum= qh_strtod(s, &s);+ qh_option(qh, "Centrum-postmerge", NULL, &qh->postmerge_centrum);+ qh->POSTmerge= True;+ }+ qh->MERGING= True;+ }+ break;+ case 'E':+ if (*s == '-')+ qh_fprintf(qh, qh->ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'. Ignored.\n");+ else if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'. Ignored.\n");+ else {+ qh->DISTround= qh_strtod(s, &s);+ qh_option(qh, "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+ qh_fprintf(qh, qh->ferr, 7006, "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((size_t)(t-start+1), (size_t)1))) {+ qh_fprintf(qh, qh->ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ strncpy(qh->feasible_string, start, (size_t)(t-start));+ qh_option(qh, "Halfspace-about", NULL, NULL);+ qh_option(qh, qh->feasible_string, NULL, NULL);+ }else+ qh_option(qh, "Halfspace", NULL, NULL);+ break;+ case 'R':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'. Ignored\n");+ else {+ qh->RANDOMfactor= qh_strtod(s, &s);+ qh_option(qh, "Random_perturb", NULL, &qh->RANDOMfactor);+ qh->RANDOMdist= True;+ }+ break;+ case 'V':+ if (!isdigit(*s) && *s != '-')+ qh_fprintf(qh, qh->ferr, 7008, "qhull warning: missing visible distance for option 'Vn'. Ignored\n");+ else {+ qh->MINvisible= qh_strtod(s, &s);+ qh_option(qh, "Visible", NULL, &qh->MINvisible);+ }+ break;+ case 'U':+ if (!isdigit(*s) && *s != '-')+ qh_fprintf(qh, qh->ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'. Ignored\n");+ else {+ qh->MAXcoplanar= qh_strtod(s, &s);+ qh_option(qh, "U-coplanar", NULL, &qh->MAXcoplanar);+ }+ break;+ case 'W':+ if (*s == '-')+ qh_fprintf(qh, qh->ferr, 7010, "qhull warning: negative outside width for option 'Wn'. Ignored.\n");+ else if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7011, "qhull warning: missing outside width for option 'Wn'. Ignored\n");+ else {+ qh->MINoutside= qh_strtod(s, &s);+ qh_option(qh, "W-outside", NULL, &qh->MINoutside);+ qh->APPROXhull= True;+ }+ break;+ /************ sub menus ***************/+ case 'F':+ while (*s && !isspace(*s)) {+ switch (*s++) {+ case 'a':+ qh_option(qh, "Farea", NULL, NULL);+ qh_appendprint(qh, qh_PRINTarea);+ qh->GETarea= True;+ break;+ case 'A':+ qh_option(qh, "FArea-total", NULL, NULL);+ qh->GETarea= True;+ break;+ case 'c':+ qh_option(qh, "Fcoplanars", NULL, NULL);+ qh_appendprint(qh, qh_PRINTcoplanars);+ break;+ case 'C':+ qh_option(qh, "FCentrums", NULL, NULL);+ qh_appendprint(qh, qh_PRINTcentrums);+ break;+ case 'd':+ qh_option(qh, "Fd-cdd-in", NULL, NULL);+ qh->CDDinput= True;+ break;+ case 'D':+ qh_option(qh, "FD-cdd-out", NULL, NULL);+ qh->CDDoutput= True;+ break;+ case 'F':+ qh_option(qh, "FFacets-xridge", NULL, NULL);+ qh_appendprint(qh, qh_PRINTfacets_xridge);+ break;+ case 'i':+ qh_option(qh, "Finner", NULL, NULL);+ qh_appendprint(qh, qh_PRINTinner);+ break;+ case 'I':+ qh_option(qh, "FIDs", NULL, NULL);+ qh_appendprint(qh, qh_PRINTids);+ break;+ case 'm':+ qh_option(qh, "Fmerges", NULL, NULL);+ qh_appendprint(qh, qh_PRINTmerges);+ break;+ case 'M':+ qh_option(qh, "FMaple", NULL, NULL);+ qh_appendprint(qh, qh_PRINTmaple);+ break;+ case 'n':+ qh_option(qh, "Fneighbors", NULL, NULL);+ qh_appendprint(qh, qh_PRINTneighbors);+ break;+ case 'N':+ qh_option(qh, "FNeighbors-vertex", NULL, NULL);+ qh_appendprint(qh, qh_PRINTvneighbors);+ break;+ case 'o':+ qh_option(qh, "Fouter", NULL, NULL);+ qh_appendprint(qh, qh_PRINTouter);+ break;+ case 'O':+ if (qh->PRINToptions1st) {+ qh_option(qh, "FOptions", NULL, NULL);+ qh_appendprint(qh, qh_PRINToptions);+ }else+ qh->PRINToptions1st= True;+ break;+ case 'p':+ qh_option(qh, "Fpoint-intersect", NULL, NULL);+ qh_appendprint(qh, qh_PRINTpointintersect);+ break;+ case 'P':+ qh_option(qh, "FPoint-nearest", NULL, NULL);+ qh_appendprint(qh, qh_PRINTpointnearest);+ break;+ case 'Q':+ qh_option(qh, "FQhull", NULL, NULL);+ qh_appendprint(qh, qh_PRINTqhull);+ break;+ case 's':+ qh_option(qh, "Fsummary", NULL, NULL);+ qh_appendprint(qh, qh_PRINTsummary);+ break;+ case 'S':+ qh_option(qh, "FSize", NULL, NULL);+ qh_appendprint(qh, qh_PRINTsize);+ qh->GETarea= True;+ break;+ case 't':+ qh_option(qh, "Ftriangles", NULL, NULL);+ qh_appendprint(qh, qh_PRINTtriangles);+ break;+ case 'v':+ /* option set in qh_initqhull_globals */+ qh_appendprint(qh, qh_PRINTvertices);+ break;+ case 'V':+ qh_option(qh, "FVertex-average", NULL, NULL);+ qh_appendprint(qh, qh_PRINTaverage);+ break;+ case 'x':+ qh_option(qh, "Fxtremes", NULL, NULL);+ qh_appendprint(qh, qh_PRINTextremes);+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7012, "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, qh_PRINTgeom);+ while (*s && !isspace(*s)) {+ switch (*s++) {+ case 'a':+ qh_option(qh, "Gall-points", NULL, NULL);+ qh->PRINTdots= True;+ break;+ case 'c':+ qh_option(qh, "Gcentrums", NULL, NULL);+ qh->PRINTcentrums= True;+ break;+ case 'h':+ qh_option(qh, "Gintersections", NULL, NULL);+ qh->DOintersections= True;+ break;+ case 'i':+ qh_option(qh, "Ginner", NULL, NULL);+ qh->PRINTinner= True;+ break;+ case 'n':+ qh_option(qh, "Gno-planes", NULL, NULL);+ qh->PRINTnoplanes= True;+ break;+ case 'o':+ qh_option(qh, "Gouter", NULL, NULL);+ qh->PRINTouter= True;+ break;+ case 'p':+ qh_option(qh, "Gpoints", NULL, NULL);+ qh->PRINTcoplanar= True;+ break;+ case 'r':+ qh_option(qh, "Gridges", NULL, NULL);+ qh->PRINTridges= True;+ break;+ case 't':+ qh_option(qh, "Gtransparent", NULL, NULL);+ qh->PRINTtransparent= True;+ break;+ case 'v':+ qh_option(qh, "Gvertices", NULL, NULL);+ qh->PRINTspheres= True;+ break;+ case 'D':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n");+ else {+ if (qh->DROPdim >= 0)+ qh_fprintf(qh, qh->ferr, 7013, "qhull warning: can only drop one dimension. Previous 'GD%d' ignored\n",+ qh->DROPdim);+ qh->DROPdim= qh_strtol(s, &s);+ qh_option(qh, "GDrop-dim", &qh->DROPdim, NULL);+ }+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7014, "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(qh, "Pdrop-facets-dim-less", &i, &r);+ else+ qh_option(qh, "PDrop-facets-dim-more", &i, &r);+ break;+ case 'g':+ qh_option(qh, "Pgood-facets", NULL, NULL);+ qh->PRINTgood= True;+ break;+ case 'G':+ qh_option(qh, "PGood-facet-neighbors", NULL, NULL);+ qh->PRINTneighbors= True;+ break;+ case 'o':+ qh_option(qh, "Poutput-forced", NULL, NULL);+ qh->FORCEoutput= True;+ break;+ case 'p':+ qh_option(qh, "Pprecision-ignore", NULL, NULL);+ qh->PRINTprecision= False;+ break;+ case 'A':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n");+ else {+ qh->KEEParea= qh_strtol(s, &s);+ qh_option(qh, "PArea-keep", &qh->KEEParea, NULL);+ qh->GETarea= True;+ }+ break;+ case 'F':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n");+ else {+ qh->KEEPminArea= qh_strtod(s, &s);+ qh_option(qh, "PFacet-area-keep", NULL, &qh->KEEPminArea);+ qh->GETarea= True;+ }+ break;+ case 'M':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n");+ else {+ qh->KEEPmerge= qh_strtol(s, &s);+ qh_option(qh, "PMerge-keep", &qh->KEEPmerge, NULL);+ }+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7015, "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(qh, "QbBound-unit-box", NULL, &r);+ break;+ }+ if (key == 'b' && *s == 'b') {+ s++;+ qh->SCALElast= True;+ qh_option(qh, "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, qh->ferr, 2004, "qh_initflags: project dimension %d\n", k));+ qh_option(qh, "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(qh, "Qbound-dim-low", &k, &r);+ }else {+ qh->SCALEinput= True;+ if (r == 0.0)+ r= qh_DEFAULTbox;+ qh_option(qh, "QBound-dim-high", &k, &r);+ }+ }+ break;+ case 'c':+ qh_option(qh, "Qcoplanar-keep", NULL, NULL);+ qh->KEEPcoplanar= True;+ break;+ case 'f':+ qh_option(qh, "Qfurthest-outside", NULL, NULL);+ qh->BESToutside= True;+ break;+ case 'g':+ qh_option(qh, "Qgood-facets-only", NULL, NULL);+ qh->ONLYgood= True;+ break;+ case 'i':+ qh_option(qh, "Qinterior-keep", NULL, NULL);+ qh->KEEPinside= True;+ break;+ case 'm':+ qh_option(qh, "Qmax-outside-only", NULL, NULL);+ qh->ONLYmax= True;+ break;+ case 'r':+ qh_option(qh, "Qrandom-outside", NULL, NULL);+ qh->RANDOMoutside= True;+ break;+ case 's':+ qh_option(qh, "Qsearch-initial-simplex", NULL, NULL);+ qh->ALLpoints= True;+ break;+ case 't':+ qh_option(qh, "Qtriangulate", NULL, NULL);+ qh->TRIangulate= True;+ break;+ case 'T':+ qh_option(qh, "QTestPoints", NULL, NULL);+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n");+ else {+ qh->TESTpoints= qh_strtol(s, &s);+ qh_option(qh, "QTestPoints", &qh->TESTpoints, NULL);+ }+ break;+ case 'u':+ qh_option(qh, "QupperDelaunay", NULL, NULL);+ qh->UPPERdelaunay= True;+ break;+ case 'v':+ qh_option(qh, "Qvertex-neighbors-convex", NULL, NULL);+ qh->TESTvneighbors= True;+ break;+ case 'x':+ qh_option(qh, "Qxact-merge", NULL, NULL);+ qh->MERGEexact= True;+ break;+ case 'z':+ qh_option(qh, "Qz-infinity-point", NULL, NULL);+ qh->ATinfinity= True;+ break;+ case '0':+ qh_option(qh, "Q0-no-premerge", NULL, NULL);+ qh->NOpremerge= True;+ break;+ case '1':+ if (!isdigit(*s)) {+ qh_option(qh, "Q1-no-angle-sort", NULL, NULL);+ qh->ANGLEmerge= False;+ break;+ }+ switch (*s++) {+ case '0':+ qh_option(qh, "Q10-no-narrow", NULL, NULL);+ qh->NOnarrow= True;+ break;+ case '1':+ qh_option(qh, "Q11-trinormals Qtriangulate", NULL, NULL);+ qh->TRInormals= True;+ qh->TRIangulate= True;+ break;+ case '2':+ qh_option(qh, "Q12-no-wide-dup", NULL, NULL);+ qh->NOwide= True;+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);+ while (*++s && !isspace(*s));+ break;+ }+ break;+ case '2':+ qh_option(qh, "Q2-no-merge-independent", NULL, NULL);+ qh->MERGEindependent= False;+ goto LABELcheckdigit;+ break; /* no warnings */+ case '3':+ qh_option(qh, "Q3-no-merge-vertices", NULL, NULL);+ qh->MERGEvertices= False;+ LABELcheckdigit:+ if (isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit. '%c' skipped.\n",+ *s++);+ break;+ case '4':+ qh_option(qh, "Q4-avoid-old-into-new", NULL, NULL);+ qh->AVOIDold= True;+ break;+ case '5':+ qh_option(qh, "Q5-no-check-outer", NULL, NULL);+ qh->SKIPcheckmax= True;+ break;+ case '6':+ qh_option(qh, "Q6-no-concave-merge", NULL, NULL);+ qh->SKIPconvex= True;+ break;+ case '7':+ qh_option(qh, "Q7-no-breadth-first", NULL, NULL);+ qh->VIRTUALmemory= True;+ break;+ case '8':+ qh_option(qh, "Q8-no-near-inside", NULL, NULL);+ qh->NOnearinside= True;+ break;+ case '9':+ qh_option(qh, "Q9-pick-furthest", NULL, NULL);+ qh->PICKfurthest= True;+ break;+ case 'G':+ i= qh_strtol(s, &t);+ if (qh->GOODpoint)+ qh_fprintf(qh, qh->ferr, 7018, "qhull warning: good point already defined for option 'QGn'. Ignored\n");+ else if (s == t)+ qh_fprintf(qh, qh->ferr, 7019, "qhull warning: missing good point id for option 'QGn'. Ignored\n");+ else if (i < 0 || *s == '-') {+ qh->GOODpoint= i-1;+ qh_option(qh, "QGood-if-dont-see-point", &i, NULL);+ }else {+ qh->GOODpoint= i+1;+ qh_option(qh, "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(qh, "QJoggle", NULL, &qh->JOGGLEmax);+ }+ break;+ case 'R':+ if (!isdigit(*s) && *s != '-')+ qh_fprintf(qh, qh->ferr, 7020, "qhull warning: missing random seed for option 'QRn'. Ignored\n");+ else {+ qh->ROTATErandom= i= qh_strtol(s, &s);+ if (i > 0)+ qh_option(qh, "QRotate-id", &i, NULL );+ else if (i < -1)+ qh_option(qh, "QRandom-seed", &i, NULL );+ }+ break;+ case 'V':+ i= qh_strtol(s, &t);+ if (qh->GOODvertex)+ qh_fprintf(qh, qh->ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'. Ignored\n");+ else if (s == t)+ qh_fprintf(qh, qh->ferr, 7022, "qhull warning: no good point id given for option 'QVn'. Ignored\n");+ else if (i < 0) {+ qh->GOODvertex= i - 1;+ qh_option(qh, "QV-good-facets-not-point", &i, NULL);+ }else {+ qh_option(qh, "QV-good-facets-point", &i, NULL);+ qh->GOODvertex= i + 1;+ }+ s= t;+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7023, "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 'a':+ qh_option(qh, "Tannotate-output", NULL, NULL);+ qh->ANNOTATEoutput= True;+ break;+ case 'c':+ qh_option(qh, "Tcheck-frequently", NULL, NULL);+ qh->CHECKfrequently= True;+ break;+ case 's':+ qh_option(qh, "Tstatistics", NULL, NULL);+ qh->PRINTstatistics= True;+ break;+ case 'v':+ qh_option(qh, "Tverify", NULL, NULL);+ qh->VERIFYoutput= True;+ break;+ case 'z':+ if (qh->ferr == qh_FILEstderr) {+ /* The C++ interface captures the output in qh_fprint_qhull() */+ qh_option(qh, "Tz-stdout", NULL, NULL);+ qh->USEstdout= True;+ }else if (!qh->fout)+ qh_fprintf(qh, qh->ferr, 7024, "qhull warning: output file undefined(stdout). Option 'Tz' ignored.\n");+ else {+ qh_option(qh, "Tz-stdout", NULL, NULL);+ qh->USEstdout= True;+ qh->ferr= qh->fout;+ qh->qhmem.ferr= qh->fout;+ }+ break;+ case 'C':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'. Ignored\n");+ else {+ i= qh_strtol(s, &s);+ qh_option(qh, "TCone-stop", &i, NULL);+ qh->STOPcone= i + 1;+ }+ break;+ case 'F':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'. Ignored\n");+ else {+ qh->REPORTfreq= qh_strtol(s, &s);+ qh_option(qh, "TFacet-log", &qh->REPORTfreq, NULL);+ qh->REPORTfreq2= qh->REPORTfreq/2; /* for tracemerging() */+ }+ break;+ case 'I':+ if (!isspace(*s))+ qh_fprintf(qh, qh->ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s);+ while (isspace(*s))+ s++;+ t= qh_skipfilename(qh, s);+ {+ char filename[qh_FILENAMElen];++ qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */+ s= t;+ if (!freopen(filename, "r", stdin)) {+ qh_fprintf(qh, qh->ferr, 6041, "qhull error: could not open file \"%s\".", filename);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }else {+ qh_option(qh, "TInput-file", NULL, NULL);+ qh_option(qh, filename, NULL, NULL);+ }+ }+ break;+ case 'O':+ if (!isspace(*s))+ qh_fprintf(qh, qh->ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s);+ while (isspace(*s))+ s++;+ t= qh_skipfilename(qh, s);+ {+ char filename[qh_FILENAMElen];++ qh_copyfilename(qh, filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */+ s= t;+ if (!qh->fout) {+ 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");+ }else if (!freopen(filename, "w", qh->fout)) {+ qh_fprintf(qh, qh->ferr, 6044, "qhull error: could not open file \"%s\".", filename);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }else {+ qh_option(qh, "TOutput-file", NULL, NULL);+ qh_option(qh, filename, NULL, NULL);+ }+ }+ break;+ case 'P':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7029, "qhull warning: missing point id for trace option 'TPn'. Ignored\n");+ else {+ qh->TRACEpoint= qh_strtol(s, &s);+ qh_option(qh, "Trace-point", &qh->TRACEpoint, NULL);+ }+ break;+ case 'M':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'. Ignored\n");+ else {+ qh->TRACEmerge= qh_strtol(s, &s);+ qh_option(qh, "Trace-merge", &qh->TRACEmerge, NULL);+ }+ break;+ case 'R':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'. Ignored\n");+ else {+ qh->RERUN= qh_strtol(s, &s);+ qh_option(qh, "TRerun", &qh->RERUN, NULL);+ }+ break;+ case 'V':+ i= qh_strtol(s, &t);+ if (s == t)+ qh_fprintf(qh, qh->ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'. Ignored\n");+ else if (i < 0) {+ qh->STOPpoint= i - 1;+ qh_option(qh, "TV-stop-before-point", &i, NULL);+ }else {+ qh->STOPpoint= i + 1;+ qh_option(qh, "TV-stop-after-point", &i, NULL);+ }+ s= t;+ break;+ case 'W':+ if (!isdigit(*s))+ qh_fprintf(qh, qh->ferr, 7033, "qhull warning: missing max width for trace option 'TWn'. Ignored\n");+ else {+ qh->TRACEdist= (realT) qh_strtod(s, &s);+ qh_option(qh, "TWide-trace", NULL, &qh->TRACEdist);+ }+ break;+ default:+ s--;+ qh_fprintf(qh, qh->ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);+ while (*++s && !isspace(*s));+ break;+ }+ }+ break;+ default:+ qh_fprintf(qh, qh->ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1],+ (int)s[-1]);+ break;+ }+ if (s-1 == prev_s && *s && !isspace(*s)) {+ qh_fprintf(qh, qh->ferr, 7036, "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 (qh->STOPcone && qh->JOGGLEmax < REALmax/2)+ qh_fprintf(qh, qh->ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");+ if (isgeom && !qh->FORCEoutput && qh->PRINTout[1])+ qh_fprintf(qh, qh->ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n");+ /* set derived values in qh_initqhull_globals */+} /* initflags */+++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_buffers">-</a>++ qh_initqhull_buffers(qh)+ initialize global memory buffers++ notes:+ must match qh_freebuffers()+*/+void qh_initqhull_buffers(qhT *qh) {+ int k;++ qh->TEMPsize= (qh->qhmem.LASTsize - sizeof(setT))/SETelemsize;+ if (qh->TEMPsize <= 0 || qh->TEMPsize > qh->qhmem.LASTsize)+ qh->TEMPsize= 8; /* e.g., if qh_NOmem */+ qh->other_points= qh_setnew(qh, qh->TEMPsize);+ qh->del_vertices= qh_setnew(qh, qh->TEMPsize);+ qh->coplanarfacetset= qh_setnew(qh, qh->TEMPsize);+ qh->NEARzero= (realT *)qh_memalloc(qh, qh->hull_dim * sizeof(realT));+ qh->lower_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));+ qh->upper_threshold= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));+ qh->lower_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));+ qh->upper_bound= (realT *)qh_memalloc(qh, (qh->input_dim+1) * sizeof(realT));+ for (k=qh->input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */+ 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, (qh->hull_dim+1) * qh->hull_dim * sizeof(coordT));+ qh->gm_row= (coordT **)qh_memalloc(qh, (qh->hull_dim+1) * sizeof(coordT *));+} /* initqhull_buffers */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_globals">-</a>++ qh_initqhull_globals(qh, 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)+ initialize qh.CENTERtype, qh.normal_size,+ qh.center_size, qh.TRACEpoint/level,+ initialize and test random numbers+ qh_initqhull_outputflags() -- adjust and test output flags+*/+void qh_initqhull_globals(qhT *qh, coordT *points, int numpoints, int dim, boolT ismalloc) {+ int seed, pointsneeded, extra= 0, i, randi, k;+ realT randr;+ realT factorial;++ time_t timedata;++ trace0((qh, qh->ferr, 13, "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(qh, "_pre-merge", NULL, NULL);+ }else {+ qh->MERGEexact= True;+ qh_option(qh, "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)+ qh_fprintf(qh, qh->ferr, 7038, "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(qh, "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(qh, "_zero-centrum", NULL, NULL);+ }+ if (qh->JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh->PRINTprecision)+ 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",+ REALepsilon);+#ifdef qh_NOmerge+ if (qh->MERGING) {+ qh_fprintf(qh, qh->ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+#endif+ if (qh->DELAUNAY && qh->KEEPcoplanar && !qh->KEEPinside) {+ qh->KEEPinside= True;+ qh_option(qh, "Qinterior-keep", NULL, NULL);+ }+ if (qh->DELAUNAY && qh->HALFspace) {+ qh_fprintf(qh, qh->ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (!qh->DELAUNAY && (qh->UPPERdelaunay || qh->ATinfinity)) {+ qh_fprintf(qh, qh->ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->UPPERdelaunay && qh->ATinfinity) {+ qh_fprintf(qh, qh->ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->SCALElast && !qh->DELAUNAY && qh->PRINTprecision)+ qh_fprintf(qh, qh->ferr, 7040, "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) {+ qh_fprintf(qh, qh->ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n");+ qh_errexit(qh, qh_ERRinput, NULL ,NULL);+ }+ if (qh->PROJECTinput || (qh->DELAUNAY && qh->PROJECTdelaunay)) {+ qh->hull_dim -= qh->PROJECTinput;+ if (qh->DELAUNAY) {+ qh->hull_dim++;+ if (qh->ATinfinity)+ extra= 1;+ }+ }+ if (qh->hull_dim <= 1) {+ qh_fprintf(qh, qh->ferr, 6050, "qhull error: dimension %d must be > 1\n", qh->hull_dim);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ for (k=2, factorial=1.0; k < qh->hull_dim; k++)+ factorial *= k;+ qh->AREAfactor= 1.0 / factorial;+ trace2((qh, qh->ferr, 2005, "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(qh, "Q3-no-merge-vertices-dim-high", NULL, NULL);+ }+ if (qh->GOODpoint)+ pointsneeded++;+#ifdef qh_NOtrace+ if (qh->IStracing) {+ qh_fprintf(qh, qh->ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)");+ qh_errexit(qh, 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 != qh_IDunknown || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {+ qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);+ qh->IStracing= 0;+ }+ if (qh->ROTATErandom == 0 || qh->ROTATErandom == -1) {+ seed= (int)time(&timedata);+ if (qh->ROTATErandom == -1) {+ seed= -seed;+ qh_option(qh, "QRandom-seed", &seed, NULL );+ }else+ qh_option(qh, "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_(qh, seed);+ randr= 0.0;+ for (i=1000; i--; ) {+ randi= qh_RANDOMint;+ randr += randi;+ if (randi > qh_RANDOMmax) {+ qh_fprintf(qh, qh->ferr, 8036, "\+qhull configuration error (qh_RANDOMmax in user.h):\n\+ random integer %d > qh_RANDOMmax(qh, %.8g)\n",+ randi, qh_RANDOMmax);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ }+ qh_RANDOMseed_(qh, seed);+ randr = randr/1000;+ if (randr < qh_RANDOMmax * 0.1+ || randr > qh_RANDOMmax * 0.9)+ qh_fprintf(qh, qh->ferr, 8037, "\+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 * 0.5, qh_RANDOMmax);+ qh->RANDOMa= 2.0 * qh->RANDOMfactor/qh_RANDOMmax;+ qh->RANDOMb= 1.0 - qh->RANDOMfactor;+ if (qh_HASHfactor < 1.1) {+ 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",+ qh_HASHfactor);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ if (numpoints+extra < pointsneeded) {+ qh_fprintf(qh, qh->ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",+ numpoints, pointsneeded);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ qh_initqhull_outputflags(qh);+} /* initqhull_globals */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_mem">-</a>++ qh_initqhull_mem(qh, )+ initialize mem_r.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(qh) to add up to 10 additional sizes for quick allocation+ (see numsizes below)++ returns:+ mem_r.c already for qh_memalloc/qh_memfree (errors if called beforehand)++ notes:+ qh_produceoutput() prints memsizes++*/+void qh_initqhull_mem(qhT *qh) {+ int numsizes;+ int i;++ numsizes= 8+10;+ qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, numsizes,+ qh_MEMbufsize, qh_MEMinitbuf);+ qh_memsize(qh, (int)sizeof(vertexT));+ if (qh->MERGING) {+ qh_memsize(qh, (int)sizeof(ridgeT));+ qh_memsize(qh, (int)sizeof(mergeT));+ }+ qh_memsize(qh, (int)sizeof(facetT));+ i= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize; /* ridge.vertices */+ qh_memsize(qh, i);+ qh_memsize(qh, qh->normal_size); /* normal */+ i += SETelemsize; /* facet.vertices, .ridges, .neighbors */+ qh_memsize(qh, i);+ qh_user_memsizes(qh);+ qh_memsetup(qh);+} /* initqhull_mem */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_outputflags">-</a>++ qh_initqhull_outputflags+ initialize flags concerned with output++ returns:+ adjust user flags as needed++ see:+ qh_clear_outputflags() resets the flags++ design:+ test for qh.PRINTgood (i.e., only print 'good' facets)+ check for conflicting print output options+*/+void qh_initqhull_outputflags(qhT *qh) {+ boolT printgeom= False, printmath= False, printcoplanar= False;+ int i;++ trace3((qh, qh->ferr, 3024, "qh_initqhull_outputflags: %s\n", qh->qhull_command));+ 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(qh, "Pgood", NULL, NULL);+ }+ }+ if (qh->PRINTtransparent) {+ if (qh->hull_dim != 4 || !qh->DELAUNAY || qh->VORONOI || qh->DROPdim >= 0) {+ qh_fprintf(qh, qh->ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");+ qh_errexit(qh, 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 || qh->PRINTout[i] == qh_PRINTmaple)+ 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) {+ qh_fprintf(qh, qh->ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }else if (qh->PRINTout[i] == qh_PRINTtriangles && (qh->HALFspace || qh->VORONOI)) {+ qh_fprintf(qh, qh->ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }else if (qh->PRINTout[i] == qh_PRINTcentrums && qh->VORONOI) {+ qh_fprintf(qh, qh->ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }else if (qh->PRINTout[i] == qh_PRINTvertices) {+ if (qh->VORONOI)+ qh_option(qh, "Fvoronoi", NULL, NULL);+ else+ qh_option(qh, "Fvertices", NULL, NULL);+ }+ }+ if (printcoplanar && qh->DELAUNAY && qh->JOGGLEmax < REALmax/2) {+ if (qh->PRINTprecision)+ qh_fprintf(qh, qh->ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");+ }+ if (printmath && (qh->hull_dim > 3 || qh->VORONOI)) {+ 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");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (printgeom) {+ if (qh->hull_dim > 4) {+ qh_fprintf(qh, qh->ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->PRINTnoplanes && !(qh->PRINTcoplanar + qh->PRINTcentrums+ + qh->PRINTdots + qh->PRINTspheres + qh->DOintersections + qh->PRINTridges)) {+ qh_fprintf(qh, qh->ferr, 6058, "qhull input error: no output specified for Geomview\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->VORONOI && (qh->hull_dim > 3 || qh->DROPdim >= 0)) {+ qh_fprintf(qh, qh->ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");+ qh_errexit(qh, 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)) {+ qh_fprintf(qh, qh->ferr, 7042, "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;+ }+ }+ if (!qh->KEEPcoplanar && !qh->KEEPinside && !qh->ONLYgood) {+ if ((qh->PRINTcoplanar && qh->PRINTspheres) || printcoplanar) {+ if (qh->QHULLfinished) {+ qh_fprintf(qh, qh->ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");+ }else {+ qh->KEEPcoplanar = True;+ qh_option(qh, "Qcoplanar", NULL, NULL);+ }+ }+ }+ 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)+ 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);+ }else+ qh->DROPdim= -1;+ }else if (qh->VORONOI) {+ qh->DROPdim= qh->hull_dim-1;+ qh->PRINTdim= qh->hull_dim-1;+ }+} /* qh_initqhull_outputflags */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_start">-</a>++ qh_initqhull_start(qh, infile, outfile, errfile )+ allocate memory if needed and call qh_initqhull_start2()+*/+void qh_initqhull_start(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {++ qh_initstatistics(qh);+ qh_initqhull_start2(qh, infile, outfile, errfile);+} /* initqhull_start */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initqhull_start2">-</a>++ qh_initqhull_start2(qh, infile, outfile, errfile )+ start initialization of qhull+ initialize statistics, stdio, default values for global variables+ assumes qh is allocated+ notes:+ report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized+ see:+ qh_maxmin() determines the precision constants+ qh_freeqhull()+*/+void qh_initqhull_start2(qhT *qh, FILE *infile, FILE *outfile, FILE *errfile) {+ time_t timedata;+ int seed;++ qh_CPUclock; /* start the clock(for qh_clock). One-shot. */+ /* memset is the same in qh_freeqhull() and qh_initqhull_start2() */+ memset((char *)qh, 0, sizeof(qhT)-sizeof(qhmemT)-sizeof(qhstatT)); /* every field is 0, FALSE, NULL */+ qh->NOerrexit= True;+ qh->ANGLEmerge= True;+ qh->DROPdim= -1;+ qh->ferr= errfile;+ qh->fin= infile;+ qh->fout= outfile;+ qh->furthest_id= qh_IDunknown;+ qh->JOGGLEmax= REALmax;+ qh->KEEPminArea = REALmax;+ qh->last_low= REALmax;+ qh->last_high= REALmax;+ qh->last_newhigh= REALmax;+ qh->last_random= 1;+ 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= qh_IDunknown; /* recompile or use 'TPn' */+ qh->tracefacet_id= UINT_MAX; /* recompile to trace a facet */+ qh->tracevertex_id= UINT_MAX; /* recompile to trace a vertex */+ seed= (int)time(&timedata);+ qh_RANDOMseed_(qh, seed);+ qh->run_id= qh_RANDOMint;+ if(!qh->run_id)+ qh->run_id++; /* guarantee non-zero */+ qh_option(qh, "run-id", &qh->run_id, NULL);+ strcat(qh->qhull, "qhull");+} /* initqhull_start2 */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="initthresholds">-</a>++ qh_initthresholds(qh, 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(qhT *qh, char *command) {+ realT value;+ int idx, maxdim, k;+ char *s= command; /* non-const due to strtol */+ 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)) {+ qh_fprintf(qh, qh->ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s. Ignored\n",+ key, s-1);+ continue;+ }+ idx= qh_strtol(s, &s);+ if (idx >= qh->hull_dim) {+ qh_fprintf(qh, qh->ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d. Ignored\n",+ idx, key, qh->hull_dim);+ continue;+ }+ if (*s == ':') {+ s++;+ value= qh_strtod(s, &s);+ if (fabs((double)value) > 1.0) {+ qh_fprintf(qh, qh->ferr, 7046, "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[idx]= value;+ else+ qh->upper_threshold[idx]= 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)) {+ qh_fprintf(qh, qh->ferr, 7047, "qhull warning: no dimension given for Qhull option %c. Ignored\n",+ key);+ continue;+ }+ idx= qh_strtol(s, &s);+ if (idx >= maxdim) {+ qh_fprintf(qh, qh->ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n",+ idx, 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[idx]= value;+ else+ qh->upper_bound[idx]= 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_r.htm#TOC"+ >-------------------------------</a><a name="lib_check">-</a>++ qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )+ Report error if library does not agree with caller++ notes:+ NOerrors -- qh_lib_check can not call qh_errexit()+*/+void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {+ boolT iserror= False;++#if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG) /* user_r.h */+ // _CrtSetBreakAlloc(744); /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );+ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );+ _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );+ _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );+ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );+#endif++ if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */+ qh_fprintf_stderr(6257, "qh_lib_check: Incorrect qhull library called. Caller uses non-reentrant Qhull with a static qhT. Library is reentrant.\n");+ iserror= True;+ }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */+ 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");+ iserror= True;+ }else if (qhullLibraryType!=QHULL_REENTRANT) { /* 2 */+ 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);+ iserror= True;+ }+ if (qhTsize != sizeof(qhT)) {+ 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));+ iserror= True;+ }+ if (vertexTsize != sizeof(vertexT)) {+ 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));+ iserror= True;+ }+ if (ridgeTsize != sizeof(ridgeT)) {+ 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));+ iserror= True;+ }+ if (facetTsize != sizeof(facetT)) {+ 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));+ iserror= True;+ }+ if (setTsize && setTsize != sizeof(setT)) {+ 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));+ iserror= True;+ }+ if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {+ 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));+ iserror= True;+ }+ if (iserror) {+ qh_fprintf_stderr(6259, "qh_lib_check: Cannot continue. Library '%s' is reentrant (e.g., qhull_r.so)\n", qh_version2);+ qh_exit(qh_ERRqhull); /* can not use qh_errexit() */+ }+} /* lib_check */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="option">-</a>++ qh_option(qh, option, intVal, realVal )+ add an option description to qh.qhull_options++ notes:+ NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]+ will be printed with statistics ('Ts') and errors+ strlen(option) < 40+*/+void qh_option(qhT *qh, const 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= (int)strlen(buf); /* WARN64 */+ qh->qhull_optionlen += len;+ maxlen= sizeof(qh->qhull_options) - len -1;+ maximize_(maxlen, 0);+ if (qh->qhull_optionlen >= qh_OPTIONline && maxlen > 0) {+ qh->qhull_optionlen= len;+ strncat(qh->qhull_options, "\n", (size_t)(maxlen--));+ }+ strncat(qh->qhull_options, buf, (size_t)maxlen);+} /* option */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="zero">-</a>++ qh_zero( qh, errfile )+ Initialize and zero Qhull's memory for qh_new_qhull()++ notes:+ Not needed in global.c because static variables are initialized to zero+*/+void qh_zero(qhT *qh, FILE *errfile) {+ memset((char *)qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */+ qh->NOerrexit= True;+ qh_meminit(qh, errfile);+} /* zero */+
+ Cdir/halfspaces.c view
@@ -0,0 +1,68 @@+#define qh_QHimport+#include "qhull_ra.h"++double** intersections(+ double* halfspaces,+ double* interiorpoint,+ unsigned dim,+ unsigned n,+ unsigned* nintersections,+ unsigned* exitcode,+ unsigned print+)+{+ char opts[250];+ sprintf(opts, "qhull s Fp FF H H%f", interiorpoint[0]); //, interiorpoint[1] , interiorpoint[2]);+ for(unsigned i=1; i < dim; i++){+ char x[20];+ sprintf(x, ",%f", interiorpoint[i]);+ strcat(opts, x);+ }+ printf(opts); printf("\n");++ qhT qh_qh; /* Qhull's data structure */+ qhT* qh= &qh_qh;+ QHULL_LIB_CHECK+ qh_meminit(qh, stderr);+ boolT ismalloc = False; /* True if qhull should free points in qh_freeqhull() or reallocation */+ FILE *errfile = NULL;+ FILE* outfile = print ? stdout : NULL;+ qh_zero(qh, errfile);+ *exitcode = qh_new_qhull(qh, dim+1, n, halfspaces, ismalloc, opts, outfile,+ errfile);+ printf("exitcode: %u\n", *exitcode);++ double** out;+ if(!(*exitcode)){+ *nintersections = qh->num_facets;+ out = malloc(*nintersections * sizeof(double*));+ facetT *facet;+ unsigned i_facet = 0;+ FORALLfacets{+ if(facet->offset != 0){+ out[i_facet] = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ out[i_facet][i] = - facet->normal[i] / facet->offset ++ qh->feasible_point[i]; // = interiorpoint ? yes+ }+ i_facet++;+ }else{+ (*nintersections)--;+ }+ }++ }++ /* Do cleanup regardless of whether there is an error */+ int curlong, totlong;+ qh_freeqhull(qh, !qh_ALL); /* free long memory */+ qh_memfreeshort(qh, &curlong, &totlong); /* free short memory and memory allocator */++ if(*exitcode){+ free(out);+ return 0;+ }else{+ return out;+ }++}
+ Cdir/io_r.c view
@@ -0,0 +1,4062 @@+/*<html><pre> -<a href="qh-io_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ io_r.c+ Input/Output routines of qhull application++ see qh-io_r.htm and io_r.h++ see user_r.c for qh_errprint and qh_printfacetlist++ unix_r.c calls qh_readpoints and qh_produce_output++ unix_r.c and user_r.c are the only callers of io_r.c functions+ This allows the user to avoid loading io_r.o from qhull.a++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/io_r.c#4 $$Change: 2064 $+ $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $+*/++#include "qhull_ra.h"++/*========= -functions in alphabetical order after qh_produce_output(qh) =====*/++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="produce_output">-</a>++ qh_produce_output(qh)+ qh_produce_output2(qh)+ prints out the result of qhull in desired format+ qh_produce_output2(qh) does not call qh_prepare_output(qh)+ if qh.GETarea+ computes and prints area and volume+ qh.PRINTout[] is an array of output formats++ notes:+ prints output in qh.PRINTout order+*/+void qh_produce_output(qhT *qh) {+ int tempsize= qh_setsize(qh, qh->qhmem.tempstack);++ qh_prepare_output(qh);+ qh_produce_output2(qh);+ if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {+ qh_fprintf(qh, qh->ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n",+ qh_setsize(qh, qh->qhmem.tempstack));+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+} /* produce_output */+++void qh_produce_output2(qhT *qh) {+ int i, tempsize= qh_setsize(qh, qh->qhmem.tempstack), d_1;++ if (qh->PRINTsummary)+ qh_printsummary(qh, qh->ferr);+ else if (qh->PRINTout[0] == qh_PRINTnone)+ qh_printsummary(qh, qh->fout);+ for (i=0; i < qh_PRINTEND; i++)+ qh_printfacets(qh, qh->fout, qh->PRINTout[i], qh->facet_list, NULL, !qh_ALL);+ qh_allstatistics(qh);+ if (qh->PRINTprecision && !qh->MERGING && (qh->JOGGLEmax > REALmax/2 || qh->RERUN))+ qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);+ if (qh->VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))+ qh_printstats(qh, qh->ferr, qh->qhstat.vridges, NULL);+ if (qh->PRINTstatistics) {+ qh_printstatistics(qh, qh->ferr, "");+ qh_memstatistics(qh, qh->ferr);+ d_1= sizeof(setT) + (qh->hull_dim - 1) * SETelemsize;+ qh_fprintf(qh, qh->ferr, 8040, "\+ size in bytes: merge %d ridge %d vertex %d facet %d\n\+ normal %d ridge vertices %d facet vertices or neighbors %d\n",+ (int)sizeof(mergeT), (int)sizeof(ridgeT),+ (int)sizeof(vertexT), (int)sizeof(facetT),+ qh->normal_size, d_1, d_1 + SETelemsize);+ }+ if (qh_setsize(qh, qh->qhmem.tempstack) != tempsize) {+ qh_fprintf(qh, qh->ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n",+ qh_setsize(qh, qh->qhmem.tempstack));+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+} /* produce_output2 */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="dfacet">-</a>++ qh_dfacet(qh, id )+ print facet by id, for debugging++*/+void qh_dfacet(qhT *qh, unsigned id) {+ facetT *facet;++ FORALLfacets {+ if (facet->id == id) {+ qh_printfacet(qh, qh->fout, facet);+ break;+ }+ }+} /* dfacet */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="dvertex">-</a>++ qh_dvertex(qh, id )+ print vertex by id, for debugging+*/+void qh_dvertex(qhT *qh, unsigned id) {+ vertexT *vertex;++ FORALLvertices {+ if (vertex->id == id) {+ qh_printvertex(qh, qh->fout, vertex);+ break;+ }+ }+} /* dvertex */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="compare_facetarea">-</a>++ qh_compare_facetarea(p1, p2 )+ used by qsort() to order facets by area+*/+int qh_compare_facetarea(const void *p1, const void *p2) {+ const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);++ if (!a->isarea)+ return -1;+ if (!b->isarea)+ return 1;+ if (a->f.area > b->f.area)+ return 1;+ else if (a->f.area == b->f.area)+ return 0;+ return -1;+} /* compare_facetarea */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="compare_facetmerge">-</a>++ qh_compare_facetmerge(p1, p2 )+ used by qsort() to order facets by number of merges+*/+int qh_compare_facetmerge(const void *p1, const void *p2) {+ const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);++ return(a->nummerge - b->nummerge);+} /* compare_facetvisit */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="compare_facetvisit">-</a>++ qh_compare_facetvisit(p1, p2 )+ used by qsort() to order facets by visit id or id+*/+int qh_compare_facetvisit(const void *p1, const void *p2) {+ const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2);+ int i,j;++ if (!(i= a->visitid))+ i= 0 - a->id; /* do not convert to int, sign distinguishes id from visitid */+ if (!(j= b->visitid))+ j= 0 - b->id;+ return(i - j);+} /* compare_facetvisit */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="compare_vertexpoint">-</a>++ qh_compare_vertexpoint( p1, p2 )+ used by qsort() to order vertices by point id++ Not usable in qhulllib_r since qh_pointid depends on qh++ int qh_compare_vertexpoint(const void *p1, const void *p2) {+ const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);++ return((qh_pointid(qh, a->point) > qh_pointid(qh, b->point)?1:-1));+}*/++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="copyfilename">-</a>++ qh_copyfilename(qh, dest, size, source, length )+ copy filename identified by qh_skipfilename()++ notes:+ see qh_skipfilename() for syntax+*/+void qh_copyfilename(qhT *qh, char *filename, int size, const char* source, int length) {+ char c= *source;++ if (length > size + 1) {+ qh_fprintf(qh, qh->ferr, 6040, "qhull error: filename is more than %d characters, %s\n", size-1, source);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ strncpy(filename, source, length);+ filename[length]= '\0';+ if (c == '\'' || c == '"') {+ char *s= filename + 1;+ char *t= filename;+ while (*s) {+ if (*s == c) {+ if (s[-1] == '\\')+ t[-1]= c;+ }else+ *t++= *s;+ s++;+ }+ *t= '\0';+ }+} /* copyfilename */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="countfacets">-</a>++ qh_countfacets(qh, facetlist, facets, printall,+ numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars )+ count good facets for printing and set visitid+ if allfacets, ignores qh_skipfacet()++ notes:+ qh_printsummary and qh_countfacets must match counts++ returns:+ numfacets, numsimplicial, total neighbors, numridges, coplanars+ each facet with ->visitid indicating 1-relative position+ ->visitid==0 indicates not good++ notes+ numfacets >= numsimplicial+ if qh.NEWfacets,+ does not count visible facets (matches qh_printafacet)++ design:+ for all facets on facetlist and in facets set+ unless facet is skipped or visible (i.e., will be deleted)+ mark facet->visitid+ update counts+*/+void qh_countfacets(qhT *qh, facetT *facetlist, setT *facets, boolT printall,+ int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {+ facetT *facet, **facetp;+ int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;++ FORALLfacet_(facetlist) {+ if ((facet->visible && qh->NEWfacets)+ || (!printall && qh_skipfacet(qh, facet)))+ facet->visitid= 0;+ else {+ facet->visitid= ++numfacets;+ totneighbors += qh_setsize(qh, facet->neighbors);+ if (facet->simplicial) {+ numsimplicial++;+ if (facet->keepcentrum && facet->tricoplanar)+ numtricoplanars++;+ }else+ numridges += qh_setsize(qh, facet->ridges);+ if (facet->coplanarset)+ numcoplanars += qh_setsize(qh, facet->coplanarset);+ }+ }++ FOREACHfacet_(facets) {+ if ((facet->visible && qh->NEWfacets)+ || (!printall && qh_skipfacet(qh, facet)))+ facet->visitid= 0;+ else {+ facet->visitid= ++numfacets;+ totneighbors += qh_setsize(qh, facet->neighbors);+ if (facet->simplicial){+ numsimplicial++;+ if (facet->keepcentrum && facet->tricoplanar)+ numtricoplanars++;+ }else+ numridges += qh_setsize(qh, facet->ridges);+ if (facet->coplanarset)+ numcoplanars += qh_setsize(qh, facet->coplanarset);+ }+ }+ qh->visit_id += numfacets+1;+ *numfacetsp= numfacets;+ *numsimplicialp= numsimplicial;+ *totneighborsp= totneighbors;+ *numridgesp= numridges;+ *numcoplanarsp= numcoplanars;+ *numtricoplanarsp= numtricoplanars;+} /* countfacets */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="detvnorm">-</a>++ qh_detvnorm(qh, vertex, vertexA, centers, offset )+ compute separating plane of the Voronoi diagram for a pair of input sites+ centers= set of facets (i.e., Voronoi vertices)+ facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)++ assumes:+ qh_ASvoronoi and qh_vertexneighbors() already set++ returns:+ norm+ a pointer into qh.gm_matrix to qh.hull_dim-1 reals+ copy the data before reusing qh.gm_matrix+ offset+ if 'QVn'+ sign adjusted so that qh.GOODvertexp is inside+ else+ sign adjusted so that vertex is inside++ qh.gm_matrix= simplex of points from centers relative to first center++ notes:+ in io_r.c so that code for 'v Tv' can be removed by removing io_r.c+ returns pointer into qh.gm_matrix to avoid tracking of temporary memory++ design:+ determine midpoint of input sites+ build points as the set of Voronoi vertices+ select a simplex from points (if necessary)+ include midpoint if the Voronoi region is unbounded+ relocate the first vertex of the simplex to the origin+ compute the normalized hyperplane through the simplex+ orient the hyperplane toward 'QVn' or 'vertex'+ if 'Tv' or 'Ts'+ if bounded+ test that hyperplane is the perpendicular bisector of the input sites+ test that Voronoi vertices not in the simplex are still on the hyperplane+ free up temporary memory+*/+pointT *qh_detvnorm(qhT *qh, vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {+ facetT *facet, **facetp;+ int i, k, pointid, pointidA, point_i, point_n;+ setT *simplex= NULL;+ pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;+ coordT *coord, *gmcoord, *normalp;+ setT *points= qh_settemp(qh, qh->TEMPsize);+ boolT nearzero= False;+ boolT unbounded= False;+ int numcenters= 0;+ int dim= qh->hull_dim - 1;+ realT dist, offset, angle, zero= 0.0;++ midpoint= qh->gm_matrix + qh->hull_dim * qh->hull_dim; /* last row */+ for (k=0; k < dim; k++)+ midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;+ FOREACHfacet_(centers) {+ numcenters++;+ if (!facet->visitid)+ unbounded= True;+ else {+ if (!facet->center)+ facet->center= qh_facetcenter(qh, facet->vertices);+ qh_setappend(qh, &points, facet->center);+ }+ }+ if (numcenters > dim) {+ simplex= qh_settemp(qh, qh->TEMPsize);+ qh_setappend(qh, &simplex, vertex->point);+ if (unbounded)+ qh_setappend(qh, &simplex, midpoint);+ qh_maxsimplex(qh, dim, points, NULL, 0, &simplex);+ qh_setdelnth(qh, simplex, 0);+ }else if (numcenters == dim) {+ if (unbounded)+ qh_setappend(qh, &points, midpoint);+ simplex= points;+ }else {+ qh_fprintf(qh, qh->ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ i= 0;+ gmcoord= qh->gm_matrix;+ point0= SETfirstt_(simplex, pointT);+ FOREACHpoint_(simplex) {+ if (qh->IStracing >= 4)+ qh_printmatrix(qh, qh->ferr, "qh_detvnorm: Voronoi vertex or midpoint",+ &point, 1, dim);+ if (point != point0) {+ qh->gm_row[i++]= gmcoord;+ coord= point0;+ for (k=dim; k--; )+ *(gmcoord++)= *point++ - *coord++;+ }+ }+ qh->gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */+ normal= gmcoord;+ qh_sethyperplane_gauss(qh, dim, qh->gm_row, point0, True,+ normal, &offset, &nearzero);+ if (qh->GOODvertexp == vertexA->point)+ inpoint= vertexA->point;+ else+ inpoint= vertex->point;+ zinc_(Zdistio);+ dist= qh_distnorm(dim, inpoint, normal, &offset);+ if (dist > 0) {+ offset= -offset;+ normalp= normal;+ for (k=dim; k--; ) {+ *normalp= -(*normalp);+ normalp++;+ }+ }+ if (qh->VERIFYoutput || qh->PRINTstatistics) {+ pointid= qh_pointid(qh, vertex->point);+ pointidA= qh_pointid(qh, vertexA->point);+ if (!unbounded) {+ zinc_(Zdiststat);+ dist= qh_distnorm(dim, midpoint, normal, &offset);+ if (dist < 0)+ dist= -dist;+ zzinc_(Zridgemid);+ wwmax_(Wridgemidmax, dist);+ wwadd_(Wridgemid, dist);+ trace4((qh, qh->ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",+ pointid, pointidA, dist));+ for (k=0; k < dim; k++)+ midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */+ qh_normalize(qh, midpoint, dim, False);+ angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */+ if (angle < 0.0)+ angle= angle + 1.0;+ else+ angle= angle - 1.0;+ if (angle < 0.0)+ angle -= angle;+ trace4((qh, qh->ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",+ pointid, pointidA, angle, nearzero));+ if (nearzero) {+ zzinc_(Zridge0);+ wwmax_(Wridge0max, angle);+ wwadd_(Wridge0, angle);+ }else {+ zzinc_(Zridgeok)+ wwmax_(Wridgeokmax, angle);+ wwadd_(Wridgeok, angle);+ }+ }+ if (simplex != points) {+ FOREACHpoint_i_(qh, points) {+ if (!qh_setin(simplex, point)) {+ facet= SETelemt_(centers, point_i, facetT);+ zinc_(Zdiststat);+ dist= qh_distnorm(dim, point, normal, &offset);+ if (dist < 0)+ dist= -dist;+ zzinc_(Zridge);+ wwmax_(Wridgemax, dist);+ wwadd_(Wridge, dist);+ trace4((qh, qh->ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",+ pointid, pointidA, facet->visitid, dist));+ }+ }+ }+ }+ *offsetp= offset;+ if (simplex != points)+ qh_settempfree(qh, &simplex);+ qh_settempfree(qh, &points);+ return normal;+} /* detvnorm */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="detvridge">-</a>++ qh_detvridge(qh, vertexA )+ determine Voronoi ridge from 'seen' neighbors of vertexA+ include one vertex-at-infinite if an !neighbor->visitid++ returns:+ temporary set of centers (facets, i.e., Voronoi vertices)+ sorted by center id+*/+setT *qh_detvridge(qhT *qh, vertexT *vertex) {+ setT *centers= qh_settemp(qh, qh->TEMPsize);+ setT *tricenters= qh_settemp(qh, qh->TEMPsize);+ facetT *neighbor, **neighborp;+ boolT firstinf= True;++ FOREACHneighbor_(vertex) {+ if (neighbor->seen) {+ if (neighbor->visitid) {+ if (!neighbor->tricoplanar || qh_setunique(qh, &tricenters, neighbor->center))+ qh_setappend(qh, ¢ers, neighbor);+ }else if (firstinf) {+ firstinf= False;+ qh_setappend(qh, ¢ers, neighbor);+ }+ }+ }+ qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(qh, centers),+ sizeof(facetT *), qh_compare_facetvisit);+ qh_settempfree(qh, &tricenters);+ return centers;+} /* detvridge */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="detvridge3">-</a>++ qh_detvridge3(qh, atvertex, vertex )+ determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex+ include one vertex-at-infinite for !neighbor->visitid+ assumes all facet->seen2= True++ returns:+ temporary set of centers (facets, i.e., Voronoi vertices)+ listed in adjacency order (!oriented)+ all facet->seen2= True++ design:+ mark all neighbors of atvertex+ for each adjacent neighbor of both atvertex and vertex+ if neighbor selected+ add neighbor to set of Voronoi vertices+*/+setT *qh_detvridge3(qhT *qh, vertexT *atvertex, vertexT *vertex) {+ setT *centers= qh_settemp(qh, qh->TEMPsize);+ setT *tricenters= qh_settemp(qh, qh->TEMPsize);+ facetT *neighbor, **neighborp, *facet= NULL;+ boolT firstinf= True;++ FOREACHneighbor_(atvertex)+ neighbor->seen2= False;+ FOREACHneighbor_(vertex) {+ if (!neighbor->seen2) {+ facet= neighbor;+ break;+ }+ }+ while (facet) {+ facet->seen2= True;+ if (neighbor->seen) {+ if (facet->visitid) {+ if (!facet->tricoplanar || qh_setunique(qh, &tricenters, facet->center))+ qh_setappend(qh, ¢ers, facet);+ }else if (firstinf) {+ firstinf= False;+ qh_setappend(qh, ¢ers, facet);+ }+ }+ FOREACHneighbor_(facet) {+ if (!neighbor->seen2) {+ if (qh_setin(vertex->neighbors, neighbor))+ break;+ else+ neighbor->seen2= True;+ }+ }+ facet= neighbor;+ }+ if (qh->CHECKfrequently) {+ FOREACHneighbor_(vertex) {+ if (!neighbor->seen2) {+ qh_fprintf(qh, qh->ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n",+ qh_pointid(qh, vertex->point), neighbor->id);+ qh_errexit(qh, qh_ERRqhull, neighbor, NULL);+ }+ }+ }+ FOREACHneighbor_(atvertex)+ neighbor->seen2= True;+ qh_settempfree(qh, &tricenters);+ return centers;+} /* detvridge3 */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="eachvoronoi">-</a>++ qh_eachvoronoi(qh, fp, printvridge, vertex, visitall, innerouter, inorder )+ if visitall,+ visit all Voronoi ridges for vertex (i.e., an input site)+ else+ visit all unvisited Voronoi ridges for vertex+ all vertex->seen= False if unvisited+ assumes+ all facet->seen= False+ all facet->seen2= True (for qh_detvridge3)+ all facet->visitid == 0 if vertex_at_infinity+ == index of Voronoi vertex+ >= qh.num_facets if ignored+ innerouter:+ qh_RIDGEall-- both inner (bounded) and outer(unbounded) ridges+ qh_RIDGEinner- only inner+ qh_RIDGEouter- only outer++ if inorder+ orders vertices for 3-d Voronoi diagrams++ returns:+ number of visited ridges (does not include previously visited ridges)++ if printvridge,+ calls printvridge( fp, vertex, vertexA, centers)+ fp== any pointer (assumes FILE*)+ vertex,vertexA= pair of input sites that define a Voronoi ridge+ centers= set of facets (i.e., Voronoi vertices)+ ->visitid == index or 0 if vertex_at_infinity+ ordered for 3-d Voronoi diagram+ notes:+ uses qh.vertex_visit++ see:+ qh_eachvoronoi_all()++ design:+ mark selected neighbors of atvertex+ for each selected neighbor (either Voronoi vertex or vertex-at-infinity)+ for each unvisited vertex+ if atvertex and vertex share more than d-1 neighbors+ bump totalcount+ if printvridge defined+ build the set of shared neighbors (i.e., Voronoi vertices)+ call printvridge+*/+int qh_eachvoronoi(qhT *qh, FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {+ boolT unbounded;+ int count;+ facetT *neighbor, **neighborp, *neighborA, **neighborAp;+ setT *centers;+ setT *tricenters= qh_settemp(qh, qh->TEMPsize);++ vertexT *vertex, **vertexp;+ boolT firstinf;+ unsigned int numfacets= (unsigned int)qh->num_facets;+ int totridges= 0;++ qh->vertex_visit++;+ atvertex->seen= True;+ if (visitall) {+ FORALLvertices+ vertex->seen= False;+ }+ FOREACHneighbor_(atvertex) {+ if (neighbor->visitid < numfacets)+ neighbor->seen= True;+ }+ FOREACHneighbor_(atvertex) {+ if (neighbor->seen) {+ FOREACHvertex_(neighbor->vertices) {+ if (vertex->visitid != qh->vertex_visit && !vertex->seen) {+ vertex->visitid= qh->vertex_visit;+ count= 0;+ firstinf= True;+ qh_settruncate(qh, tricenters, 0);+ FOREACHneighborA_(vertex) {+ if (neighborA->seen) {+ if (neighborA->visitid) {+ if (!neighborA->tricoplanar || qh_setunique(qh, &tricenters, neighborA->center))+ count++;+ }else if (firstinf) {+ count++;+ firstinf= False;+ }+ }+ }+ if (count >= qh->hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */+ if (firstinf) {+ if (innerouter == qh_RIDGEouter)+ continue;+ unbounded= False;+ }else {+ if (innerouter == qh_RIDGEinner)+ continue;+ unbounded= True;+ }+ totridges++;+ trace4((qh, qh->ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",+ count, qh_pointid(qh, atvertex->point), qh_pointid(qh, vertex->point)));+ if (printvridge && fp) {+ if (inorder && qh->hull_dim == 3+1) /* 3-d Voronoi diagram */+ centers= qh_detvridge3(qh, atvertex, vertex);+ else+ centers= qh_detvridge(qh, vertex);+ (*printvridge)(qh, fp, atvertex, vertex, centers, unbounded);+ qh_settempfree(qh, ¢ers);+ }+ }+ }+ }+ }+ }+ FOREACHneighbor_(atvertex)+ neighbor->seen= False;+ qh_settempfree(qh, &tricenters);+ return totridges;+} /* eachvoronoi */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="eachvoronoi_all">-</a>++ qh_eachvoronoi_all(qh, fp, printvridge, isUpper, innerouter, inorder )+ visit all Voronoi ridges++ innerouter:+ see qh_eachvoronoi()++ if inorder+ orders vertices for 3-d Voronoi diagrams++ returns+ total number of ridges++ if isUpper == facet->upperdelaunay (i.e., a Vornoi vertex)+ facet->visitid= Voronoi vertex index(same as 'o' format)+ else+ facet->visitid= 0++ if printvridge,+ calls printvridge( fp, vertex, vertexA, centers)+ [see qh_eachvoronoi]++ notes:+ Not used for qhull.exe+ same effect as qh_printvdiagram but ridges not sorted by point id+*/+int qh_eachvoronoi_all(qhT *qh, FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) {+ facetT *facet;+ vertexT *vertex;+ int numcenters= 1; /* vertex 0 is vertex-at-infinity */+ int totridges= 0;++ qh_clearcenters(qh, qh_ASvoronoi);+ qh_vertexneighbors(qh);+ maximize_(qh->visit_id, (unsigned) qh->num_facets);+ FORALLfacets {+ facet->visitid= 0;+ facet->seen= False;+ facet->seen2= True;+ }+ FORALLfacets {+ if (facet->upperdelaunay == isUpper)+ facet->visitid= numcenters++;+ }+ FORALLvertices+ vertex->seen= False;+ FORALLvertices {+ if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)+ continue;+ totridges += qh_eachvoronoi(qh, fp, printvridge, vertex,+ !qh_ALL, innerouter, inorder);+ }+ return totridges;+} /* eachvoronoi_all */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="facet2point">-</a>++ qh_facet2point(qh, facet, point0, point1, mindist )+ return two projected temporary vertices for a 2-d facet+ may be non-simplicial++ returns:+ point0 and point1 oriented and projected to the facet+ returns mindist (maximum distance below plane)+*/+void qh_facet2point(qhT *qh, facetT *facet, pointT **point0, pointT **point1, realT *mindist) {+ vertexT *vertex0, *vertex1;+ realT dist;++ if (facet->toporient ^ qh_ORIENTclock) {+ vertex0= SETfirstt_(facet->vertices, vertexT);+ vertex1= SETsecondt_(facet->vertices, vertexT);+ }else {+ vertex1= SETfirstt_(facet->vertices, vertexT);+ vertex0= SETsecondt_(facet->vertices, vertexT);+ }+ zadd_(Zdistio, 2);+ qh_distplane(qh, vertex0->point, facet, &dist);+ *mindist= dist;+ *point0= qh_projectpoint(qh, vertex0->point, facet, dist);+ qh_distplane(qh, vertex1->point, facet, &dist);+ minimize_(*mindist, dist);+ *point1= qh_projectpoint(qh, vertex1->point, facet, dist);+} /* facet2point */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="facetvertices">-</a>++ qh_facetvertices(qh, facetlist, facets, allfacets )+ returns temporary set of vertices in a set and/or list of facets+ if allfacets, ignores qh_skipfacet()++ returns:+ vertices with qh.vertex_visit++ notes:+ optimized for allfacets of facet_list++ design:+ if allfacets of facet_list+ create vertex set from vertex_list+ else+ for each selected facet in facets or facetlist+ append unvisited vertices to vertex set+*/+setT *qh_facetvertices(qhT *qh, facetT *facetlist, setT *facets, boolT allfacets) {+ setT *vertices;+ facetT *facet, **facetp;+ vertexT *vertex, **vertexp;++ qh->vertex_visit++;+ if (facetlist == qh->facet_list && allfacets && !facets) {+ vertices= qh_settemp(qh, qh->num_vertices);+ FORALLvertices {+ vertex->visitid= qh->vertex_visit;+ qh_setappend(qh, &vertices, vertex);+ }+ }else {+ vertices= qh_settemp(qh, qh->TEMPsize);+ FORALLfacet_(facetlist) {+ if (!allfacets && qh_skipfacet(qh, facet))+ continue;+ FOREACHvertex_(facet->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ vertex->visitid= qh->vertex_visit;+ qh_setappend(qh, &vertices, vertex);+ }+ }+ }+ }+ FOREACHfacet_(facets) {+ if (!allfacets && qh_skipfacet(qh, facet))+ continue;+ FOREACHvertex_(facet->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ vertex->visitid= qh->vertex_visit;+ qh_setappend(qh, &vertices, vertex);+ }+ }+ }+ return vertices;+} /* facetvertices */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="geomplanes">-</a>++ qh_geomplanes(qh, facet, outerplane, innerplane )+ return outer and inner planes for Geomview+ qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)++ notes:+ assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon+*/+void qh_geomplanes(qhT *qh, facetT *facet, realT *outerplane, realT *innerplane) {+ realT radius;++ if (qh->MERGING || qh->JOGGLEmax < REALmax/2) {+ qh_outerinner(qh, facet, outerplane, innerplane);+ radius= qh->PRINTradius;+ if (qh->JOGGLEmax < REALmax/2)+ radius -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim); /* already accounted for in qh_outerinner() */+ *outerplane += radius;+ *innerplane -= radius;+ if (qh->PRINTcoplanar || qh->PRINTspheres) {+ *outerplane += qh->MAXabs_coord * qh_GEOMepsilon;+ *innerplane -= qh->MAXabs_coord * qh_GEOMepsilon;+ }+ }else+ *innerplane= *outerplane= 0;+} /* geomplanes */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="markkeep">-</a>++ qh_markkeep(qh, facetlist )+ mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea+ ignores visible facets (!part of convex hull)++ returns:+ may clear facet->good+ recomputes qh.num_good++ design:+ get set of good facets+ if qh.KEEParea+ sort facets by area+ clear facet->good for all but n largest facets+ if qh.KEEPmerge+ sort facets by merge count+ clear facet->good for all but n most merged facets+ if qh.KEEPminarea+ clear facet->good if area too small+ update qh.num_good+*/+void qh_markkeep(qhT *qh, facetT *facetlist) {+ facetT *facet, **facetp;+ setT *facets= qh_settemp(qh, qh->num_facets);+ int size, count;++ trace2((qh, qh->ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",+ qh->KEEParea, qh->KEEPmerge, qh->KEEPminArea));+ FORALLfacet_(facetlist) {+ if (!facet->visible && facet->good)+ qh_setappend(qh, &facets, facet);+ }+ size= qh_setsize(qh, facets);+ if (qh->KEEParea) {+ qsort(SETaddr_(facets, facetT), (size_t)size,+ sizeof(facetT *), qh_compare_facetarea);+ if ((count= size - qh->KEEParea) > 0) {+ FOREACHfacet_(facets) {+ facet->good= False;+ if (--count == 0)+ break;+ }+ }+ }+ if (qh->KEEPmerge) {+ qsort(SETaddr_(facets, facetT), (size_t)size,+ sizeof(facetT *), qh_compare_facetmerge);+ if ((count= size - qh->KEEPmerge) > 0) {+ FOREACHfacet_(facets) {+ facet->good= False;+ if (--count == 0)+ break;+ }+ }+ }+ if (qh->KEEPminArea < REALmax/2) {+ FOREACHfacet_(facets) {+ if (!facet->isarea || facet->f.area < qh->KEEPminArea)+ facet->good= False;+ }+ }+ qh_settempfree(qh, &facets);+ count= 0;+ FORALLfacet_(facetlist) {+ if (facet->good)+ count++;+ }+ qh->num_good= count;+} /* markkeep */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="markvoronoi">-</a>++ qh_markvoronoi(qh, facetlist, facets, printall, isLower, numcenters )+ mark voronoi vertices for printing by site pairs++ returns:+ temporary set of vertices indexed by pointid+ isLower set if printing lower hull (i.e., at least one facet is lower hull)+ numcenters= total number of Voronoi vertices+ bumps qh.printoutnum for vertex-at-infinity+ clears all facet->seen and sets facet->seen2++ if selected+ facet->visitid= Voronoi vertex id+ else if upper hull (or 'Qu' and lower hull)+ facet->visitid= 0+ else+ facet->visitid >= qh->num_facets++ notes:+ ignores qh.ATinfinity, if defined+*/+setT *qh_markvoronoi(qhT *qh, facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) {+ int numcenters=0;+ facetT *facet, **facetp;+ setT *vertices;+ boolT isLower= False;++ qh->printoutnum++;+ qh_clearcenters(qh, qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */+ qh_vertexneighbors(qh);+ vertices= qh_pointvertex(qh);+ if (qh->ATinfinity)+ SETelem_(vertices, qh->num_points-1)= NULL;+ qh->visit_id++;+ maximize_(qh->visit_id, (unsigned) qh->num_facets);+ FORALLfacet_(facetlist) {+ if (printall || !qh_skipfacet(qh, facet)) {+ if (!facet->upperdelaunay) {+ isLower= True;+ break;+ }+ }+ }+ FOREACHfacet_(facets) {+ if (printall || !qh_skipfacet(qh, facet)) {+ if (!facet->upperdelaunay) {+ isLower= True;+ break;+ }+ }+ }+ FORALLfacets {+ if (facet->normal && (facet->upperdelaunay == isLower))+ facet->visitid= 0; /* facetlist or facets may overwrite */+ else+ facet->visitid= qh->visit_id;+ facet->seen= False;+ facet->seen2= True;+ }+ numcenters++; /* qh_INFINITE */+ FORALLfacet_(facetlist) {+ if (printall || !qh_skipfacet(qh, facet))+ facet->visitid= numcenters++;+ }+ FOREACHfacet_(facets) {+ if (printall || !qh_skipfacet(qh, facet))+ facet->visitid= numcenters++;+ }+ *isLowerp= isLower;+ *numcentersp= numcenters;+ trace2((qh, qh->ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters));+ return vertices;+} /* markvoronoi */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="order_vertexneighbors">-</a>++ qh_order_vertexneighbors(qh, vertex )+ order facet neighbors of a 2-d or 3-d vertex by adjacency++ notes:+ does not orient the neighbors++ design:+ initialize a new neighbor set with the first facet in vertex->neighbors+ while vertex->neighbors non-empty+ select next neighbor in the previous facet's neighbor set+ set vertex->neighbors to the new neighbor set+*/+void qh_order_vertexneighbors(qhT *qh, vertexT *vertex) {+ setT *newset;+ facetT *facet, *neighbor, **neighborp;++ trace4((qh, qh->ferr, 4018, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));+ newset= qh_settemp(qh, qh_setsize(qh, vertex->neighbors));+ facet= (facetT*)qh_setdellast(vertex->neighbors);+ qh_setappend(qh, &newset, facet);+ while (qh_setsize(qh, vertex->neighbors)) {+ FOREACHneighbor_(vertex) {+ if (qh_setin(facet->neighbors, neighbor)) {+ qh_setdel(vertex->neighbors, neighbor);+ qh_setappend(qh, &newset, neighbor);+ facet= neighbor;+ break;+ }+ }+ if (!neighbor) {+ qh_fprintf(qh, qh->ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",+ vertex->id, facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ }+ qh_setfree(qh, &vertex->neighbors);+ qh_settemppop(qh);+ vertex->neighbors= newset;+} /* order_vertexneighbors */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="prepare_output">-</a>++ qh_prepare_output(qh, )+ prepare for qh_produce_output2(qh) according to+ qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds+ does not reset facet->good++ notes+ except for PRINTstatistics, no-op if previously called with same options+*/+void qh_prepare_output(qhT *qh) {+ if (qh->VORONOI) {+ qh_clearcenters(qh, qh_ASvoronoi); /* must be before qh_triangulate */+ qh_vertexneighbors(qh);+ }+ if (qh->TRIangulate && !qh->hasTriangulation) {+ qh_triangulate(qh);+ if (qh->VERIFYoutput && !qh->CHECKfrequently)+ qh_checkpolygon(qh, qh->facet_list);+ }+ qh_findgood_all(qh, qh->facet_list);+ if (qh->GETarea)+ qh_getarea(qh, qh->facet_list);+ if (qh->KEEParea || qh->KEEPmerge || qh->KEEPminArea < REALmax/2)+ qh_markkeep(qh, qh->facet_list);+ if (qh->PRINTstatistics)+ qh_collectstatistics(qh);+}++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printafacet">-</a>++ qh_printafacet(qh, fp, format, facet, printall )+ print facet to fp in given output format (see qh.PRINTout)++ returns:+ nop if !printall and qh_skipfacet()+ nop if visible facet and NEWfacets and format != PRINTfacets+ must match qh_countfacets++ notes+ preserves qh.visit_id+ facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge++ see+ qh_printbegin() and qh_printend()++ design:+ test for printing facet+ call appropriate routine for format+ or output results directly+*/+void qh_printafacet(qhT *qh, FILE *fp, qh_PRINT format, facetT *facet, boolT printall) {+ realT color[4], offset, dist, outerplane, innerplane;+ boolT zerodiv;+ coordT *point, *normp, *coordp, **pointp, *feasiblep;+ int k;+ vertexT *vertex, **vertexp;+ facetT *neighbor, **neighborp;++ if (!printall && qh_skipfacet(qh, facet))+ return;+ if (facet->visible && qh->NEWfacets && format != qh_PRINTfacets)+ return;+ qh->printoutnum++;+ switch (format) {+ case qh_PRINTarea:+ if (facet->isarea) {+ qh_fprintf(qh, fp, 9009, qh_REAL_1, facet->f.area);+ qh_fprintf(qh, fp, 9010, "\n");+ }else+ qh_fprintf(qh, fp, 9011, "0\n");+ break;+ case qh_PRINTcoplanars:+ qh_fprintf(qh, fp, 9012, "%d", qh_setsize(qh, facet->coplanarset));+ FOREACHpoint_(facet->coplanarset)+ qh_fprintf(qh, fp, 9013, " %d", qh_pointid(qh, point));+ qh_fprintf(qh, fp, 9014, "\n");+ break;+ case qh_PRINTcentrums:+ qh_printcenter(qh, fp, format, NULL, facet);+ break;+ case qh_PRINTfacets:+ qh_printfacet(qh, fp, facet);+ break;+ case qh_PRINTfacets_xridge:+ qh_printfacetheader(qh, fp, facet);+ break;+ case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */+ if (!facet->normal)+ break;+ for (k=qh->hull_dim; k--; ) {+ color[k]= (facet->normal[k]+1.0)/2.0;+ maximize_(color[k], -1.0);+ minimize_(color[k], +1.0);+ }+ qh_projectdim3(qh, color, color);+ if (qh->PRINTdim != qh->hull_dim)+ qh_normalize2(qh, color, 3, True, NULL, NULL);+ if (qh->hull_dim <= 2)+ qh_printfacet2geom(qh, fp, facet, color);+ else if (qh->hull_dim == 3) {+ if (facet->simplicial)+ qh_printfacet3geom_simplicial(qh, fp, facet, color);+ else+ qh_printfacet3geom_nonsimplicial(qh, fp, facet, color);+ }else {+ if (facet->simplicial)+ qh_printfacet4geom_simplicial(qh, fp, facet, color);+ else+ qh_printfacet4geom_nonsimplicial(qh, fp, facet, color);+ }+ break;+ case qh_PRINTids:+ qh_fprintf(qh, fp, 9015, "%d\n", facet->id);+ break;+ case qh_PRINTincidences:+ case qh_PRINToff:+ case qh_PRINTtriangles:+ if (qh->hull_dim == 3 && format != qh_PRINTtriangles)+ qh_printfacet3vertex(qh, fp, facet, format);+ else if (facet->simplicial || qh->hull_dim == 2 || format == qh_PRINToff)+ qh_printfacetNvertex_simplicial(qh, fp, facet, format);+ else+ qh_printfacetNvertex_nonsimplicial(qh, fp, facet, qh->printoutvar++, format);+ break;+ case qh_PRINTinner:+ qh_outerinner(qh, facet, NULL, &innerplane);+ offset= facet->offset - innerplane;+ goto LABELprintnorm;+ break; /* prevent warning */+ case qh_PRINTmerges:+ qh_fprintf(qh, fp, 9016, "%d\n", facet->nummerge);+ break;+ case qh_PRINTnormals:+ offset= facet->offset;+ goto LABELprintnorm;+ break; /* prevent warning */+ case qh_PRINTouter:+ qh_outerinner(qh, facet, &outerplane, NULL);+ offset= facet->offset - outerplane;+ LABELprintnorm:+ if (!facet->normal) {+ qh_fprintf(qh, fp, 9017, "no normal for facet f%d\n", facet->id);+ break;+ }+ if (qh->CDDoutput) {+ qh_fprintf(qh, fp, 9018, qh_REAL_1, -offset);+ for (k=0; k < qh->hull_dim; k++)+ qh_fprintf(qh, fp, 9019, qh_REAL_1, -facet->normal[k]);+ }else {+ for (k=0; k < qh->hull_dim; k++)+ qh_fprintf(qh, fp, 9020, qh_REAL_1, facet->normal[k]);+ qh_fprintf(qh, fp, 9021, qh_REAL_1, offset);+ }+ qh_fprintf(qh, fp, 9022, "\n");+ break;+ case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */+ case qh_PRINTmaple:+ if (qh->hull_dim == 2)+ qh_printfacet2math(qh, fp, facet, format, qh->printoutvar++);+ else+ qh_printfacet3math(qh, fp, facet, format, qh->printoutvar++);+ break;+ case qh_PRINTneighbors:+ qh_fprintf(qh, fp, 9023, "%d", qh_setsize(qh, facet->neighbors));+ FOREACHneighbor_(facet)+ qh_fprintf(qh, fp, 9024, " %d",+ neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id);+ qh_fprintf(qh, fp, 9025, "\n");+ break;+ case qh_PRINTpointintersect:+ if (!qh->feasible_point) {+ qh_fprintf(qh, qh->ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh->feasible_point\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (facet->offset > 0)+ goto LABELprintinfinite;+ point= coordp= (coordT*)qh_memalloc(qh, qh->normal_size);+ normp= facet->normal;+ feasiblep= qh->feasible_point;+ if (facet->offset < -qh->MINdenom) {+ for (k=qh->hull_dim; k--; )+ *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);+ }else {+ for (k=qh->hull_dim; k--; ) {+ *(coordp++)= qh_divzero(*(normp++), facet->offset, qh->MINdenom_1,+ &zerodiv) + *(feasiblep++);+ if (zerodiv) {+ qh_memfree(qh, point, qh->normal_size);+ goto LABELprintinfinite;+ }+ }+ }+ qh_printpoint(qh, fp, NULL, point);+ qh_memfree(qh, point, qh->normal_size);+ break;+ LABELprintinfinite:+ for (k=qh->hull_dim; k--; )+ qh_fprintf(qh, fp, 9026, qh_REAL_1, qh_INFINITE);+ qh_fprintf(qh, fp, 9027, "\n");+ break;+ case qh_PRINTpointnearest:+ FOREACHpoint_(facet->coplanarset) {+ int id, id2;+ vertex= qh_nearvertex(qh, facet, point, &dist);+ id= qh_pointid(qh, vertex->point);+ id2= qh_pointid(qh, point);+ qh_fprintf(qh, fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);+ }+ break;+ case qh_PRINTpoints: /* VORONOI only by qh_printbegin */+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9029, "1 ");+ qh_printcenter(qh, fp, format, NULL, facet);+ break;+ case qh_PRINTvertices:+ qh_fprintf(qh, fp, 9030, "%d", qh_setsize(qh, facet->vertices));+ FOREACHvertex_(facet->vertices)+ qh_fprintf(qh, fp, 9031, " %d", qh_pointid(qh, vertex->point));+ qh_fprintf(qh, fp, 9032, "\n");+ break;+ default:+ break;+ }+} /* printafacet */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printbegin">-</a>++ qh_printbegin(qh, )+ prints header for all output formats++ returns:+ checks for valid format++ notes:+ uses qh.visit_id for 3/4off+ changes qh.interior_point if printing centrums+ qh_countfacets clears facet->visitid for non-good facets++ see+ qh_printend() and qh_printafacet()++ design:+ count facets and related statistics+ print header for format+*/+void qh_printbegin(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {+ int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;+ int i, num;+ facetT *facet, **facetp;+ vertexT *vertex, **vertexp;+ setT *vertices;+ pointT *point, **pointp, *pointtemp;++ qh->printoutnum= 0;+ qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,+ &totneighbors, &numridges, &numcoplanars, &numtricoplanars);+ switch (format) {+ case qh_PRINTnone:+ break;+ case qh_PRINTarea:+ qh_fprintf(qh, fp, 9033, "%d\n", numfacets);+ break;+ case qh_PRINTcoplanars:+ qh_fprintf(qh, fp, 9034, "%d\n", numfacets);+ break;+ case qh_PRINTcentrums:+ if (qh->CENTERtype == qh_ASnone)+ qh_clearcenters(qh, qh_AScentrum);+ qh_fprintf(qh, fp, 9035, "%d\n%d\n", qh->hull_dim, numfacets);+ break;+ case qh_PRINTfacets:+ case qh_PRINTfacets_xridge:+ if (facetlist)+ qh_printvertexlist(qh, fp, "Vertices and facets:\n", facetlist, facets, printall);+ break;+ case qh_PRINTgeom:+ if (qh->hull_dim > 4) /* qh_initqhull_globals also checks */+ goto LABELnoformat;+ if (qh->VORONOI && qh->hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */+ goto LABELnoformat;+ if (qh->hull_dim == 2 && (qh->PRINTridges || qh->DOintersections))+ qh_fprintf(qh, qh->ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n");+ if (qh->hull_dim == 4 && (qh->PRINTinner || qh->PRINTouter ||+ (qh->PRINTdim == 4 && qh->PRINTcentrums)))+ qh_fprintf(qh, qh->ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");+ if (qh->PRINTdim == 4 && (qh->PRINTspheres))+ qh_fprintf(qh, qh->ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n");+ if (qh->PRINTdim == 4 && qh->DOintersections && qh->PRINTnoplanes)+ qh_fprintf(qh, qh->ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n");+ if (qh->PRINTdim == 2) {+ qh_fprintf(qh, fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n",+ qh->rbox_command, qh->qhull_command);+ }else if (qh->PRINTdim == 3) {+ qh_fprintf(qh, fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",+ qh->rbox_command, qh->qhull_command);+ }else if (qh->PRINTdim == 4) {+ qh->visit_id++;+ num= 0;+ FORALLfacet_(facetlist) /* get number of ridges to be printed */+ qh_printend4geom(qh, NULL, facet, &num, printall);+ FOREACHfacet_(facets)+ qh_printend4geom(qh, NULL, facet, &num, printall);+ qh->ridgeoutnum= num;+ qh->printoutvar= 0; /* counts number of ridges in output */+ qh_fprintf(qh, fp, 9038, "LIST # %s | %s\n", qh->rbox_command, qh->qhull_command);+ }++ if (qh->PRINTdots) {+ qh->printoutnum++;+ num= qh->num_points + qh_setsize(qh, qh->other_points);+ if (qh->DELAUNAY && qh->ATinfinity)+ num--;+ if (qh->PRINTdim == 4)+ qh_fprintf(qh, fp, 9039, "4VECT %d %d 1\n", num, num);+ else+ qh_fprintf(qh, fp, 9040, "VECT %d %d 1\n", num, num);++ for (i=num; i--; ) {+ if (i % 20 == 0)+ qh_fprintf(qh, fp, 9041, "\n");+ qh_fprintf(qh, fp, 9042, "1 ");+ }+ qh_fprintf(qh, fp, 9043, "# 1 point per line\n1 ");+ for (i=num-1; i--; ) { /* num at least 3 for D2 */+ if (i % 20 == 0)+ qh_fprintf(qh, fp, 9044, "\n");+ qh_fprintf(qh, fp, 9045, "0 ");+ }+ qh_fprintf(qh, fp, 9046, "# 1 color for all\n");+ FORALLpoints {+ if (!qh->DELAUNAY || !qh->ATinfinity || qh_pointid(qh, point) != qh->num_points-1) {+ if (qh->PRINTdim == 4)+ qh_printpoint(qh, fp, NULL, point);+ else+ qh_printpoint3(qh, fp, point);+ }+ }+ FOREACHpoint_(qh->other_points) {+ if (qh->PRINTdim == 4)+ qh_printpoint(qh, fp, NULL, point);+ else+ qh_printpoint3(qh, fp, point);+ }+ qh_fprintf(qh, fp, 9047, "0 1 1 1 # color of points\n");+ }++ if (qh->PRINTdim == 4 && !qh->PRINTnoplanes)+ /* 4dview loads up multiple 4OFF objects slowly */+ qh_fprintf(qh, fp, 9048, "4OFF %d %d 1\n", 3*qh->ridgeoutnum, qh->ridgeoutnum);+ qh->PRINTcradius= 2 * qh->DISTround; /* include test DISTround */+ if (qh->PREmerge) {+ maximize_(qh->PRINTcradius, qh->premerge_centrum + qh->DISTround);+ }else if (qh->POSTmerge)+ maximize_(qh->PRINTcradius, qh->postmerge_centrum + qh->DISTround);+ qh->PRINTradius= qh->PRINTcradius;+ if (qh->PRINTspheres + qh->PRINTcoplanar)+ maximize_(qh->PRINTradius, qh->MAXabs_coord * qh_MINradius);+ if (qh->premerge_cos < REALmax/2) {+ maximize_(qh->PRINTradius, (1- qh->premerge_cos) * qh->MAXabs_coord);+ }else if (!qh->PREmerge && qh->POSTmerge && qh->postmerge_cos < REALmax/2) {+ maximize_(qh->PRINTradius, (1- qh->postmerge_cos) * qh->MAXabs_coord);+ }+ maximize_(qh->PRINTradius, qh->MINvisible);+ if (qh->JOGGLEmax < REALmax/2)+ qh->PRINTradius += qh->JOGGLEmax * sqrt((realT)qh->hull_dim);+ if (qh->PRINTdim != 4 &&+ (qh->PRINTcoplanar || qh->PRINTspheres || qh->PRINTcentrums)) {+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ if (qh->PRINTspheres && qh->PRINTdim <= 3)+ qh_printspheres(qh, fp, vertices, qh->PRINTradius);+ if (qh->PRINTcoplanar || qh->PRINTcentrums) {+ qh->firstcentrum= True;+ if (qh->PRINTcoplanar&& !qh->PRINTspheres) {+ FOREACHvertex_(vertices)+ qh_printpointvect2(qh, fp, vertex->point, NULL, qh->interior_point, qh->PRINTradius);+ }+ FORALLfacet_(facetlist) {+ if (!printall && qh_skipfacet(qh, facet))+ continue;+ if (!facet->normal)+ continue;+ if (qh->PRINTcentrums && qh->PRINTdim <= 3)+ qh_printcentrum(qh, fp, facet, qh->PRINTcradius);+ if (!qh->PRINTcoplanar)+ continue;+ FOREACHpoint_(facet->coplanarset)+ qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);+ FOREACHpoint_(facet->outsideset)+ qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);+ }+ FOREACHfacet_(facets) {+ if (!printall && qh_skipfacet(qh, facet))+ continue;+ if (!facet->normal)+ continue;+ if (qh->PRINTcentrums && qh->PRINTdim <= 3)+ qh_printcentrum(qh, fp, facet, qh->PRINTcradius);+ if (!qh->PRINTcoplanar)+ continue;+ FOREACHpoint_(facet->coplanarset)+ qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);+ FOREACHpoint_(facet->outsideset)+ qh_printpointvect2(qh, fp, point, facet->normal, NULL, qh->PRINTradius);+ }+ }+ qh_settempfree(qh, &vertices);+ }+ qh->visit_id++; /* for printing hyperplane intersections */+ break;+ case qh_PRINTids:+ qh_fprintf(qh, fp, 9049, "%d\n", numfacets);+ break;+ case qh_PRINTincidences:+ if (qh->VORONOI && qh->PRINTprecision)+ qh_fprintf(qh, qh->ferr, 7053, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");+ qh->printoutvar= qh->vertex_id; /* centrum id for non-simplicial facets */+ if (qh->hull_dim <= 3)+ qh_fprintf(qh, fp, 9050, "%d\n", numfacets);+ else+ qh_fprintf(qh, fp, 9051, "%d\n", numsimplicial+numridges);+ break;+ case qh_PRINTinner:+ case qh_PRINTnormals:+ case qh_PRINTouter:+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9052, "%s | %s\nbegin\n %d %d real\n", qh->rbox_command,+ qh->qhull_command, numfacets, qh->hull_dim+1);+ else+ qh_fprintf(qh, fp, 9053, "%d\n%d\n", qh->hull_dim+1, numfacets);+ break;+ case qh_PRINTmathematica:+ case qh_PRINTmaple:+ if (qh->hull_dim > 3) /* qh_initbuffers also checks */+ goto LABELnoformat;+ if (qh->VORONOI)+ qh_fprintf(qh, qh->ferr, 7054, "qhull warning: output is the Delaunay triangulation\n");+ if (format == qh_PRINTmaple) {+ if (qh->hull_dim == 2)+ qh_fprintf(qh, fp, 9054, "PLOT(CURVES(\n");+ else+ qh_fprintf(qh, fp, 9055, "PLOT3D(POLYGONS(\n");+ }else+ qh_fprintf(qh, fp, 9056, "{\n");+ qh->printoutvar= 0; /* counts number of facets for notfirst */+ break;+ case qh_PRINTmerges:+ qh_fprintf(qh, fp, 9057, "%d\n", numfacets);+ break;+ case qh_PRINTpointintersect:+ qh_fprintf(qh, fp, 9058, "%d\n%d\n", qh->hull_dim, numfacets);+ break;+ case qh_PRINTneighbors:+ qh_fprintf(qh, fp, 9059, "%d\n", numfacets);+ break;+ case qh_PRINToff:+ case qh_PRINTtriangles:+ if (qh->VORONOI)+ goto LABELnoformat;+ num = qh->hull_dim;+ if (format == qh_PRINToff || qh->hull_dim == 2)+ qh_fprintf(qh, fp, 9060, "%d\n%d %d %d\n", num,+ qh->num_points+qh_setsize(qh, qh->other_points), numfacets, totneighbors/2);+ else { /* qh_PRINTtriangles */+ qh->printoutvar= qh->num_points+qh_setsize(qh, qh->other_points); /* first centrum */+ if (qh->DELAUNAY)+ num--; /* drop last dimension */+ qh_fprintf(qh, fp, 9061, "%d\n%d %d %d\n", num, qh->printoutvar+ + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);+ }+ FORALLpoints+ qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);+ FOREACHpoint_(qh->other_points)+ qh_printpointid(qh, qh->fout, NULL, num, point, qh_IDunknown);+ if (format == qh_PRINTtriangles && qh->hull_dim > 2) {+ FORALLfacets {+ if (!facet->simplicial && facet->visitid)+ qh_printcenter(qh, qh->fout, format, NULL, facet);+ }+ }+ break;+ case qh_PRINTpointnearest:+ qh_fprintf(qh, fp, 9062, "%d\n", numcoplanars);+ break;+ case qh_PRINTpoints:+ if (!qh->VORONOI)+ goto LABELnoformat;+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,+ qh->qhull_command, numfacets, qh->hull_dim);+ else+ qh_fprintf(qh, fp, 9064, "%d\n%d\n", qh->hull_dim-1, numfacets);+ break;+ case qh_PRINTvertices:+ qh_fprintf(qh, fp, 9065, "%d\n", numfacets);+ break;+ case qh_PRINTsummary:+ default:+ LABELnoformat:+ qh_fprintf(qh, qh->ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",+ qh->hull_dim);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+} /* printbegin */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printcenter">-</a>++ qh_printcenter(qh, fp, string, facet )+ print facet->center as centrum or Voronoi center+ string may be NULL. Don't include '%' codes.+ nop if qh->CENTERtype neither CENTERvoronoi nor CENTERcentrum+ if upper envelope of Delaunay triangulation and point at-infinity+ prints qh_INFINITE instead;++ notes:+ defines facet->center if needed+ if format=PRINTgeom, adds a 0 if would otherwise be 2-d+ Same as QhullFacet::printCenter+*/+void qh_printcenter(qhT *qh, FILE *fp, qh_PRINT format, const char *string, facetT *facet) {+ int k, num;++ if (qh->CENTERtype != qh_ASvoronoi && qh->CENTERtype != qh_AScentrum)+ return;+ if (string)+ qh_fprintf(qh, fp, 9066, string);+ if (qh->CENTERtype == qh_ASvoronoi) {+ num= qh->hull_dim-1;+ if (!facet->normal || !facet->upperdelaunay || !qh->ATinfinity) {+ if (!facet->center)+ facet->center= qh_facetcenter(qh, facet->vertices);+ for (k=0; k < num; k++)+ qh_fprintf(qh, fp, 9067, qh_REAL_1, facet->center[k]);+ }else {+ for (k=0; k < num; k++)+ qh_fprintf(qh, fp, 9068, qh_REAL_1, qh_INFINITE);+ }+ }else /* qh->CENTERtype == qh_AScentrum */ {+ num= qh->hull_dim;+ if (format == qh_PRINTtriangles && qh->DELAUNAY)+ num--;+ if (!facet->center)+ facet->center= qh_getcentrum(qh, facet);+ for (k=0; k < num; k++)+ qh_fprintf(qh, fp, 9069, qh_REAL_1, facet->center[k]);+ }+ if (format == qh_PRINTgeom && num == 2)+ qh_fprintf(qh, fp, 9070, " 0\n");+ else+ qh_fprintf(qh, fp, 9071, "\n");+} /* printcenter */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printcentrum">-</a>++ qh_printcentrum(qh, fp, facet, radius )+ print centrum for a facet in OOGL format+ radius defines size of centrum+ 2-d or 3-d only++ returns:+ defines facet->center if needed+*/+void qh_printcentrum(qhT *qh, FILE *fp, facetT *facet, realT radius) {+ pointT *centrum, *projpt;+ boolT tempcentrum= False;+ realT xaxis[4], yaxis[4], normal[4], dist;+ realT green[3]={0, 1, 0};+ vertexT *apex;+ int k;++ if (qh->CENTERtype == qh_AScentrum) {+ if (!facet->center)+ facet->center= qh_getcentrum(qh, facet);+ centrum= facet->center;+ }else {+ centrum= qh_getcentrum(qh, facet);+ tempcentrum= True;+ }+ qh_fprintf(qh, fp, 9072, "{appearance {-normal -edge normscale 0} ");+ if (qh->firstcentrum) {+ qh->firstcentrum= False;+ qh_fprintf(qh, fp, 9073, "{INST geom { define centrum CQUAD # f%d\n\+-0.3 -0.3 0.0001 0 0 1 1\n\+ 0.3 -0.3 0.0001 0 0 1 1\n\+ 0.3 0.3 0.0001 0 0 1 1\n\+-0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);+ }else+ qh_fprintf(qh, fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id);+ apex= SETfirstt_(facet->vertices, vertexT);+ qh_distplane(qh, apex->point, facet, &dist);+ projpt= qh_projectpoint(qh, apex->point, facet, dist);+ for (k=qh->hull_dim; k--; ) {+ xaxis[k]= projpt[k] - centrum[k];+ normal[k]= facet->normal[k];+ }+ if (qh->hull_dim == 2) {+ xaxis[2]= 0;+ normal[2]= 0;+ }else if (qh->hull_dim == 4) {+ qh_projectdim3(qh, xaxis, xaxis);+ qh_projectdim3(qh, normal, normal);+ qh_normalize2(qh, normal, qh->PRINTdim, True, NULL, NULL);+ }+ qh_crossproduct(3, xaxis, normal, yaxis);+ qh_fprintf(qh, fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);+ qh_fprintf(qh, fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);+ qh_fprintf(qh, fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);+ qh_printpoint3(qh, fp, centrum);+ qh_fprintf(qh, fp, 9078, "1 }}}\n");+ qh_memfree(qh, projpt, qh->normal_size);+ qh_printpointvect(qh, fp, centrum, facet->normal, NULL, radius, green);+ if (tempcentrum)+ qh_memfree(qh, centrum, qh->normal_size);+} /* printcentrum */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printend">-</a>++ qh_printend(qh, fp, format )+ prints trailer for all output formats++ see:+ qh_printbegin() and qh_printafacet()++*/+void qh_printend(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {+ int num;+ facetT *facet, **facetp;++ if (!qh->printoutnum)+ qh_fprintf(qh, qh->ferr, 7055, "qhull warning: no facets printed\n");+ switch (format) {+ case qh_PRINTgeom:+ if (qh->hull_dim == 4 && qh->DROPdim < 0 && !qh->PRINTnoplanes) {+ qh->visit_id++;+ num= 0;+ FORALLfacet_(facetlist)+ qh_printend4geom(qh, fp, facet,&num, printall);+ FOREACHfacet_(facets)+ qh_printend4geom(qh, fp, facet, &num, printall);+ if (num != qh->ridgeoutnum || qh->printoutvar != qh->ridgeoutnum) {+ qh_fprintf(qh, qh->ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh->ridgeoutnum, qh->printoutvar, num);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ }else+ qh_fprintf(qh, fp, 9079, "}\n");+ break;+ case qh_PRINTinner:+ case qh_PRINTnormals:+ case qh_PRINTouter:+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9080, "end\n");+ break;+ case qh_PRINTmaple:+ qh_fprintf(qh, fp, 9081, "));\n");+ break;+ case qh_PRINTmathematica:+ qh_fprintf(qh, fp, 9082, "}\n");+ break;+ case qh_PRINTpoints:+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9083, "end\n");+ break;+ default:+ break;+ }+} /* printend */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printend4geom">-</a>++ qh_printend4geom(qh, fp, facet, numridges, printall )+ helper function for qh_printbegin/printend++ returns:+ number of printed ridges++ notes:+ just counts printed ridges if fp=NULL+ uses facet->visitid+ must agree with qh_printfacet4geom...++ design:+ computes color for facet from its normal+ prints each ridge of facet+*/+void qh_printend4geom(qhT *qh, FILE *fp, facetT *facet, int *nump, boolT printall) {+ realT color[3];+ int i, num= *nump;+ facetT *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;++ if (!printall && qh_skipfacet(qh, facet))+ return;+ if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))+ return;+ if (!facet->normal)+ return;+ if (fp) {+ for (i=0; i < 3; i++) {+ color[i]= (facet->normal[i]+1.0)/2.0;+ maximize_(color[i], -1.0);+ minimize_(color[i], +1.0);+ }+ }+ facet->visitid= qh->visit_id;+ if (facet->simplicial) {+ FOREACHneighbor_(facet) {+ if (neighbor->visitid != qh->visit_id) {+ if (fp)+ qh_fprintf(qh, fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",+ 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],+ facet->id, neighbor->id);+ num++;+ }+ }+ }else {+ FOREACHridge_(facet->ridges) {+ neighbor= otherfacet_(ridge, facet);+ if (neighbor->visitid != qh->visit_id) {+ if (fp)+ qh_fprintf(qh, fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",+ 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],+ ridge->id, facet->id, neighbor->id);+ num++;+ }+ }+ }+ *nump= num;+} /* printend4geom */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printextremes">-</a>++ qh_printextremes(qh, fp, facetlist, facets, printall )+ print extreme points for convex hulls or halfspace intersections++ notes:+ #points, followed by ids, one per line++ sorted by id+ same order as qh_printpoints_out if no coplanar/interior points+*/+void qh_printextremes(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {+ setT *vertices, *points;+ pointT *point;+ vertexT *vertex, **vertexp;+ int id;+ int numpoints=0, point_i, point_n;+ int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);++ points= qh_settemp(qh, allpoints);+ qh_setzero(qh, points, 0, allpoints);+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ FOREACHvertex_(vertices) {+ id= qh_pointid(qh, vertex->point);+ if (id >= 0) {+ SETelem_(points, id)= vertex->point;+ numpoints++;+ }+ }+ qh_settempfree(qh, &vertices);+ qh_fprintf(qh, fp, 9086, "%d\n", numpoints);+ FOREACHpoint_i_(qh, points) {+ if (point)+ qh_fprintf(qh, fp, 9087, "%d\n", point_i);+ }+ qh_settempfree(qh, &points);+} /* printextremes */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printextremes_2d">-</a>++ qh_printextremes_2d(qh, fp, facetlist, facets, printall )+ prints point ids for facets in qh_ORIENTclock order++ notes:+ #points, followed by ids, one per line+ if facetlist/facets are disjoint than the output includes skips+ errors if facets form a loop+ does not print coplanar points+*/+void qh_printextremes_2d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {+ int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;+ setT *vertices;+ facetT *facet, *startfacet, *nextfacet;+ vertexT *vertexA, *vertexB;++ qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,+ &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh->visit_id */+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ qh_fprintf(qh, fp, 9088, "%d\n", qh_setsize(qh, vertices));+ qh_settempfree(qh, &vertices);+ if (!numfacets)+ return;+ facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);+ qh->vertex_visit++;+ qh->visit_id++;+ do {+ if (facet->toporient ^ qh_ORIENTclock) {+ vertexA= SETfirstt_(facet->vertices, vertexT);+ vertexB= SETsecondt_(facet->vertices, vertexT);+ nextfacet= SETfirstt_(facet->neighbors, facetT);+ }else {+ vertexA= SETsecondt_(facet->vertices, vertexT);+ vertexB= SETfirstt_(facet->vertices, vertexT);+ nextfacet= SETsecondt_(facet->neighbors, facetT);+ }+ if (facet->visitid == qh->visit_id) {+ qh_fprintf(qh, qh->ferr, 6218, "Qhull internal error (qh_printextremes_2d): loop in facet list. facet %d nextfacet %d\n",+ facet->id, nextfacet->id);+ qh_errexit2(qh, qh_ERRqhull, facet, nextfacet);+ }+ if (facet->visitid) {+ if (vertexA->visitid != qh->vertex_visit) {+ vertexA->visitid= qh->vertex_visit;+ qh_fprintf(qh, fp, 9089, "%d\n", qh_pointid(qh, vertexA->point));+ }+ if (vertexB->visitid != qh->vertex_visit) {+ vertexB->visitid= qh->vertex_visit;+ qh_fprintf(qh, fp, 9090, "%d\n", qh_pointid(qh, vertexB->point));+ }+ }+ facet->visitid= qh->visit_id;+ facet= nextfacet;+ }while (facet && facet != startfacet);+} /* printextremes_2d */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printextremes_d">-</a>++ qh_printextremes_d(qh, fp, facetlist, facets, printall )+ print extreme points of input sites for Delaunay triangulations++ notes:+ #points, followed by ids, one per line++ unordered+*/+void qh_printextremes_d(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {+ setT *vertices;+ vertexT *vertex, **vertexp;+ boolT upperseen, lowerseen;+ facetT *neighbor, **neighborp;+ int numpoints=0;++ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ qh_vertexneighbors(qh);+ FOREACHvertex_(vertices) {+ upperseen= lowerseen= False;+ FOREACHneighbor_(vertex) {+ if (neighbor->upperdelaunay)+ upperseen= True;+ else+ lowerseen= True;+ }+ if (upperseen && lowerseen) {+ vertex->seen= True;+ numpoints++;+ }else+ vertex->seen= False;+ }+ qh_fprintf(qh, fp, 9091, "%d\n", numpoints);+ FOREACHvertex_(vertices) {+ if (vertex->seen)+ qh_fprintf(qh, fp, 9092, "%d\n", qh_pointid(qh, vertex->point));+ }+ qh_settempfree(qh, &vertices);+} /* printextremes_d */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet">-</a>++ qh_printfacet(qh, fp, facet )+ prints all fields of a facet to fp++ notes:+ ridges printed in neighbor order+*/+void qh_printfacet(qhT *qh, FILE *fp, facetT *facet) {++ qh_printfacetheader(qh, fp, facet);+ if (facet->ridges)+ qh_printfacetridges(qh, fp, facet);+} /* printfacet */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet2geom">-</a>++ qh_printfacet2geom(qh, fp, facet, color )+ print facet as part of a 2-d VECT for Geomview++ notes:+ assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon+ mindist is calculated within io_r.c. maxoutside is calculated elsewhere+ so a DISTround error may have occurred.+*/+void qh_printfacet2geom(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {+ pointT *point0, *point1;+ realT mindist, innerplane, outerplane;+ int k;++ qh_facet2point(qh, facet, &point0, &point1, &mindist);+ qh_geomplanes(qh, facet, &outerplane, &innerplane);+ if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))+ qh_printfacet2geom_points(qh, fp, point0, point1, facet, outerplane, color);+ if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&+ outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {+ for (k=3; k--; )+ color[k]= 1.0 - color[k];+ qh_printfacet2geom_points(qh, fp, point0, point1, facet, innerplane, color);+ }+ qh_memfree(qh, point1, qh->normal_size);+ qh_memfree(qh, point0, qh->normal_size);+} /* printfacet2geom */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet2geom_points">-</a>++ qh_printfacet2geom_points(qh, fp, point1, point2, facet, offset, color )+ prints a 2-d facet as a VECT with 2 points at some offset.+ The points are on the facet's plane.+*/+void qh_printfacet2geom_points(qhT *qh, FILE *fp, pointT *point1, pointT *point2,+ facetT *facet, realT offset, realT color[3]) {+ pointT *p1= point1, *p2= point2;++ qh_fprintf(qh, fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id);+ if (offset != 0.0) {+ p1= qh_projectpoint(qh, p1, facet, -offset);+ p2= qh_projectpoint(qh, p2, facet, -offset);+ }+ qh_fprintf(qh, fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",+ p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);+ if (offset != 0.0) {+ qh_memfree(qh, p1, qh->normal_size);+ qh_memfree(qh, p2, qh->normal_size);+ }+ qh_fprintf(qh, fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);+} /* printfacet2geom_points */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet2math">-</a>++ qh_printfacet2math(qh, fp, facet, format, notfirst )+ print 2-d Maple or Mathematica output for a facet+ may be non-simplicial++ notes:+ use %16.8f since Mathematica 2.2 does not handle exponential format+ see qh_printfacet3math+*/+void qh_printfacet2math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {+ pointT *point0, *point1;+ realT mindist;+ const char *pointfmt;++ qh_facet2point(qh, facet, &point0, &point1, &mindist);+ if (notfirst)+ qh_fprintf(qh, fp, 9096, ",");+ if (format == qh_PRINTmaple)+ pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";+ else+ pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";+ qh_fprintf(qh, fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]);+ qh_memfree(qh, point1, qh->normal_size);+ qh_memfree(qh, point0, qh->normal_size);+} /* printfacet2math */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>++ qh_printfacet3geom_nonsimplicial(qh, fp, facet, color )+ print Geomview OFF for a 3-d nonsimplicial facet.+ if DOintersections, prints ridges to unvisited neighbors(qh->visit_id)++ notes+ uses facet->visitid for intersections and ridges+*/+void qh_printfacet3geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {+ ridgeT *ridge, **ridgep;+ setT *projectedpoints, *vertices;+ vertexT *vertex, **vertexp, *vertexA, *vertexB;+ pointT *projpt, *point, **pointp;+ facetT *neighbor;+ realT dist, outerplane, innerplane;+ int cntvertices, k;+ realT black[3]={0, 0, 0}, green[3]={0, 1, 0};++ qh_geomplanes(qh, facet, &outerplane, &innerplane);+ vertices= qh_facet3vertex(qh, facet); /* oriented */+ cntvertices= qh_setsize(qh, vertices);+ projectedpoints= qh_settemp(qh, cntvertices);+ FOREACHvertex_(vertices) {+ zinc_(Zdistio);+ qh_distplane(qh, vertex->point, facet, &dist);+ projpt= qh_projectpoint(qh, vertex->point, facet, dist);+ qh_setappend(qh, &projectedpoints, projpt);+ }+ if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))+ qh_printfacet3geom_points(qh, fp, projectedpoints, facet, outerplane, color);+ if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&+ outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {+ for (k=3; k--; )+ color[k]= 1.0 - color[k];+ qh_printfacet3geom_points(qh, fp, projectedpoints, facet, innerplane, color);+ }+ FOREACHpoint_(projectedpoints)+ qh_memfree(qh, point, qh->normal_size);+ qh_settempfree(qh, &projectedpoints);+ qh_settempfree(qh, &vertices);+ if ((qh->DOintersections || qh->PRINTridges)+ && (!facet->visible || !qh->NEWfacets)) {+ facet->visitid= qh->visit_id;+ FOREACHridge_(facet->ridges) {+ neighbor= otherfacet_(ridge, facet);+ if (neighbor->visitid != qh->visit_id) {+ if (qh->DOintersections)+ qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, black);+ if (qh->PRINTridges) {+ vertexA= SETfirstt_(ridge->vertices, vertexT);+ vertexB= SETsecondt_(ridge->vertices, vertexT);+ qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);+ }+ }+ }+ }+} /* printfacet3geom_nonsimplicial */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet3geom_points">-</a>++ qh_printfacet3geom_points(qh, fp, points, facet, offset )+ prints a 3-d facet as OFF Geomview object.+ offset is relative to the facet's hyperplane+ Facet is determined as a list of points+*/+void qh_printfacet3geom_points(qhT *qh, FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {+ int k, n= qh_setsize(qh, points), i;+ pointT *point, **pointp;+ setT *printpoints;++ qh_fprintf(qh, fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id);+ if (offset != 0.0) {+ printpoints= qh_settemp(qh, n);+ FOREACHpoint_(points)+ qh_setappend(qh, &printpoints, qh_projectpoint(qh, point, facet, -offset));+ }else+ printpoints= points;+ FOREACHpoint_(printpoints) {+ for (k=0; k < qh->hull_dim; k++) {+ if (k == qh->DROPdim)+ qh_fprintf(qh, fp, 9099, "0 ");+ else+ qh_fprintf(qh, fp, 9100, "%8.4g ", point[k]);+ }+ if (printpoints != points)+ qh_memfree(qh, point, qh->normal_size);+ qh_fprintf(qh, fp, 9101, "\n");+ }+ if (printpoints != points)+ qh_settempfree(qh, &printpoints);+ qh_fprintf(qh, fp, 9102, "%d ", n);+ for (i=0; i < n; i++)+ qh_fprintf(qh, fp, 9103, "%d ", i);+ qh_fprintf(qh, fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);+} /* printfacet3geom_points */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>++ qh_printfacet3geom_simplicial(qh, )+ print Geomview OFF for a 3-d simplicial facet.++ notes:+ may flip color+ uses facet->visitid for intersections and ridges++ assume precise calculations in io_r.c with roundoff covered by qh_GEOMepsilon+ innerplane may be off by qh->DISTround. Maxoutside is calculated elsewhere+ so a DISTround error may have occurred.+*/+void qh_printfacet3geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {+ setT *points, *vertices;+ vertexT *vertex, **vertexp, *vertexA, *vertexB;+ facetT *neighbor, **neighborp;+ realT outerplane, innerplane;+ realT black[3]={0, 0, 0}, green[3]={0, 1, 0};+ int k;++ qh_geomplanes(qh, facet, &outerplane, &innerplane);+ vertices= qh_facet3vertex(qh, facet);+ points= qh_settemp(qh, qh->TEMPsize);+ FOREACHvertex_(vertices)+ qh_setappend(qh, &points, vertex->point);+ if (qh->PRINTouter || (!qh->PRINTnoplanes && !qh->PRINTinner))+ qh_printfacet3geom_points(qh, fp, points, facet, outerplane, color);+ if (qh->PRINTinner || (!qh->PRINTnoplanes && !qh->PRINTouter &&+ outerplane - innerplane > 2 * qh->MAXabs_coord * qh_GEOMepsilon)) {+ for (k=3; k--; )+ color[k]= 1.0 - color[k];+ qh_printfacet3geom_points(qh, fp, points, facet, innerplane, color);+ }+ qh_settempfree(qh, &points);+ qh_settempfree(qh, &vertices);+ if ((qh->DOintersections || qh->PRINTridges)+ && (!facet->visible || !qh->NEWfacets)) {+ facet->visitid= qh->visit_id;+ FOREACHneighbor_(facet) {+ if (neighbor->visitid != qh->visit_id) {+ vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,+ SETindex_(facet->neighbors, neighbor), 0);+ if (qh->DOintersections)+ qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, black);+ if (qh->PRINTridges) {+ vertexA= SETfirstt_(vertices, vertexT);+ vertexB= SETsecondt_(vertices, vertexT);+ qh_printline3geom(qh, fp, vertexA->point, vertexB->point, green);+ }+ qh_setfree(qh, &vertices);+ }+ }+ }+} /* printfacet3geom_simplicial */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet3math">-</a>++ qh_printfacet3math(qh, fp, facet, notfirst )+ print 3-d Maple or Mathematica output for a facet++ notes:+ may be non-simplicial+ use %16.8f since Mathematica 2.2 does not handle exponential format+ see qh_printfacet2math+*/+void qh_printfacet3math(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format, int notfirst) {+ vertexT *vertex, **vertexp;+ setT *points, *vertices;+ pointT *point, **pointp;+ boolT firstpoint= True;+ realT dist;+ const char *pointfmt, *endfmt;++ if (notfirst)+ qh_fprintf(qh, fp, 9105, ",\n");+ vertices= qh_facet3vertex(qh, facet);+ points= qh_settemp(qh, qh_setsize(qh, vertices));+ FOREACHvertex_(vertices) {+ zinc_(Zdistio);+ qh_distplane(qh, vertex->point, facet, &dist);+ point= qh_projectpoint(qh, vertex->point, facet, dist);+ qh_setappend(qh, &points, point);+ }+ if (format == qh_PRINTmaple) {+ qh_fprintf(qh, fp, 9106, "[");+ pointfmt= "[%16.8f, %16.8f, %16.8f]";+ endfmt= "]";+ }else {+ qh_fprintf(qh, fp, 9107, "Polygon[{");+ pointfmt= "{%16.8f, %16.8f, %16.8f}";+ endfmt= "}]";+ }+ FOREACHpoint_(points) {+ if (firstpoint)+ firstpoint= False;+ else+ qh_fprintf(qh, fp, 9108, ",\n");+ qh_fprintf(qh, fp, 9109, pointfmt, point[0], point[1], point[2]);+ }+ FOREACHpoint_(points)+ qh_memfree(qh, point, qh->normal_size);+ qh_settempfree(qh, &points);+ qh_settempfree(qh, &vertices);+ qh_fprintf(qh, fp, 9110, "%s", endfmt);+} /* printfacet3math */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet3vertex">-</a>++ qh_printfacet3vertex(qh, fp, facet, format )+ print vertices in a 3-d facet as point ids++ notes:+ prints number of vertices first if format == qh_PRINToff+ the facet may be non-simplicial+*/+void qh_printfacet3vertex(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {+ vertexT *vertex, **vertexp;+ setT *vertices;++ vertices= qh_facet3vertex(qh, facet);+ if (format == qh_PRINToff)+ qh_fprintf(qh, fp, 9111, "%d ", qh_setsize(qh, vertices));+ FOREACHvertex_(vertices)+ qh_fprintf(qh, fp, 9112, "%d ", qh_pointid(qh, vertex->point));+ qh_fprintf(qh, fp, 9113, "\n");+ qh_settempfree(qh, &vertices);+} /* printfacet3vertex */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>++ qh_printfacet4geom_nonsimplicial(qh, )+ print Geomview 4OFF file for a 4d nonsimplicial facet+ prints all ridges to unvisited neighbors (qh.visit_id)+ if qh.DROPdim+ prints in OFF format++ notes:+ must agree with printend4geom()+*/+void qh_printfacet4geom_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {+ facetT *neighbor;+ ridgeT *ridge, **ridgep;+ vertexT *vertex, **vertexp;+ pointT *point;+ int k;+ realT dist;++ facet->visitid= qh->visit_id;+ if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))+ return;+ FOREACHridge_(facet->ridges) {+ neighbor= otherfacet_(ridge, facet);+ if (neighbor->visitid == qh->visit_id)+ continue;+ if (qh->PRINTtransparent && !neighbor->good)+ continue;+ if (qh->DOintersections)+ qh_printhyperplaneintersection(qh, fp, facet, neighbor, ridge->vertices, color);+ else {+ if (qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9114, "OFF 3 1 1 # f%d\n", facet->id);+ else {+ qh->printoutvar++;+ qh_fprintf(qh, fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);+ }+ FOREACHvertex_(ridge->vertices) {+ zinc_(Zdistio);+ qh_distplane(qh, vertex->point,facet, &dist);+ point=qh_projectpoint(qh, vertex->point,facet, dist);+ for (k=0; k < qh->hull_dim; k++) {+ if (k != qh->DROPdim)+ qh_fprintf(qh, fp, 9116, "%8.4g ", point[k]);+ }+ qh_fprintf(qh, fp, 9117, "\n");+ qh_memfree(qh, point, qh->normal_size);+ }+ if (qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);+ }+ }+} /* printfacet4geom_nonsimplicial */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>++ qh_printfacet4geom_simplicial(qh, fp, facet, color )+ print Geomview 4OFF file for a 4d simplicial facet+ prints triangles for unvisited neighbors (qh.visit_id)++ notes:+ must agree with printend4geom()+*/+void qh_printfacet4geom_simplicial(qhT *qh, FILE *fp, facetT *facet, realT color[3]) {+ setT *vertices;+ facetT *neighbor, **neighborp;+ vertexT *vertex, **vertexp;+ int k;++ facet->visitid= qh->visit_id;+ if (qh->PRINTnoplanes || (facet->visible && qh->NEWfacets))+ return;+ FOREACHneighbor_(facet) {+ if (neighbor->visitid == qh->visit_id)+ continue;+ if (qh->PRINTtransparent && !neighbor->good)+ continue;+ vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,+ SETindex_(facet->neighbors, neighbor), 0);+ if (qh->DOintersections)+ qh_printhyperplaneintersection(qh, fp, facet, neighbor, vertices, color);+ else {+ if (qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n",+ facet->id, neighbor->id);+ else {+ qh->printoutvar++;+ qh_fprintf(qh, fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id);+ }+ FOREACHvertex_(vertices) {+ for (k=0; k < qh->hull_dim; k++) {+ if (k != qh->DROPdim)+ qh_fprintf(qh, fp, 9121, "%8.4g ", vertex->point[k]);+ }+ qh_fprintf(qh, fp, 9122, "\n");+ }+ if (qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);+ }+ qh_setfree(qh, &vertices);+ }+} /* printfacet4geom_simplicial */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>++ qh_printfacetNvertex_nonsimplicial(qh, fp, facet, id, format )+ print vertices for an N-d non-simplicial facet+ triangulates each ridge to the id+*/+void qh_printfacetNvertex_nonsimplicial(qhT *qh, FILE *fp, facetT *facet, int id, qh_PRINT format) {+ vertexT *vertex, **vertexp;+ ridgeT *ridge, **ridgep;++ if (facet->visible && qh->NEWfacets)+ return;+ FOREACHridge_(facet->ridges) {+ if (format == qh_PRINTtriangles)+ qh_fprintf(qh, fp, 9124, "%d ", qh->hull_dim);+ qh_fprintf(qh, fp, 9125, "%d ", id);+ if ((ridge->top == facet) ^ qh_ORIENTclock) {+ FOREACHvertex_(ridge->vertices)+ qh_fprintf(qh, fp, 9126, "%d ", qh_pointid(qh, vertex->point));+ }else {+ FOREACHvertexreverse12_(ridge->vertices)+ qh_fprintf(qh, fp, 9127, "%d ", qh_pointid(qh, vertex->point));+ }+ qh_fprintf(qh, fp, 9128, "\n");+ }+} /* printfacetNvertex_nonsimplicial */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>++ qh_printfacetNvertex_simplicial(qh, fp, facet, format )+ print vertices for an N-d simplicial facet+ prints vertices for non-simplicial facets+ 2-d facets (orientation preserved by qh_mergefacet2d)+ PRINToff ('o') for 4-d and higher+*/+void qh_printfacetNvertex_simplicial(qhT *qh, FILE *fp, facetT *facet, qh_PRINT format) {+ vertexT *vertex, **vertexp;++ if (format == qh_PRINToff || format == qh_PRINTtriangles)+ qh_fprintf(qh, fp, 9129, "%d ", qh_setsize(qh, facet->vertices));+ if ((facet->toporient ^ qh_ORIENTclock)+ || (qh->hull_dim > 2 && !facet->simplicial)) {+ FOREACHvertex_(facet->vertices)+ qh_fprintf(qh, fp, 9130, "%d ", qh_pointid(qh, vertex->point));+ }else {+ FOREACHvertexreverse12_(facet->vertices)+ qh_fprintf(qh, fp, 9131, "%d ", qh_pointid(qh, vertex->point));+ }+ qh_fprintf(qh, fp, 9132, "\n");+} /* printfacetNvertex_simplicial */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacetheader">-</a>++ qh_printfacetheader(qh, fp, facet )+ prints header fields of a facet to fp++ notes:+ for 'f' output and debugging+ Same as QhullFacet::printHeader()+*/+void qh_printfacetheader(qhT *qh, FILE *fp, facetT *facet) {+ pointT *point, **pointp, *furthest;+ facetT *neighbor, **neighborp;+ realT dist;++ if (facet == qh_MERGEridge) {+ qh_fprintf(qh, fp, 9133, " MERGEridge\n");+ return;+ }else if (facet == qh_DUPLICATEridge) {+ qh_fprintf(qh, fp, 9134, " DUPLICATEridge\n");+ return;+ }else if (!facet) {+ qh_fprintf(qh, fp, 9135, " NULLfacet\n");+ return;+ }+ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ qh_fprintf(qh, fp, 9136, "- f%d\n", facet->id);+ qh_fprintf(qh, fp, 9137, " - flags:");+ if (facet->toporient)+ qh_fprintf(qh, fp, 9138, " top");+ else+ qh_fprintf(qh, fp, 9139, " bottom");+ if (facet->simplicial)+ qh_fprintf(qh, fp, 9140, " simplicial");+ if (facet->tricoplanar)+ qh_fprintf(qh, fp, 9141, " tricoplanar");+ if (facet->upperdelaunay)+ qh_fprintf(qh, fp, 9142, " upperDelaunay");+ if (facet->visible)+ qh_fprintf(qh, fp, 9143, " visible");+ if (facet->newfacet)+ qh_fprintf(qh, fp, 9144, " new");+ if (facet->tested)+ qh_fprintf(qh, fp, 9145, " tested");+ if (!facet->good)+ qh_fprintf(qh, fp, 9146, " notG");+ if (facet->seen)+ qh_fprintf(qh, fp, 9147, " seen");+ if (facet->coplanar)+ qh_fprintf(qh, fp, 9148, " coplanar");+ if (facet->mergehorizon)+ qh_fprintf(qh, fp, 9149, " mergehorizon");+ if (facet->keepcentrum)+ qh_fprintf(qh, fp, 9150, " keepcentrum");+ if (facet->dupridge)+ qh_fprintf(qh, fp, 9151, " dupridge");+ if (facet->mergeridge && !facet->mergeridge2)+ qh_fprintf(qh, fp, 9152, " mergeridge1");+ if (facet->mergeridge2)+ qh_fprintf(qh, fp, 9153, " mergeridge2");+ if (facet->newmerge)+ qh_fprintf(qh, fp, 9154, " newmerge");+ if (facet->flipped)+ qh_fprintf(qh, fp, 9155, " flipped");+ if (facet->notfurthest)+ qh_fprintf(qh, fp, 9156, " notfurthest");+ if (facet->degenerate)+ qh_fprintf(qh, fp, 9157, " degenerate");+ if (facet->redundant)+ qh_fprintf(qh, fp, 9158, " redundant");+ qh_fprintf(qh, fp, 9159, "\n");+ if (facet->isarea)+ qh_fprintf(qh, fp, 9160, " - area: %2.2g\n", facet->f.area);+ else if (qh->NEWfacets && facet->visible && facet->f.replace)+ qh_fprintf(qh, fp, 9161, " - replacement: f%d\n", facet->f.replace->id);+ else if (facet->newfacet) {+ if (facet->f.samecycle && facet->f.samecycle != facet)+ qh_fprintf(qh, fp, 9162, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);+ }else if (facet->tricoplanar /* !isarea */) {+ if (facet->f.triowner)+ qh_fprintf(qh, fp, 9163, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);+ }else if (facet->f.newcycle)+ qh_fprintf(qh, fp, 9164, " - was horizon to f%d\n", facet->f.newcycle->id);+ if (facet->nummerge)+ qh_fprintf(qh, fp, 9165, " - merges: %d\n", facet->nummerge);+ qh_printpointid(qh, fp, " - normal: ", qh->hull_dim, facet->normal, qh_IDunknown);+ qh_fprintf(qh, fp, 9166, " - offset: %10.7g\n", facet->offset);+ if (qh->CENTERtype == qh_ASvoronoi || facet->center)+ qh_printcenter(qh, fp, qh_PRINTfacets, " - center: ", facet);+#if qh_MAXoutside+ if (facet->maxoutside > qh->DISTround)+ qh_fprintf(qh, fp, 9167, " - maxoutside: %10.7g\n", facet->maxoutside);+#endif+ if (!SETempty_(facet->outsideset)) {+ furthest= (pointT*)qh_setlast(facet->outsideset);+ if (qh_setsize(qh, facet->outsideset) < 6) {+ qh_fprintf(qh, fp, 9168, " - outside set(furthest p%d):\n", qh_pointid(qh, furthest));+ FOREACHpoint_(facet->outsideset)+ qh_printpoint(qh, fp, " ", point);+ }else if (qh_setsize(qh, facet->outsideset) < 21) {+ qh_printpoints(qh, fp, " - outside set:", facet->outsideset);+ }else {+ qh_fprintf(qh, fp, 9169, " - outside set: %d points.", qh_setsize(qh, facet->outsideset));+ qh_printpoint(qh, fp, " Furthest", furthest);+ }+#if !qh_COMPUTEfurthest+ qh_fprintf(qh, fp, 9170, " - furthest distance= %2.2g\n", facet->furthestdist);+#endif+ }+ if (!SETempty_(facet->coplanarset)) {+ furthest= (pointT*)qh_setlast(facet->coplanarset);+ if (qh_setsize(qh, facet->coplanarset) < 6) {+ qh_fprintf(qh, fp, 9171, " - coplanar set(furthest p%d):\n", qh_pointid(qh, furthest));+ FOREACHpoint_(facet->coplanarset)+ qh_printpoint(qh, fp, " ", point);+ }else if (qh_setsize(qh, facet->coplanarset) < 21) {+ qh_printpoints(qh, fp, " - coplanar set:", facet->coplanarset);+ }else {+ qh_fprintf(qh, fp, 9172, " - coplanar set: %d points.", qh_setsize(qh, facet->coplanarset));+ qh_printpoint(qh, fp, " Furthest", furthest);+ }+ zinc_(Zdistio);+ qh_distplane(qh, furthest, facet, &dist);+ qh_fprintf(qh, fp, 9173, " furthest distance= %2.2g\n", dist);+ }+ qh_printvertices(qh, fp, " - vertices:", facet->vertices);+ qh_fprintf(qh, fp, 9174, " - neighboring facets:");+ FOREACHneighbor_(facet) {+ if (neighbor == qh_MERGEridge)+ qh_fprintf(qh, fp, 9175, " MERGE");+ else if (neighbor == qh_DUPLICATEridge)+ qh_fprintf(qh, fp, 9176, " DUP");+ else+ qh_fprintf(qh, fp, 9177, " f%d", neighbor->id);+ }+ qh_fprintf(qh, fp, 9178, "\n");+ qh->RANDOMdist= qh->old_randomdist;+} /* printfacetheader */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacetridges">-</a>++ qh_printfacetridges(qh, fp, facet )+ prints ridges of a facet to fp++ notes:+ ridges printed in neighbor order+ assumes the ridges exist+ for 'f' output+ same as QhullFacet::printRidges+*/+void qh_printfacetridges(qhT *qh, FILE *fp, facetT *facet) {+ facetT *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;+ int numridges= 0;+++ if (facet->visible && qh->NEWfacets) {+ qh_fprintf(qh, fp, 9179, " - ridges(ids may be garbage):");+ FOREACHridge_(facet->ridges)+ qh_fprintf(qh, fp, 9180, " r%d", ridge->id);+ qh_fprintf(qh, fp, 9181, "\n");+ }else {+ qh_fprintf(qh, fp, 9182, " - ridges:\n");+ FOREACHridge_(facet->ridges)+ ridge->seen= False;+ if (qh->hull_dim == 3) {+ ridge= SETfirstt_(facet->ridges, ridgeT);+ while (ridge && !ridge->seen) {+ ridge->seen= True;+ qh_printridge(qh, fp, ridge);+ numridges++;+ ridge= qh_nextridge3d(ridge, facet, NULL);+ }+ }else {+ FOREACHneighbor_(facet) {+ FOREACHridge_(facet->ridges) {+ if (otherfacet_(ridge,facet) == neighbor) {+ ridge->seen= True;+ qh_printridge(qh, fp, ridge);+ numridges++;+ }+ }+ }+ }+ if (numridges != qh_setsize(qh, facet->ridges)) {+ qh_fprintf(qh, fp, 9183, " - all ridges:");+ FOREACHridge_(facet->ridges)+ qh_fprintf(qh, fp, 9184, " r%d", ridge->id);+ qh_fprintf(qh, fp, 9185, "\n");+ }+ FOREACHridge_(facet->ridges) {+ if (!ridge->seen)+ qh_printridge(qh, fp, ridge);+ }+ }+} /* printfacetridges */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printfacets">-</a>++ qh_printfacets(qh, fp, format, facetlist, facets, printall )+ prints facetlist and/or facet set in output format++ notes:+ also used for specialized formats ('FO' and summary)+ turns off 'Rn' option since want actual numbers+*/+void qh_printfacets(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {+ int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;+ facetT *facet, **facetp;+ setT *vertices;+ coordT *center;+ realT outerplane, innerplane;++ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ if (qh->CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))+ qh_fprintf(qh, qh->ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");+ if (format == qh_PRINTnone)+ ; /* print nothing */+ else if (format == qh_PRINTaverage) {+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ center= qh_getcenter(qh, vertices);+ qh_fprintf(qh, fp, 9186, "%d 1\n", qh->hull_dim);+ qh_printpointid(qh, fp, NULL, qh->hull_dim, center, qh_IDunknown);+ qh_memfree(qh, center, qh->normal_size);+ qh_settempfree(qh, &vertices);+ }else if (format == qh_PRINTextremes) {+ if (qh->DELAUNAY)+ qh_printextremes_d(qh, fp, facetlist, facets, printall);+ else if (qh->hull_dim == 2)+ qh_printextremes_2d(qh, fp, facetlist, facets, printall);+ else+ qh_printextremes(qh, fp, facetlist, facets, printall);+ }else if (format == qh_PRINToptions)+ qh_fprintf(qh, fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);+ else if (format == qh_PRINTpoints && !qh->VORONOI)+ qh_printpoints_out(qh, fp, facetlist, facets, printall);+ else if (format == qh_PRINTqhull)+ qh_fprintf(qh, fp, 9188, "%s | %s\n", qh->rbox_command, qh->qhull_command);+ else if (format == qh_PRINTsize) {+ qh_fprintf(qh, fp, 9189, "0\n2 ");+ qh_fprintf(qh, fp, 9190, qh_REAL_1, qh->totarea);+ qh_fprintf(qh, fp, 9191, qh_REAL_1, qh->totvol);+ qh_fprintf(qh, fp, 9192, "\n");+ }else if (format == qh_PRINTsummary) {+ qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,+ &totneighbors, &numridges, &numcoplanars, &numtricoplanars);+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ qh_fprintf(qh, fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh->hull_dim,+ qh->num_points + qh_setsize(qh, qh->other_points),+ qh->num_vertices, qh->num_facets - qh->num_visible,+ qh_setsize(qh, vertices), numfacets, numcoplanars,+ numfacets - numsimplicial, zzval_(Zdelvertextot),+ numtricoplanars);+ qh_settempfree(qh, &vertices);+ qh_outerinner(qh, NULL, &outerplane, &innerplane);+ qh_fprintf(qh, fp, 9194, qh_REAL_2n, outerplane, innerplane);+ }else if (format == qh_PRINTvneighbors)+ qh_printvneighbors(qh, fp, facetlist, facets, printall);+ else if (qh->VORONOI && format == qh_PRINToff)+ qh_printvoronoi(qh, fp, format, facetlist, facets, printall);+ else if (qh->VORONOI && format == qh_PRINTgeom) {+ qh_printbegin(qh, fp, format, facetlist, facets, printall);+ qh_printvoronoi(qh, fp, format, facetlist, facets, printall);+ qh_printend(qh, fp, format, facetlist, facets, printall);+ }else if (qh->VORONOI+ && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))+ qh_printvdiagram(qh, fp, format, facetlist, facets, printall);+ else {+ qh_printbegin(qh, fp, format, facetlist, facets, printall);+ FORALLfacet_(facetlist)+ qh_printafacet(qh, fp, format, facet, printall);+ FOREACHfacet_(facets)+ qh_printafacet(qh, fp, format, facet, printall);+ qh_printend(qh, fp, format, facetlist, facets, printall);+ }+ qh->RANDOMdist= qh->old_randomdist;+} /* printfacets */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printhyperplaneintersection">-</a>++ qh_printhyperplaneintersection(qh, fp, facet1, facet2, vertices, color )+ print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d+*/+void qh_printhyperplaneintersection(qhT *qh, FILE *fp, facetT *facet1, facetT *facet2,+ setT *vertices, realT color[3]) {+ realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];+ vertexT *vertex, **vertexp;+ int i, k;+ boolT nearzero1, nearzero2;++ costheta= qh_getangle(qh, facet1->normal, facet2->normal);+ denominator= 1 - costheta * costheta;+ i= qh_setsize(qh, vertices);+ if (qh->hull_dim == 3)+ qh_fprintf(qh, fp, 9195, "VECT 1 %d 1 %d 1 ", i, i);+ else if (qh->hull_dim == 4 && qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9196, "OFF 3 1 1 ");+ else+ qh->printoutvar++;+ qh_fprintf(qh, fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id);+ mindenom= 1 / (10.0 * qh->MAXabs_coord);+ FOREACHvertex_(vertices) {+ zadd_(Zdistio, 2);+ qh_distplane(qh, vertex->point, facet1, &dist1);+ qh_distplane(qh, vertex->point, facet2, &dist2);+ s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);+ t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);+ if (nearzero1 || nearzero2)+ s= t= 0.0;+ for (k=qh->hull_dim; k--; )+ p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;+ if (qh->PRINTdim <= 3) {+ qh_projectdim3(qh, p, p);+ qh_fprintf(qh, fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);+ }else+ qh_fprintf(qh, fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);+ if (nearzero1+nearzero2)+ qh_fprintf(qh, fp, 9200, "p%d(coplanar facets)\n", qh_pointid(qh, vertex->point));+ else+ qh_fprintf(qh, fp, 9201, "projected p%d\n", qh_pointid(qh, vertex->point));+ }+ if (qh->hull_dim == 3)+ qh_fprintf(qh, fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);+ else if (qh->hull_dim == 4 && qh->DROPdim >= 0)+ qh_fprintf(qh, fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);+} /* printhyperplaneintersection */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printline3geom">-</a>++ qh_printline3geom(qh, fp, pointA, pointB, color )+ prints a line as a VECT+ prints 0's for qh.DROPdim++ notes:+ if pointA == pointB,+ it's a 1 point VECT+*/+void qh_printline3geom(qhT *qh, FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {+ int k;+ realT pA[4], pB[4];++ qh_projectdim3(qh, pointA, pA);+ qh_projectdim3(qh, pointB, pB);+ if ((fabs(pA[0] - pB[0]) > 1e-3) ||+ (fabs(pA[1] - pB[1]) > 1e-3) ||+ (fabs(pA[2] - pB[2]) > 1e-3)) {+ qh_fprintf(qh, fp, 9204, "VECT 1 2 1 2 1\n");+ for (k=0; k < 3; k++)+ qh_fprintf(qh, fp, 9205, "%8.4g ", pB[k]);+ qh_fprintf(qh, fp, 9206, " # p%d\n", qh_pointid(qh, pointB));+ }else+ qh_fprintf(qh, fp, 9207, "VECT 1 1 1 1 1\n");+ for (k=0; k < 3; k++)+ qh_fprintf(qh, fp, 9208, "%8.4g ", pA[k]);+ qh_fprintf(qh, fp, 9209, " # p%d\n", qh_pointid(qh, pointA));+ qh_fprintf(qh, fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);+}++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printneighborhood">-</a>++ qh_printneighborhood(qh, fp, format, facetA, facetB, printall )+ print neighborhood of one or two facets++ notes:+ calls qh_findgood_all()+ bumps qh.visit_id+*/+void qh_printneighborhood(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) {+ facetT *neighbor, **neighborp, *facet;+ setT *facets;++ if (format == qh_PRINTnone)+ return;+ qh_findgood_all(qh, qh->facet_list);+ if (facetA == facetB)+ facetB= NULL;+ facets= qh_settemp(qh, 2*(qh_setsize(qh, facetA->neighbors)+1));+ qh->visit_id++;+ for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {+ if (facet->visitid != qh->visit_id) {+ facet->visitid= qh->visit_id;+ qh_setappend(qh, &facets, facet);+ }+ FOREACHneighbor_(facet) {+ if (neighbor->visitid == qh->visit_id)+ continue;+ neighbor->visitid= qh->visit_id;+ if (printall || !qh_skipfacet(qh, neighbor))+ qh_setappend(qh, &facets, neighbor);+ }+ }+ qh_printfacets(qh, fp, format, NULL, facets, printall);+ qh_settempfree(qh, &facets);+} /* printneighborhood */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printpoint">-</a>++ qh_printpoint(qh, fp, string, point )+ qh_printpointid(qh, fp, string, dim, point, id )+ prints the coordinates of a point++ returns:+ if string is defined+ prints 'string p%d'. Skips p%d if id=qh_IDunknown(-1) or qh_IDnone(-3)++ notes:+ nop if point is NULL+ Same as QhullPoint's printPoint+*/+void qh_printpoint(qhT *qh, FILE *fp, const char *string, pointT *point) {+ int id= qh_pointid(qh, point);++ qh_printpointid(qh, fp, string, qh->hull_dim, point, id);+} /* printpoint */++void qh_printpointid(qhT *qh, FILE *fp, const char *string, int dim, pointT *point, int id) {+ int k;+ realT r; /*bug fix*/++ if (!point)+ return;+ if (string) {+ qh_fprintf(qh, fp, 9211, "%s", string);+ if (id != qh_IDunknown && id != qh_IDnone)+ qh_fprintf(qh, fp, 9212, " p%d: ", id);+ }+ for (k=dim; k--; ) {+ r= *point++;+ if (string)+ qh_fprintf(qh, fp, 9213, " %8.4g", r);+ else+ qh_fprintf(qh, fp, 9214, qh_REAL_1, r);+ }+ qh_fprintf(qh, fp, 9215, "\n");+} /* printpointid */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printpoint3">-</a>++ qh_printpoint3(qh, fp, point )+ prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates+*/+void qh_printpoint3(qhT *qh, FILE *fp, pointT *point) {+ int k;+ realT p[4];++ qh_projectdim3(qh, point, p);+ for (k=0; k < 3; k++)+ qh_fprintf(qh, fp, 9216, "%8.4g ", p[k]);+ qh_fprintf(qh, fp, 9217, " # p%d\n", qh_pointid(qh, point));+} /* printpoint3 */++/*----------------------------------------+-printpoints- print pointids for a set of points starting at index+ see geom_r.c+*/++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printpoints_out">-</a>++ qh_printpoints_out(qh, fp, facetlist, facets, printall )+ prints vertices, coplanar/inside points, for facets by their point coordinates+ allows qh.CDDoutput++ notes:+ same format as qhull input+ if no coplanar/interior points,+ same order as qh_printextremes+*/+void qh_printpoints_out(qhT *qh, FILE *fp, facetT *facetlist, setT *facets, boolT printall) {+ int allpoints= qh->num_points + qh_setsize(qh, qh->other_points);+ int numpoints=0, point_i, point_n;+ setT *vertices, *points;+ facetT *facet, **facetp;+ pointT *point, **pointp;+ vertexT *vertex, **vertexp;+ int id;++ points= qh_settemp(qh, allpoints);+ qh_setzero(qh, points, 0, allpoints);+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ FOREACHvertex_(vertices) {+ id= qh_pointid(qh, vertex->point);+ if (id >= 0)+ SETelem_(points, id)= vertex->point;+ }+ if (qh->KEEPinside || qh->KEEPcoplanar || qh->KEEPnearinside) {+ FORALLfacet_(facetlist) {+ if (!printall && qh_skipfacet(qh, facet))+ continue;+ FOREACHpoint_(facet->coplanarset) {+ id= qh_pointid(qh, point);+ if (id >= 0)+ SETelem_(points, id)= point;+ }+ }+ FOREACHfacet_(facets) {+ if (!printall && qh_skipfacet(qh, facet))+ continue;+ FOREACHpoint_(facet->coplanarset) {+ id= qh_pointid(qh, point);+ if (id >= 0)+ SETelem_(points, id)= point;+ }+ }+ }+ qh_settempfree(qh, &vertices);+ FOREACHpoint_i_(qh, points) {+ if (point)+ numpoints++;+ }+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh->rbox_command,+ qh->qhull_command, numpoints, qh->hull_dim + 1);+ else+ qh_fprintf(qh, fp, 9219, "%d\n%d\n", qh->hull_dim, numpoints);+ FOREACHpoint_i_(qh, points) {+ if (point) {+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9220, "1 ");+ qh_printpoint(qh, fp, NULL, point);+ }+ }+ if (qh->CDDoutput)+ qh_fprintf(qh, fp, 9221, "end\n");+ qh_settempfree(qh, &points);+} /* printpoints_out */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printpointvect">-</a>++ qh_printpointvect(qh, fp, point, normal, center, radius, color )+ prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point+*/+void qh_printpointvect(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {+ realT diff[4], pointA[4];+ int k;++ for (k=qh->hull_dim; k--; ) {+ if (center)+ diff[k]= point[k]-center[k];+ else if (normal)+ diff[k]= normal[k];+ else+ diff[k]= 0;+ }+ if (center)+ qh_normalize2(qh, diff, qh->hull_dim, True, NULL, NULL);+ for (k=qh->hull_dim; k--; )+ pointA[k]= point[k]+diff[k] * radius;+ qh_printline3geom(qh, fp, point, pointA, color);+} /* printpointvect */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printpointvect2">-</a>++ qh_printpointvect2(qh, fp, point, normal, center, radius )+ prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point+*/+void qh_printpointvect2(qhT *qh, FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {+ realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};++ qh_printpointvect(qh, fp, point, normal, center, radius, red);+ qh_printpointvect(qh, fp, point, normal, center, -radius, yellow);+} /* printpointvect2 */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printridge">-</a>++ qh_printridge(qh, fp, ridge )+ prints the information in a ridge++ notes:+ for qh_printfacetridges()+ same as operator<< [QhullRidge.cpp]+*/+void qh_printridge(qhT *qh, FILE *fp, ridgeT *ridge) {++ qh_fprintf(qh, fp, 9222, " - r%d", ridge->id);+ if (ridge->tested)+ qh_fprintf(qh, fp, 9223, " tested");+ if (ridge->nonconvex)+ qh_fprintf(qh, fp, 9224, " nonconvex");+ qh_fprintf(qh, fp, 9225, "\n");+ qh_printvertices(qh, fp, " vertices:", ridge->vertices);+ if (ridge->top && ridge->bottom)+ qh_fprintf(qh, fp, 9226, " between f%d and f%d\n",+ ridge->top->id, ridge->bottom->id);+} /* printridge */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printspheres">-</a>++ qh_printspheres(qh, fp, vertices, radius )+ prints 3-d vertices as OFF spheres++ notes:+ inflated octahedron from Stuart Levy earth/mksphere2+*/+void qh_printspheres(qhT *qh, FILE *fp, setT *vertices, realT radius) {+ vertexT *vertex, **vertexp;++ qh->printoutnum++;+ qh_fprintf(qh, fp, 9227, "{appearance {-edge -normal normscale 0} {\n\+INST geom {define vsphere OFF\n\+18 32 48\n\+\n\+0 0 1\n\+1 0 0\n\+0 1 0\n\+-1 0 0\n\+0 -1 0\n\+0 0 -1\n\+0.707107 0 0.707107\n\+0 -0.707107 0.707107\n\+0.707107 -0.707107 0\n\+-0.707107 0 0.707107\n\+-0.707107 -0.707107 0\n\+0 0.707107 0.707107\n\+-0.707107 0.707107 0\n\+0.707107 0.707107 0\n\+0.707107 0 -0.707107\n\+0 0.707107 -0.707107\n\+-0.707107 0 -0.707107\n\+0 -0.707107 -0.707107\n\+\n\+3 0 6 11\n\+3 0 7 6 \n\+3 0 9 7 \n\+3 0 11 9\n\+3 1 6 8 \n\+3 1 8 14\n\+3 1 13 6\n\+3 1 14 13\n\+3 2 11 13\n\+3 2 12 11\n\+3 2 13 15\n\+3 2 15 12\n\+3 3 9 12\n\+3 3 10 9\n\+3 3 12 16\n\+3 3 16 10\n\+3 4 7 10\n\+3 4 8 7\n\+3 4 10 17\n\+3 4 17 8\n\+3 5 14 17\n\+3 5 15 14\n\+3 5 16 15\n\+3 5 17 16\n\+3 6 13 11\n\+3 7 8 6\n\+3 9 10 7\n\+3 11 12 9\n\+3 14 8 17\n\+3 15 13 14\n\+3 16 12 15\n\+3 17 10 16\n} transforms { TLIST\n");+ FOREACHvertex_(vertices) {+ qh_fprintf(qh, fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",+ radius, vertex->id, radius, radius);+ qh_printpoint3(qh, fp, vertex->point);+ qh_fprintf(qh, fp, 9229, "1\n");+ }+ qh_fprintf(qh, fp, 9230, "}}}\n");+} /* printspheres */+++/*----------------------------------------------+-printsummary-+ see libqhull_r.c+*/++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvdiagram">-</a>++ qh_printvdiagram(qh, fp, format, facetlist, facets, printall )+ print voronoi diagram+ # of pairs of input sites+ #indices site1 site2 vertex1 ...++ sites indexed by input point id+ point 0 is the first input point+ vertices indexed by 'o' and 'p' order+ vertex 0 is the 'vertex-at-infinity'+ vertex 1 is the first Voronoi vertex++ see:+ qh_printvoronoi()+ qh_eachvoronoi_all()++ notes:+ if all facets are upperdelaunay,+ prints upper hull (furthest-site Voronoi diagram)+*/+void qh_printvdiagram(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {+ setT *vertices;+ int totcount, numcenters;+ boolT isLower;+ qh_RIDGE innerouter= qh_RIDGEall;+ printvridgeT printvridge= NULL;++ if (format == qh_PRINTvertices) {+ innerouter= qh_RIDGEall;+ printvridge= qh_printvridge;+ }else if (format == qh_PRINTinner) {+ innerouter= qh_RIDGEinner;+ printvridge= qh_printvnorm;+ }else if (format == qh_PRINTouter) {+ innerouter= qh_RIDGEouter;+ printvridge= qh_printvnorm;+ }else {+ qh_fprintf(qh, qh->ferr, 6219, "Qhull internal error (qh_printvdiagram): unknown print format %d.\n", format);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);+ totcount= qh_printvdiagram2(qh, NULL, NULL, vertices, innerouter, False);+ qh_fprintf(qh, fp, 9231, "%d\n", totcount);+ totcount= qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, True /* inorder*/);+ qh_settempfree(qh, &vertices);+#if 0 /* for testing qh_eachvoronoi_all */+ qh_fprintf(qh, fp, 9232, "\n");+ totcount= qh_eachvoronoi_all(qh, fp, printvridge, qh->UPPERdelaunay, innerouter, True /* inorder*/);+ qh_fprintf(qh, fp, 9233, "%d\n", totcount);+#endif+} /* printvdiagram */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvdiagram2">-</a>++ qh_printvdiagram2(qh, fp, printvridge, vertices, innerouter, inorder )+ visit all pairs of input sites (vertices) for selected Voronoi vertices+ vertices may include NULLs++ innerouter:+ qh_RIDGEall print inner ridges(bounded) and outer ridges(unbounded)+ qh_RIDGEinner print only inner ridges+ qh_RIDGEouter print only outer ridges++ inorder:+ print 3-d Voronoi vertices in order++ assumes:+ qh_markvoronoi marked facet->visitid for Voronoi vertices+ all facet->seen= False+ all facet->seen2= True++ returns:+ total number of Voronoi ridges+ if printvridge,+ calls printvridge( fp, vertex, vertexA, centers) for each ridge+ [see qh_eachvoronoi()]++ see:+ qh_eachvoronoi_all()+*/+int qh_printvdiagram2(qhT *qh, FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {+ int totcount= 0;+ int vertex_i, vertex_n;+ vertexT *vertex;++ FORALLvertices+ vertex->seen= False;+ FOREACHvertex_i_(qh, vertices) {+ if (vertex) {+ if (qh->GOODvertex > 0 && qh_pointid(qh, vertex->point)+1 != qh->GOODvertex)+ continue;+ totcount += qh_eachvoronoi(qh, fp, printvridge, vertex, !qh_ALL, innerouter, inorder);+ }+ }+ return totcount;+} /* printvdiagram2 */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvertex">-</a>++ qh_printvertex(qh, fp, vertex )+ prints the information in a vertex+ Duplicated as operator<< [QhullVertex.cpp]+*/+void qh_printvertex(qhT *qh, FILE *fp, vertexT *vertex) {+ pointT *point;+ int k, count= 0;+ facetT *neighbor, **neighborp;+ realT r; /*bug fix*/++ if (!vertex) {+ qh_fprintf(qh, fp, 9234, " NULLvertex\n");+ return;+ }+ qh_fprintf(qh, fp, 9235, "- p%d(v%d):", qh_pointid(qh, vertex->point), vertex->id);+ point= vertex->point;+ if (point) {+ for (k=qh->hull_dim; k--; ) {+ r= *point++;+ qh_fprintf(qh, fp, 9236, " %5.2g", r);+ }+ }+ if (vertex->deleted)+ qh_fprintf(qh, fp, 9237, " deleted");+ if (vertex->delridge)+ qh_fprintf(qh, fp, 9238, " ridgedeleted");+ qh_fprintf(qh, fp, 9239, "\n");+ if (vertex->neighbors) {+ qh_fprintf(qh, fp, 9240, " neighbors:");+ FOREACHneighbor_(vertex) {+ if (++count % 100 == 0)+ qh_fprintf(qh, fp, 9241, "\n ");+ qh_fprintf(qh, fp, 9242, " f%d", neighbor->id);+ }+ qh_fprintf(qh, fp, 9243, "\n");+ }+} /* printvertex */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvertexlist">-</a>++ qh_printvertexlist(qh, fp, string, facetlist, facets, printall )+ prints vertices used by a facetlist or facet set+ tests qh_skipfacet() if !printall+*/+void qh_printvertexlist(qhT *qh, FILE *fp, const char* string, facetT *facetlist,+ setT *facets, boolT printall) {+ vertexT *vertex, **vertexp;+ setT *vertices;++ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ qh_fprintf(qh, fp, 9244, "%s", string);+ FOREACHvertex_(vertices)+ qh_printvertex(qh, fp, vertex);+ qh_settempfree(qh, &vertices);+} /* printvertexlist */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvertices">-</a>++ qh_printvertices(qh, fp, string, vertices )+ prints vertices in a set+ duplicated as printVertexSet [QhullVertex.cpp]+*/+void qh_printvertices(qhT *qh, FILE *fp, const char* string, setT *vertices) {+ vertexT *vertex, **vertexp;++ qh_fprintf(qh, fp, 9245, "%s", string);+ FOREACHvertex_(vertices)+ qh_fprintf(qh, fp, 9246, " p%d(v%d)", qh_pointid(qh, vertex->point), vertex->id);+ qh_fprintf(qh, fp, 9247, "\n");+} /* printvertices */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvneighbors">-</a>++ qh_printvneighbors(qh, fp, facetlist, facets, printall )+ print vertex neighbors of vertices in facetlist and facets ('FN')++ notes:+ qh_countfacets clears facet->visitid for non-printed facets++ design:+ collect facet count and related statistics+ if necessary, build neighbor sets for each vertex+ collect vertices in facetlist and facets+ build a point array for point->vertex and point->coplanar facet+ for each point+ list vertex neighbors or coplanar facet+*/+void qh_printvneighbors(qhT *qh, FILE *fp, facetT* facetlist, setT *facets, boolT printall) {+ int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;+ setT *vertices, *vertex_points, *coplanar_points;+ int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);+ vertexT *vertex, **vertexp;+ int vertex_i, vertex_n;+ facetT *facet, **facetp, *neighbor, **neighborp;+ pointT *point, **pointp;++ qh_countfacets(qh, facetlist, facets, printall, &numfacets, &numsimplicial,+ &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */+ qh_fprintf(qh, fp, 9248, "%d\n", numpoints);+ qh_vertexneighbors(qh);+ vertices= qh_facetvertices(qh, facetlist, facets, printall);+ vertex_points= qh_settemp(qh, numpoints);+ coplanar_points= qh_settemp(qh, numpoints);+ qh_setzero(qh, vertex_points, 0, numpoints);+ qh_setzero(qh, coplanar_points, 0, numpoints);+ FOREACHvertex_(vertices)+ qh_point_add(qh, vertex_points, vertex->point, vertex);+ FORALLfacet_(facetlist) {+ FOREACHpoint_(facet->coplanarset)+ qh_point_add(qh, coplanar_points, point, facet);+ }+ FOREACHfacet_(facets) {+ FOREACHpoint_(facet->coplanarset)+ qh_point_add(qh, coplanar_points, point, facet);+ }+ FOREACHvertex_i_(qh, vertex_points) {+ if (vertex) {+ numneighbors= qh_setsize(qh, vertex->neighbors);+ qh_fprintf(qh, fp, 9249, "%d", numneighbors);+ if (qh->hull_dim == 3)+ qh_order_vertexneighbors(qh, vertex);+ else if (qh->hull_dim >= 4)+ qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors,+ sizeof(facetT *), qh_compare_facetvisit);+ FOREACHneighbor_(vertex)+ qh_fprintf(qh, fp, 9250, " %d",+ neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id);+ qh_fprintf(qh, fp, 9251, "\n");+ }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))+ qh_fprintf(qh, fp, 9252, "1 %d\n",+ facet->visitid ? facet->visitid - 1 : 0 - facet->id);+ else+ qh_fprintf(qh, fp, 9253, "0\n");+ }+ qh_settempfree(qh, &coplanar_points);+ qh_settempfree(qh, &vertex_points);+ qh_settempfree(qh, &vertices);+} /* printvneighbors */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvoronoi">-</a>++ qh_printvoronoi(qh, fp, format, facetlist, facets, printall )+ print voronoi diagram in 'o' or 'G' format+ for 'o' format+ prints voronoi centers for each facet and for infinity+ for each vertex, lists ids of printed facets or infinity+ assumes facetlist and facets are disjoint+ for 'G' format+ prints an OFF object+ adds a 0 coordinate to center+ prints infinity but does not list in vertices++ see:+ qh_printvdiagram()++ notes:+ if 'o',+ prints a line for each point except "at-infinity"+ if all facets are upperdelaunay,+ reverses lower and upper hull+*/+void qh_printvoronoi(qhT *qh, FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) {+ int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;+ facetT *facet, **facetp, *neighbor, **neighborp;+ setT *vertices;+ vertexT *vertex;+ boolT isLower;+ unsigned int numfacets= (unsigned int) qh->num_facets;++ vertices= qh_markvoronoi(qh, facetlist, facets, printall, &isLower, &numcenters);+ FOREACHvertex_i_(qh, vertices) {+ if (vertex) {+ numvertices++;+ numneighbors = numinf = 0;+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid == 0)+ numinf= 1;+ else if (neighbor->visitid < numfacets)+ numneighbors++;+ }+ if (numinf && !numneighbors) {+ SETelem_(vertices, vertex_i)= NULL;+ numvertices--;+ }+ }+ }+ if (format == qh_PRINTgeom)+ qh_fprintf(qh, fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",+ numcenters, numvertices);+ else+ qh_fprintf(qh, fp, 9255, "%d\n%d %d 1\n", qh->hull_dim-1, numcenters, qh_setsize(qh, vertices));+ if (format == qh_PRINTgeom) {+ for (k=qh->hull_dim-1; k--; )+ qh_fprintf(qh, fp, 9256, qh_REAL_1, 0.0);+ qh_fprintf(qh, fp, 9257, " 0 # infinity not used\n");+ }else {+ for (k=qh->hull_dim-1; k--; )+ qh_fprintf(qh, fp, 9258, qh_REAL_1, qh_INFINITE);+ qh_fprintf(qh, fp, 9259, "\n");+ }+ FORALLfacet_(facetlist) {+ if (facet->visitid && facet->visitid < numfacets) {+ if (format == qh_PRINTgeom)+ qh_fprintf(qh, fp, 9260, "# %d f%d\n", vid++, facet->id);+ qh_printcenter(qh, fp, format, NULL, facet);+ }+ }+ FOREACHfacet_(facets) {+ if (facet->visitid && facet->visitid < numfacets) {+ if (format == qh_PRINTgeom)+ qh_fprintf(qh, fp, 9261, "# %d f%d\n", vid++, facet->id);+ qh_printcenter(qh, fp, format, NULL, facet);+ }+ }+ FOREACHvertex_i_(qh, vertices) {+ numneighbors= 0;+ numinf=0;+ if (vertex) {+ if (qh->hull_dim == 3)+ qh_order_vertexneighbors(qh, vertex);+ else if (qh->hull_dim >= 4)+ qsort(SETaddr_(vertex->neighbors, facetT),+ (size_t)qh_setsize(qh, vertex->neighbors),+ sizeof(facetT *), qh_compare_facetvisit);+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid == 0)+ numinf= 1;+ else if (neighbor->visitid < numfacets)+ numneighbors++;+ }+ }+ if (format == qh_PRINTgeom) {+ if (vertex) {+ qh_fprintf(qh, fp, 9262, "%d", numneighbors);+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid && neighbor->visitid < numfacets)+ qh_fprintf(qh, fp, 9263, " %d", neighbor->visitid);+ }+ qh_fprintf(qh, fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id);+ }else+ qh_fprintf(qh, fp, 9265, " # p%d is coplanar or isolated\n", vertex_i);+ }else {+ if (numinf)+ numneighbors++;+ qh_fprintf(qh, fp, 9266, "%d", numneighbors);+ if (vertex) {+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid == 0) {+ if (numinf) {+ numinf= 0;+ qh_fprintf(qh, fp, 9267, " %d", neighbor->visitid);+ }+ }else if (neighbor->visitid < numfacets)+ qh_fprintf(qh, fp, 9268, " %d", neighbor->visitid);+ }+ }+ qh_fprintf(qh, fp, 9269, "\n");+ }+ }+ if (format == qh_PRINTgeom)+ qh_fprintf(qh, fp, 9270, "}\n");+ qh_settempfree(qh, &vertices);+} /* printvoronoi */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvnorm">-</a>++ qh_printvnorm(qh, fp, vertex, vertexA, centers, unbounded )+ print one separating plane of the Voronoi diagram for a pair of input sites+ unbounded==True if centers includes vertex-at-infinity++ assumes:+ qh_ASvoronoi and qh_vertexneighbors() already set++ note:+ parameter unbounded is UNUSED by this callback++ see:+ qh_printvdiagram()+ qh_eachvoronoi()+*/+void qh_printvnorm(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {+ pointT *normal;+ realT offset;+ int k;+ QHULL_UNUSED(unbounded);++ normal= qh_detvnorm(qh, vertex, vertexA, centers, &offset);+ qh_fprintf(qh, fp, 9271, "%d %d %d ",+ 2+qh->hull_dim, qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));+ for (k=0; k< qh->hull_dim-1; k++)+ qh_fprintf(qh, fp, 9272, qh_REAL_1, normal[k]);+ qh_fprintf(qh, fp, 9273, qh_REAL_1, offset);+ qh_fprintf(qh, fp, 9274, "\n");+} /* printvnorm */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printvridge">-</a>++ qh_printvridge(qh, fp, vertex, vertexA, centers, unbounded )+ print one ridge of the Voronoi diagram for a pair of input sites+ unbounded==True if centers includes vertex-at-infinity++ see:+ qh_printvdiagram()++ notes:+ the user may use a different function+ parameter unbounded is UNUSED+*/+void qh_printvridge(qhT *qh, FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {+ facetT *facet, **facetp;+ QHULL_UNUSED(unbounded);++ qh_fprintf(qh, fp, 9275, "%d %d %d", qh_setsize(qh, centers)+2,+ qh_pointid(qh, vertex->point), qh_pointid(qh, vertexA->point));+ FOREACHfacet_(centers)+ qh_fprintf(qh, fp, 9276, " %d", facet->visitid);+ qh_fprintf(qh, fp, 9277, "\n");+} /* printvridge */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="projectdim3">-</a>++ qh_projectdim3(qh, source, destination )+ project 2-d 3-d or 4-d point to a 3-d point+ uses qh.DROPdim and qh.hull_dim+ source and destination may be the same++ notes:+ allocate 4 elements to destination just in case+*/+void qh_projectdim3(qhT *qh, pointT *source, pointT *destination) {+ int i,k;++ for (k=0, i=0; k < qh->hull_dim; k++) {+ if (qh->hull_dim == 4) {+ if (k != qh->DROPdim)+ destination[i++]= source[k];+ }else if (k == qh->DROPdim)+ destination[i++]= 0;+ else+ destination[i++]= source[k];+ }+ while (i < 3)+ destination[i++]= 0.0;+} /* projectdim3 */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="readfeasible">-</a>++ qh_readfeasible(qh, dim, curline )+ read feasible point from current line and qh.fin++ returns:+ number of lines read from qh.fin+ sets qh.feasible_point with malloc'd coordinates++ notes:+ checks for qh.HALFspace+ assumes dim > 1++ see:+ qh_setfeasible+*/+int qh_readfeasible(qhT *qh, int dim, const char *curline) {+ boolT isfirst= True;+ int linecount= 0, tokcount= 0;+ const char *s;+ char *t, firstline[qh_MAXfirst+1];+ coordT *coords, value;++ if (!qh->HALFspace) {+ qh_fprintf(qh, qh->ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->feasible_string)+ qh_fprintf(qh, qh->ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");+ if (!(qh->feasible_point= (coordT*)qh_malloc(dim* sizeof(coordT)))) {+ qh_fprintf(qh, qh->ferr, 6071, "qhull error: insufficient memory for feasible point\n");+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ coords= qh->feasible_point;+ while ((s= (isfirst ? curline : fgets(firstline, qh_MAXfirst, qh->fin)))) {+ if (isfirst)+ isfirst= False;+ else+ linecount++;+ while (*s) {+ while (isspace(*s))+ s++;+ value= qh_strtod(s, &t);+ if (s == t)+ break;+ s= t;+ *(coords++)= value;+ if (++tokcount == dim) {+ while (isspace(*s))+ s++;+ qh_strtod(s, &t);+ if (s != t) {+ qh_fprintf(qh, qh->ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",+ s);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ return linecount;+ }+ }+ }+ qh_fprintf(qh, qh->ferr, 6073, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",+ tokcount, dim);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ return 0;+} /* readfeasible */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="readpoints">-</a>++ qh_readpoints(qh, numpoints, dimension, ismalloc )+ read points from qh.fin into qh.first_point, qh.num_points+ qh.fin is lines of coordinates, one per vertex, first line number of points+ if 'rbox D4',+ gives message+ if qh.ATinfinity,+ adds point-at-infinity for Delaunay triangulations++ returns:+ number of points, array of point coordinates, dimension, ismalloc True+ if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid+ and clears qh.PROJECTdelaunay+ if qh.HALFspace, reads optional feasible point, reads halfspaces,+ converts to dual.++ for feasible point in "cdd format" in 3-d:+ 3 1+ coordinates+ comments+ begin+ n 4 real/integer+ ...+ end++ notes:+ dimension will change in qh_initqhull_globals if qh.PROJECTinput+ uses malloc() since qh_mem not initialized+ FIXUP QH11012: qh_readpoints needs rewriting, too long+*/+coordT *qh_readpoints(qhT *qh, int *numpoints, int *dimension, boolT *ismalloc) {+ coordT *points, *coords, *infinity= NULL;+ realT paraboloid, maxboloid= -REALmax, value;+ realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;+ char *s= 0, *t, firstline[qh_MAXfirst+1];+ int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;+ int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;+ int tokcount= 0, linecount=0, maxcount, coordcount=0;+ boolT islong, isfirst= True, wasbegin= False;+ boolT isdelaunay= qh->DELAUNAY && !qh->PROJECTinput;++ if (qh->CDDinput) {+ while ((s= fgets(firstline, qh_MAXfirst, qh->fin))) {+ linecount++;+ if (qh->HALFspace && linecount == 1 && isdigit(*s)) {+ dimfeasible= qh_strtol(s, &s);+ while (isspace(*s))+ s++;+ if (qh_strtol(s, &s) == 1)+ linecount += qh_readfeasible(qh, dimfeasible, s);+ else+ dimfeasible= 0;+ }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5))+ break;+ else if (!*qh->rbox_command)+ strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);+ }+ if (!s) {+ qh_fprintf(qh, qh->ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ }+ while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh->fin))) {+ linecount++;+ if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5))+ wasbegin= True;+ while (*s) {+ while (isspace(*s))+ s++;+ if (!*s)+ break;+ if (!isdigit(*s)) {+ if (!*qh->rbox_command) {+ strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);+ firsttext= linecount;+ }+ break;+ }+ if (!diminput)+ diminput= qh_strtol(s, &s);+ else {+ numinput= qh_strtol(s, &s);+ if (numinput == 1 && diminput >= 2 && qh->HALFspace && !qh->CDDinput) {+ linecount += qh_readfeasible(qh, diminput, s); /* checks if ok */+ dimfeasible= diminput;+ diminput= numinput= 0;+ }else+ break;+ }+ }+ }+ if (!s) {+ qh_fprintf(qh, qh->ferr, 6075, "qhull input error: short input file. Did not find dimension and number of points\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (diminput > numinput) {+ tempi= diminput; /* exchange dim and n, e.g., for cdd input format */+ diminput= numinput;+ numinput= tempi;+ }+ if (diminput < 2) {+ qh_fprintf(qh, qh->ferr, 6220,"qhull input error: dimension %d(first number) should be at least 2\n",+ diminput);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (isdelaunay) {+ qh->PROJECTdelaunay= False;+ if (qh->CDDinput)+ *dimension= diminput;+ else+ *dimension= diminput+1;+ *numpoints= numinput;+ if (qh->ATinfinity)+ (*numpoints)++;+ }else if (qh->HALFspace) {+ *dimension= diminput - 1;+ *numpoints= numinput;+ if (diminput < 3) {+ qh_fprintf(qh, qh->ferr, 6221,"qhull input error: dimension %d(first number, includes offset) should be at least 3 for halfspaces\n",+ diminput);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (dimfeasible) {+ if (dimfeasible != *dimension) {+ qh_fprintf(qh, qh->ferr, 6222,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",+ dimfeasible, diminput);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ }else+ qh_setfeasible(qh, *dimension);+ }else {+ if (qh->CDDinput)+ *dimension= diminput-1;+ else+ *dimension= diminput;+ *numpoints= numinput;+ }+ qh->normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */+ if (qh->HALFspace) {+ qh->half_space= coordp= (coordT*)qh_malloc(qh->normal_size + sizeof(coordT));+ if (qh->CDDinput) {+ offsetp= qh->half_space;+ normalp= offsetp + 1;+ }else {+ normalp= qh->half_space;+ offsetp= normalp + *dimension;+ }+ }+ qh->maxline= diminput * (qh_REALdigits + 5);+ maximize_(qh->maxline, 500);+ qh->line= (char*)qh_malloc((qh->maxline+1) * sizeof(char));+ *ismalloc= True; /* use malloc since memory not setup */+ coords= points= qh->temp_malloc= /* numinput and diminput >=2 by QH6220 */+ (coordT*)qh_malloc((*numpoints)*(*dimension)*sizeof(coordT));+ if (!coords || !qh->line || (qh->HALFspace && !qh->half_space)) {+ qh_fprintf(qh, qh->ferr, 6076, "qhull error: insufficient memory to read %d points\n",+ numinput);+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ if (isdelaunay && qh->ATinfinity) {+ infinity= points + numinput * (*dimension);+ for (k= (*dimension) - 1; k--; )+ infinity[k]= 0.0;+ }+ maxcount= numinput * diminput;+ paraboloid= 0.0;+ while ((s= (isfirst ? s : fgets(qh->line, qh->maxline, qh->fin)))) {+ if (!isfirst) {+ linecount++;+ if (*s == 'e' || *s == 'E') {+ if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) {+ if (qh->CDDinput )+ break;+ else if (wasbegin)+ qh_fprintf(qh, qh->ferr, 7058, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");+ }+ }+ }+ islong= False;+ while (*s) {+ while (isspace(*s))+ s++;+ value= qh_strtod(s, &t);+ if (s == t) {+ if (!*qh->rbox_command)+ strncat(qh->rbox_command, s, sizeof(qh->rbox_command)-1);+ if (*s && !firsttext)+ firsttext= linecount;+ if (!islong && !firstshort && coordcount)+ firstshort= linecount;+ break;+ }+ if (!firstpoint)+ firstpoint= linecount;+ s= t;+ if (++tokcount > maxcount)+ continue;+ if (qh->HALFspace) {+ if (qh->CDDinput)+ *(coordp++)= -value; /* both coefficients and offset */+ else+ *(coordp++)= value;+ }else {+ *(coords++)= value;+ if (qh->CDDinput && !coordcount) {+ if (value != 1.0) {+ qh_fprintf(qh, qh->ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n",+ linecount);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ coords--;+ }else if (isdelaunay) {+ paraboloid += value * value;+ if (qh->ATinfinity) {+ if (qh->CDDinput)+ infinity[coordcount-1] += value;+ else+ infinity[coordcount] += value;+ }+ }+ }+ if (++coordcount == diminput) {+ coordcount= 0;+ if (isdelaunay) {+ *(coords++)= paraboloid;+ maximize_(maxboloid, paraboloid);+ paraboloid= 0.0;+ }else if (qh->HALFspace) {+ if (!qh_sethalfspace(qh, *dimension, coords, &coords, normalp, offsetp, qh->feasible_point)) {+ qh_fprintf(qh, qh->ferr, 8048, "The halfspace was on line %d\n", linecount);+ if (wasbegin)+ qh_fprintf(qh, qh->ferr, 8049, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ coordp= qh->half_space;+ }+ while (isspace(*s))+ s++;+ if (*s) {+ islong= True;+ if (!firstlong)+ firstlong= linecount;+ }+ }+ }+ if (!islong && !firstshort && coordcount)+ firstshort= linecount;+ if (!isfirst && s - qh->line >= qh->maxline) {+ qh_fprintf(qh, qh->ferr, 6078, "qhull input error: line %d contained more than %d characters\n",+ linecount, (int) (s - qh->line)); /* WARN64 */+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ isfirst= False;+ }+ if (tokcount != maxcount) {+ newnum= fmin_(numinput, tokcount/diminput);+ qh_fprintf(qh, qh->ferr, 7073,"\+qhull warning: instead of %d %d-dimensional points, input contains\n\+%d points and %d extra coordinates. Line %d is the first\npoint",+ numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);+ if (firsttext)+ qh_fprintf(qh, qh->ferr, 8051, ", line %d is the first comment", firsttext);+ if (firstshort)+ qh_fprintf(qh, qh->ferr, 8052, ", line %d is the first short\nline", firstshort);+ if (firstlong)+ qh_fprintf(qh, qh->ferr, 8053, ", line %d is the first long line", firstlong);+ qh_fprintf(qh, qh->ferr, 8054, ". Continue with %d points.\n", newnum);+ numinput= newnum;+ if (isdelaunay && qh->ATinfinity) {+ for (k= tokcount % diminput; k--; )+ infinity[k] -= *(--coords);+ *numpoints= newnum+1;+ }else {+ coords -= tokcount % diminput;+ *numpoints= newnum;+ }+ }+ if (isdelaunay && qh->ATinfinity) {+ for (k= (*dimension) -1; k--; )+ infinity[k] /= numinput;+ if (coords == infinity)+ coords += (*dimension) -1;+ else {+ for (k=0; k < (*dimension) -1; k++)+ *(coords++)= infinity[k];+ }+ *(coords++)= maxboloid * 1.1;+ }+ if (qh->rbox_command[0]) {+ qh->rbox_command[strlen(qh->rbox_command)-1]= '\0';+ if (!strcmp(qh->rbox_command, "./rbox D4"))+ qh_fprintf(qh, qh->ferr, 8055, "\n\+This is the qhull test case. If any errors or core dumps occur,\n\+recompile qhull with 'make new'. If errors still occur, there is\n\+an incompatibility. You should try a different compiler. You can also\n\+change the choices in user.h. If you discover the source of the problem,\n\+please send mail to qhull_bug@qhull.org.\n\+\n\+Type 'qhull' for a short list of options.\n");+ }+ qh_free(qh->line);+ qh->line= NULL;+ if (qh->half_space) {+ qh_free(qh->half_space);+ qh->half_space= NULL;+ }+ qh->temp_malloc= NULL;+ trace1((qh, qh->ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n",+ numinput, diminput));+ return(points);+} /* readpoints */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="setfeasible">-</a>++ qh_setfeasible(qh, dim )+ set qh.feasible_point from qh.feasible_string in "n,n,n" or "n n n" format++ notes:+ "n,n,n" already checked by qh_initflags()+ see qh_readfeasible()+ called only once from qh_new_qhull, otherwise leaks memory+*/+void qh_setfeasible(qhT *qh, int dim) {+ int tokcount= 0;+ char *s;+ coordT *coords, value;++ if (!(s= qh->feasible_string)) {+ qh_fprintf(qh, qh->ferr, 6223, "\+qhull input error: halfspace intersection needs a feasible point.\n\+Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (!(qh->feasible_point= (pointT*)qh_malloc(dim * sizeof(coordT)))) {+ qh_fprintf(qh, qh->ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n");+ qh_errexit(qh, qh_ERRmem, NULL, NULL);+ }+ coords= qh->feasible_point;+ while (*s) {+ value= qh_strtod(s, &s);+ if (++tokcount > dim) {+ qh_fprintf(qh, qh->ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",+ qh->feasible_string, dim);+ break;+ }+ *(coords++)= value;+ if (*s)+ s++;+ }+ while (++tokcount <= dim)+ *(coords++)= 0.0;+} /* setfeasible */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="skipfacet">-</a>++ qh_skipfacet(qh, facet )+ returns 'True' if this facet is not to be printed++ notes:+ based on the user provided slice thresholds and 'good' specifications+*/+boolT qh_skipfacet(qhT *qh, facetT *facet) {+ facetT *neighbor, **neighborp;++ if (qh->PRINTneighbors) {+ if (facet->good)+ return !qh->PRINTgood;+ FOREACHneighbor_(facet) {+ if (neighbor->good)+ return False;+ }+ return True;+ }else if (qh->PRINTgood)+ return !facet->good;+ else if (!facet->normal)+ return True;+ return(!qh_inthresholds(qh, facet->normal, NULL));+} /* skipfacet */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="skipfilename">-</a>++ qh_skipfilename(qh, string )+ returns pointer to character after filename++ notes:+ skips leading spaces+ ends with spacing or eol+ if starts with ' or " ends with the same, skipping \' or \"+ For qhull, qh_argv_to_command() only uses double quotes+*/+char *qh_skipfilename(qhT *qh, char *filename) {+ char *s= filename; /* non-const due to return */+ char c;++ while (*s && isspace(*s))+ s++;+ c= *s++;+ if (c == '\0') {+ qh_fprintf(qh, qh->ferr, 6204, "qhull input error: filename expected, none found.\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (c == '\'' || c == '"') {+ while (*s !=c || s[-1] == '\\') {+ if (!*s) {+ qh_fprintf(qh, qh->ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ s++;+ }+ s++;+ }+ else while (*s && !isspace(*s))+ s++;+ return s;+} /* skipfilename */+
+ Cdir/libqhull_r.c view
@@ -0,0 +1,1403 @@+/*<html><pre> -<a href="qh-qhull_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ libqhull_r.c+ Quickhull algorithm for convex hulls++ qhull() and top-level routines++ see qh-qhull_r.htm, libqhull.h, unix_r.c++ see qhull_ra.h for internal functions++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/libqhull_r.c#2 $$Change: 2047 $+ $DateTime: 2016/01/04 22:03:18 $$Author: bbarber $+*/++#include "qhull_ra.h"++/*============= functions in alphabetic order after qhull() =======*/++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="qhull">-</a>++ qh_qhull(qh)+ compute DIM3 convex hull of qh.num_points starting at qh.first_point+ qh->contains all global options and variables++ returns:+ returns polyhedron+ qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,++ returns global variables+ qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex++ returns precision constants+ qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge++ notes:+ unless needed for output+ qh.max_vertex and qh.min_vertex are max/min due to merges++ see:+ to add individual points to either qh.num_points+ use qh_addpoint()++ if qh.GETarea+ qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()++ design:+ record starting time+ initialize hull and partition points+ build convex hull+ unless early termination+ update facet->maxoutside for vertices, coplanar, and near-inside points+ error if temporary sets exist+ record end time+*/++void qh_qhull(qhT *qh) {+ int numoutside;++ qh->hulltime= qh_CPUclock;+ if (qh->RERUN || qh->JOGGLEmax < REALmax/2)+ qh_build_withrestart(qh);+ else {+ qh_initbuild(qh);+ qh_buildhull(qh);+ }+ if (!qh->STOPpoint && !qh->STOPcone) {+ if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)+ qh_checkzero(qh, qh_ALL);+ if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {+ trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points. Post-merging and check of maxout not needed.\n"));+ qh->DOcheckmax= False;+ }else {+ if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))+ qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,+ (qh->POSTmerge ? False : qh->TESTvneighbors));+ else if (!qh->POSTmerge && qh->TESTvneighbors)+ qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,+ qh->premerge_cos, True);+ if (qh->POSTmerge)+ qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,+ qh->postmerge_cos, qh->TESTvneighbors);+ if (qh->visible_list == qh->facet_list) { /* i.e., merging done */+ qh->findbestnew= True;+ qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numoutside);+ qh->findbestnew= False;+ qh_deletevisible(qh /*qh.visible_list*/);+ qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);+ }+ }+ if (qh->DOcheckmax){+ if (qh->REPORTfreq) {+ qh_buildtracing(qh, NULL, NULL);+ qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");+ }+ qh_check_maxout(qh);+ }+ if (qh->KEEPnearinside && !qh->maxoutdone)+ qh_nearcoplanar(qh);+ }+ if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {+ qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d)\n",+ qh_setsize(qh, qh->qhmem.tempstack));+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ qh->hulltime= qh_CPUclock - qh->hulltime;+ qh->QHULLfinished= True;+ trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));+} /* qhull */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="addpoint">-</a>++ qh_addpoint(qh, furthest, facet, checkdist )+ add point (usually furthest point) above facet to hull+ if checkdist,+ check that point is above facet.+ if point is not outside of the hull, uses qh_partitioncoplanar()+ assumes that facet is defined by qh_findbestfacet()+ else if facet specified,+ assumes that point is above facet (major damage if below)+ for Delaunay triangulations,+ Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed+ Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.++ returns:+ returns False if user requested an early termination+ qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined+ updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices+ clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)+ if unknown point, adds a pointer to qh.other_points+ do not deallocate the point's coordinates++ notes:+ assumes point is near its best facet and not at a local minimum of a lens+ distributions. Use qh_findbestfacet to avoid this case.+ uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets++ see also:+ qh_triangulate() -- triangulate non-simplicial facets++ design:+ add point to other_points if needed+ if checkdist+ if point not above facet+ partition coplanar point+ exit+ exit if pre STOPpoint requested+ find horizon and visible facets for point+ make new facets for point to horizon+ make hyperplanes for point+ compute balance statistics+ match neighboring new facets+ update vertex neighbors and delete interior vertices+ exit if STOPcone requested+ merge non-convex new facets+ if merge found, many merges, or 'Qf'+ use qh_findbestnew() instead of qh_findbest()+ partition outside points from visible facets+ delete visible facets+ check polyhedron if requested+ exit if post STOPpoint requested+ reset working lists of facets and vertices+*/+boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {+ int goodvisible, goodhorizon;+ vertexT *vertex;+ facetT *newfacet;+ realT dist, newbalance, pbalance;+ boolT isoutside= False;+ int numpart, numpoints, numnew, firstnew;++ qh->maxoutdone= False;+ if (qh_pointid(qh, furthest) == qh_IDunknown)+ qh_setappend(qh, &qh->other_points, furthest);+ if (!facet) {+ qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet. Need to call qh_findbestfacet first\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ if (checkdist) {+ facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,+ &dist, &isoutside, &numpart);+ zzadd_(Zpartition, numpart);+ if (!isoutside) {+ zinc_(Znotmax); /* last point of outsideset is no longer furthest. */+ facet->notfurthest= True;+ qh_partitioncoplanar(qh, furthest, facet, &dist);+ return True;+ }+ }+ qh_buildtracing(qh, furthest, facet);+ if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {+ facet->notfurthest= True;+ return False;+ }+ qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);+ if (qh->ONLYgood && !(goodvisible+goodhorizon) && !qh->GOODclosest) {+ zinc_(Znotgood);+ facet->notfurthest= True;+ /* last point of outsideset is no longer furthest. This is ok+ since all points of the outside are likely to be bad */+ qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);+ return True;+ }+ zzinc_(Zprocessed);+ firstnew= qh->facet_id;+ vertex= qh_makenewfacets(qh, furthest /*visible_list, attaches if !ONLYgood */);+ qh_makenewplanes(qh /* newfacet_list */);+ numnew= qh->facet_id - firstnew;+ newbalance= numnew - (realT) (qh->num_facets-qh->num_visible)+ * qh->hull_dim/qh->num_vertices;+ wadd_(Wnewbalance, newbalance);+ wadd_(Wnewbalance2, newbalance * newbalance);+ if (qh->ONLYgood+ && !qh_findgood(qh, qh->newfacet_list, goodhorizon) && !qh->GOODclosest) {+ FORALLnew_facets+ qh_delfacet(qh, newfacet);+ qh_delvertex(qh, vertex);+ qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);+ zinc_(Znotgoodnew);+ facet->notfurthest= True;+ return True;+ }+ if (qh->ONLYgood)+ qh_attachnewfacets(qh /*visible_list*/);+ qh_matchnewfacets(qh);+ qh_updatevertices(qh);+ if (qh->STOPcone && qh->furthest_id == qh->STOPcone-1) {+ facet->notfurthest= True;+ return False; /* visible_list etc. still defined */+ }+ qh->findbestnew= False;+ if (qh->PREmerge || qh->MERGEexact) {+ qh_premerge(qh, vertex, qh->premerge_centrum, qh->premerge_cos);+ if (qh_USEfindbestnew)+ qh->findbestnew= True;+ else {+ FORALLnew_facets {+ if (!newfacet->simplicial) {+ qh->findbestnew= True; /* use qh_findbestnew instead of qh_findbest*/+ break;+ }+ }+ }+ }else if (qh->BESToutside)+ qh->findbestnew= True;+ qh_partitionvisible(qh /*qh.visible_list*/, !qh_ALL, &numpoints);+ qh->findbestnew= False;+ qh->findbest_notsharp= False;+ zinc_(Zpbalance);+ pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */+ * (qh->num_points - qh->num_vertices)/qh->num_vertices;+ wadd_(Wpbalance, pbalance);+ wadd_(Wpbalance2, pbalance * pbalance);+ qh_deletevisible(qh /*qh.visible_list*/);+ zmax_(Zmaxvertex, qh->num_vertices);+ qh->NEWfacets= False;+ if (qh->IStracing >= 4) {+ if (qh->num_facets < 2000)+ qh_printlists(qh);+ qh_printfacetlist(qh, qh->newfacet_list, NULL, True);+ qh_checkpolygon(qh, qh->facet_list);+ }else if (qh->CHECKfrequently) {+ if (qh->num_facets < 50)+ qh_checkpolygon(qh, qh->facet_list);+ else+ qh_checkpolygon(qh, qh->newfacet_list);+ }+ if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)+ return False;+ qh_resetlists(qh, True, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);+ /* qh_triangulate(qh); to test qh.TRInormals */+ trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",+ qh_pointid(qh, furthest), numnew, newbalance, pbalance));+ return True;+} /* addpoint */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="build_withrestart">-</a>++ qh_build_withrestart(qh)+ allow restarts due to qh.JOGGLEmax while calling qh_buildhull()+ qh_errexit always undoes qh_build_withrestart()+ qh.FIRSTpoint/qh.NUMpoints is point array+ it may be moved by qh_joggleinput(qh)+*/+void qh_build_withrestart(qhT *qh) {+ int restart;++ qh->ALLOWrestart= True;+ while (True) {+ restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */+ if (restart) { /* only from qh_precision() */+ zzinc_(Zretry);+ wmax_(Wretrymax, qh->JOGGLEmax);+ /* QH7078 warns about using 'TCn' with 'QJn' */+ qh->STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */+ }+ if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {+ if (qh->build_cnt > qh_JOGGLEmaxretry) {+ qh_fprintf(qh, qh->ferr, 6229, "qhull precision error: %d attempts to construct a convex hull\n\+ with joggled input. Increase joggle above 'QJ%2.2g'\n\+ or modify qh_JOGGLE... parameters in user.h\n",+ qh->build_cnt, qh->JOGGLEmax);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ if (qh->build_cnt && !restart)+ break;+ }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)+ break;+ qh->STOPcone= 0;+ qh_freebuild(qh, True); /* first call is a nop */+ qh->build_cnt++;+ if (!qh->qhull_optionsiz)+ qh->qhull_optionsiz= (int)strlen(qh->qhull_options); /* WARN64 */+ else {+ qh->qhull_options [qh->qhull_optionsiz]= '\0';+ qh->qhull_optionlen= qh_OPTIONline; /* starts a new line */+ }+ qh_option(qh, "_run", &qh->build_cnt, NULL);+ if (qh->build_cnt == qh->RERUN) {+ qh->IStracing= qh->TRACElastrun; /* duplicated from qh_initqhull_globals */+ if (qh->TRACEpoint != qh_IDunknown || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {+ qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);+ qh->IStracing= 0;+ }+ qh->qhmem.IStracing= qh->IStracing;+ }+ if (qh->JOGGLEmax < REALmax/2)+ qh_joggleinput(qh);+ qh_initbuild(qh);+ qh_buildhull(qh);+ if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)+ qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);+ }+ qh->ALLOWrestart= False;+} /* qh_build_withrestart */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="buildhull">-</a>++ qh_buildhull(qh)+ construct a convex hull by adding outside points one at a time++ returns:++ notes:+ may be called multiple times+ checks facet and vertex lists for incorrect flags+ to recover from STOPcone, call qh_deletevisible and qh_resetlists++ design:+ check visible facet and newfacet flags+ check newlist vertex flags and qh.STOPcone/STOPpoint+ for each facet with a furthest outside point+ add point to facet+ exit if qh.STOPcone or qh.STOPpoint requested+ if qh.NARROWhull for initial simplex+ partition remaining outside points to coplanar sets+*/+void qh_buildhull(qhT *qh) {+ facetT *facet;+ pointT *furthest;+ vertexT *vertex;+ int id;++ trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));+ FORALLfacets {+ if (facet->visible || facet->newfacet) {+ qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",+ facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ }+ FORALLvertices {+ if (vertex->newlist) {+ qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",+ vertex->id);+ qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ id= qh_pointid(qh, vertex->point);+ if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||+ (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||+ (qh->STOPcone>0 && id == qh->STOPcone-1)) {+ trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));+ return;+ }+ }+ qh->facet_next= qh->facet_list; /* advance facet when processed */+ while ((furthest= qh_nextfurthest(qh, &facet))) {+ qh->num_outside--; /* if ONLYmax, furthest may not be outside */+ if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))+ break;+ }+ if (qh->NARROWhull) /* move points from outsideset to coplanarset */+ qh_outcoplanar(qh /* facet_list */ );+ if (qh->num_outside && !furthest) {+ qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));+} /* buildhull */+++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="buildtracing">-</a>++ qh_buildtracing(qh, furthest, facet )+ trace an iteration of qh_buildhull() for furthest point and facet+ if !furthest, prints progress message++ returns:+ tracks progress with qh.lastreport+ updates qh.furthest_id (-3 if furthest is NULL)+ also resets visit_id, vertext_visit on wrap around++ see:+ qh_tracemerging()++ design:+ if !furthest+ print progress message+ exit+ if 'TFn' iteration+ print progress message+ else if tracing+ trace furthest point and facet+ reset qh.visit_id and qh.vertex_visit if overflow may occur+ set qh.furthest_id for tracing+*/+void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {+ realT dist= 0;+ float cpu;+ int total, furthestid;+ time_t timedata;+ struct tm *tp;+ vertexT *vertex;++ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ if (!furthest) {+ time(&timedata);+ tp= localtime(&timedata);+ cpu= (float)qh_CPUclock - (float)qh->hulltime;+ cpu /= (float)qh_SECticks;+ total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);+ qh_fprintf(qh, qh->ferr, 8118, "\n\+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\+ The current hull contains %d facets and %d vertices. Last point was p%d\n",+ tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,+ total, qh->num_facets, qh->num_vertices, qh->furthest_id);+ return;+ }+ furthestid= qh_pointid(qh, furthest);+ if (qh->TRACEpoint == furthestid) {+ qh->IStracing= qh->TRACElevel;+ qh->qhmem.IStracing= qh->TRACElevel;+ }else if (qh->TRACEpoint != qh_IDunknown && qh->TRACEdist < REALmax/2) {+ qh->IStracing= 0;+ qh->qhmem.IStracing= 0;+ }+ if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport+qh->REPORTfreq)) {+ qh->lastreport= qh->facet_id-1;+ time(&timedata);+ tp= localtime(&timedata);+ cpu= (float)qh_CPUclock - (float)qh->hulltime;+ cpu /= (float)qh_SECticks;+ total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);+ zinc_(Zdistio);+ qh_distplane(qh, furthest, facet, &dist);+ qh_fprintf(qh, qh->ferr, 8119, "\n\+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\+ The current hull contains %d facets and %d vertices. There are %d\n\+ outside points. Next is point p%d(v%d), %2.2g above f%d.\n",+ tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,+ total, qh->num_facets, qh->num_vertices, qh->num_outside+1,+ furthestid, qh->vertex_id, dist, getid_(facet));+ }else if (qh->IStracing >=1) {+ cpu= (float)qh_CPUclock - (float)qh->hulltime;+ cpu /= (float)qh_SECticks;+ qh_distplane(qh, furthest, facet, &dist);+ qh_fprintf(qh, qh->ferr, 8120, "qh_addpoint: add p%d(v%d) to hull of %d facets(%2.2g above f%d) and %d outside at %4.4g CPU secs. Previous was p%d.\n",+ furthestid, qh->vertex_id, qh->num_facets, dist,+ getid_(facet), qh->num_outside+1, cpu, qh->furthest_id);+ }+ zmax_(Zvisit2max, (int)qh->visit_id/2);+ if (qh->visit_id > (unsigned) INT_MAX) { /* 31 bits */+ zinc_(Zvisit);+ qh->visit_id= 0;+ FORALLfacets+ facet->visitid= 0;+ }+ zmax_(Zvvisit2max, (int)qh->vertex_visit/2);+ if (qh->vertex_visit > (unsigned) INT_MAX) { /* 31 bits */ + zinc_(Zvvisit);+ qh->vertex_visit= 0;+ FORALLvertices+ vertex->visitid= 0;+ }+ qh->furthest_id= furthestid;+ qh->RANDOMdist= qh->old_randomdist;+} /* buildtracing */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="errexit2">-</a>++ qh_errexit2(qh, exitcode, facet, otherfacet )+ return exitcode to system after an error+ report two facets++ returns:+ assumes exitcode non-zero++ see:+ normally use qh_errexit() in user.c(reports a facet and a ridge)+*/+void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {++ qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);+ qh_errexit(qh, exitcode, NULL, NULL);+} /* errexit2 */+++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="findhorizon">-</a>++ qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )+ given a visible facet, find the point's horizon and visible facets+ for all facets, !facet-visible++ returns:+ returns qh.visible_list/num_visible with all visible facets+ marks visible facets with ->visible+ updates count of good visible and good horizon facets+ updates qh.max_outside, qh.max_vertex, facet->maxoutside++ see:+ similar to qh_delpoint()++ design:+ move facet to qh.visible_list at end of qh.facet_list+ for all visible facets+ for each unvisited neighbor of a visible facet+ compute distance of point to neighbor+ if point above neighbor+ move neighbor to end of qh.visible_list+ else if point is coplanar with neighbor+ update qh.max_outside, qh.max_vertex, neighbor->maxoutside+ mark neighbor coplanar (will create a samecycle later)+ update horizon statistics+*/+void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {+ facetT *neighbor, **neighborp, *visible;+ int numhorizon= 0, coplanar= 0;+ realT dist;++ trace1((qh, qh->ferr, 1040,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));+ *goodvisible= *goodhorizon= 0;+ zinc_(Ztotvisible);+ qh_removefacet(qh, facet); /* visible_list at end of qh->facet_list */+ qh_appendfacet(qh, facet);+ qh->num_visible= 1;+ if (facet->good)+ (*goodvisible)++;+ qh->visible_list= facet;+ facet->visible= True;+ facet->f.replace= NULL;+ if (qh->IStracing >=4)+ qh_errprint(qh, "visible", facet, NULL, NULL, NULL);+ qh->visit_id++;+ FORALLvisible_facets {+ if (visible->tricoplanar && !qh->TRInormals) {+ qh_fprintf(qh, qh->ferr, 6230, "Qhull internal error (qh_findhorizon): does not work for tricoplanar facets. Use option 'Q11'\n");+ qh_errexit(qh, qh_ERRqhull, visible, NULL);+ }+ visible->visitid= qh->visit_id;+ FOREACHneighbor_(visible) {+ if (neighbor->visitid == qh->visit_id)+ continue;+ neighbor->visitid= qh->visit_id;+ zzinc_(Znumvisibility);+ qh_distplane(qh, point, neighbor, &dist);+ if (dist > qh->MINvisible) {+ zinc_(Ztotvisible);+ qh_removefacet(qh, neighbor); /* append to end of qh->visible_list */+ qh_appendfacet(qh, neighbor);+ neighbor->visible= True;+ neighbor->f.replace= NULL;+ qh->num_visible++;+ if (neighbor->good)+ (*goodvisible)++;+ if (qh->IStracing >=4)+ qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);+ }else {+ if (dist > - qh->MAXcoplanar) {+ neighbor->coplanar= True;+ zzinc_(Zcoplanarhorizon);+ qh_precision(qh, "coplanar horizon");+ coplanar++;+ if (qh->MERGING) {+ if (dist > 0) {+ maximize_(qh->max_outside, dist);+ maximize_(qh->max_vertex, dist);+#if qh_MAXoutside+ maximize_(neighbor->maxoutside, dist);+#endif+ }else+ minimize_(qh->min_vertex, dist); /* due to merge later */+ }+ trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",+ qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));+ }else+ neighbor->coplanar= False;+ zinc_(Ztothorizon);+ numhorizon++;+ if (neighbor->good)+ (*goodhorizon)++;+ if (qh->IStracing >=4)+ qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);+ }+ }+ }+ if (!numhorizon) {+ qh_precision(qh, "empty horizon");+ qh_fprintf(qh, qh->ferr, 6168, "qhull precision error (qh_findhorizon): empty horizon\n\+QhullPoint p%d was above all facets.\n", qh_pointid(qh, point));+ qh_printfacetlist(qh, qh->facet_list, NULL, True);+ qh_errexit(qh, qh_ERRprec, NULL, NULL);+ }+ trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",+ numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));+ if (qh->IStracing >= 4 && qh->num_facets < 50)+ qh_printlists(qh);+} /* findhorizon */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="nextfurthest">-</a>++ qh_nextfurthest(qh, visible )+ returns next furthest point and visible facet for qh_addpoint()+ starts search at qh.facet_next++ returns:+ removes furthest point from outside set+ NULL if none available+ advances qh.facet_next over facets with empty outside sets++ design:+ for each facet from qh.facet_next+ if empty outside set+ advance qh.facet_next+ else if qh.NARROWhull+ determine furthest outside point+ if furthest point is not outside+ advance qh.facet_next(point will be coplanar)+ remove furthest point from outside set+*/+pointT *qh_nextfurthest(qhT *qh, facetT **visible) {+ facetT *facet;+ int size, idx;+ realT randr, dist;+ pointT *furthest;++ while ((facet= qh->facet_next) != qh->facet_tail) {+ if (!facet->outsideset) {+ qh->facet_next= facet->next;+ continue;+ }+ SETreturnsize_(facet->outsideset, size);+ if (!size) {+ qh_setfree(qh, &facet->outsideset);+ qh->facet_next= facet->next;+ continue;+ }+ if (qh->NARROWhull) {+ if (facet->notfurthest)+ qh_furthestout(qh, facet);+ furthest= (pointT*)qh_setlast(facet->outsideset);+#if qh_COMPUTEfurthest+ qh_distplane(qh, furthest, facet, &dist);+ zinc_(Zcomputefurthest);+#else+ dist= facet->furthestdist;+#endif+ if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */+ qh->facet_next= facet->next;+ continue;+ }+ }+ if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {+ if (qh->PICKfurthest) {+ qh_furthestnext(qh /* qh->facet_list */);+ facet= qh->facet_next;+ }+ *visible= facet;+ return((pointT*)qh_setdellast(facet->outsideset));+ }+ if (qh->RANDOMoutside) {+ int outcoplanar = 0;+ if (qh->NARROWhull) {+ FORALLfacets {+ if (facet == qh->facet_next)+ break;+ if (facet->outsideset)+ outcoplanar += qh_setsize(qh, facet->outsideset);+ }+ }+ randr= qh_RANDOMint;+ randr= randr/(qh_RANDOMmax+1);+ idx= (int)floor((qh->num_outside - outcoplanar) * randr);+ FORALLfacet_(qh->facet_next) {+ if (facet->outsideset) {+ SETreturnsize_(facet->outsideset, size);+ if (!size)+ qh_setfree(qh, &facet->outsideset);+ else if (size > idx) {+ *visible= facet;+ return((pointT*)qh_setdelnth(qh, facet->outsideset, idx));+ }else+ idx -= size;+ }+ }+ qh_fprintf(qh, qh->ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",+ qh->num_outside, idx+1, randr);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }else { /* VIRTUALmemory */+ facet= qh->facet_tail->previous;+ if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {+ if (facet->outsideset)+ qh_setfree(qh, &facet->outsideset);+ qh_removefacet(qh, facet);+ qh_prependfacet(qh, facet, &qh->facet_list);+ continue;+ }+ *visible= facet;+ return furthest;+ }+ }+ return NULL;+} /* nextfurthest */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="partitionall">-</a>++ qh_partitionall(qh, vertices, points, numpoints )+ partitions all points in points/numpoints to the outsidesets of facets+ vertices= vertices in qh.facet_list(!partitioned)++ returns:+ builds facet->outsideset+ does not partition qh.GOODpoint+ if qh.ONLYgood && !qh.MERGING,+ does not partition qh.GOODvertex++ notes:+ faster if qh.facet_list sorted by anticipated size of outside set++ design:+ initialize pointset with all points+ remove vertices from pointset+ remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)+ for all facets+ for all remaining points in pointset+ compute distance from point to facet+ if point is outside facet+ remove point from pointset (by not reappending)+ update bestpoint+ append point or old bestpoint to facet's outside set+ append bestpoint to facet's outside set (furthest)+ for all points remaining in pointset+ partition point into facets' outside sets and coplanar sets+*/+void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){+ setT *pointset;+ vertexT *vertex, **vertexp;+ pointT *point, **pointp, *bestpoint;+ int size, point_i, point_n, point_end, remaining, i, id;+ facetT *facet;+ realT bestdist= -REALmax, dist, distoutside;++ trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));+ pointset= qh_settemp(qh, numpoints);+ qh->num_outside= 0;+ pointp= SETaddr_(pointset, pointT);+ for (i=numpoints, point= points; i--; point += qh->hull_dim)+ *(pointp++)= point;+ qh_settruncate(qh, pointset, numpoints);+ FOREACHvertex_(vertices) {+ if ((id= qh_pointid(qh, vertex->point)) >= 0)+ SETelem_(pointset, id)= NULL;+ }+ id= qh_pointid(qh, qh->GOODpointp);+ if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)+ SETelem_(pointset, id)= NULL;+ if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/+ if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)+ SETelem_(pointset, id)= NULL;+ }+ if (!qh->BESToutside) { /* matches conditional for qh_partitionpoint below */+ distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */+ zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */+ remaining= qh->num_facets;+ point_end= numpoints;+ FORALLfacets {+ size= point_end/(remaining--) + 100;+ facet->outsideset= qh_setnew(qh, size);+ bestpoint= NULL;+ point_end= 0;+ FOREACHpoint_i_(qh, pointset) {+ if (point) {+ zzinc_(Zpartitionall);+ qh_distplane(qh, point, facet, &dist);+ if (dist < distoutside)+ SETelem_(pointset, point_end++)= point;+ else {+ qh->num_outside++;+ if (!bestpoint) {+ bestpoint= point;+ bestdist= dist;+ }else if (dist > bestdist) {+ qh_setappend(qh, &facet->outsideset, bestpoint);+ bestpoint= point;+ bestdist= dist;+ }else+ qh_setappend(qh, &facet->outsideset, point);+ }+ }+ }+ if (bestpoint) {+ qh_setappend(qh, &facet->outsideset, bestpoint);+#if !qh_COMPUTEfurthest+ facet->furthestdist= bestdist;+#endif+ }else+ qh_setfree(qh, &facet->outsideset);+ qh_settruncate(qh, pointset, point_end);+ }+ }+ /* if !qh->BESToutside, pointset contains points not assigned to outsideset */+ if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside) {+ qh->findbestnew= True;+ FOREACHpoint_i_(qh, pointset) {+ if (point)+ qh_partitionpoint(qh, point, qh->facet_list);+ }+ qh->findbestnew= False;+ }+ zzadd_(Zpartitionall, zzval_(Zpartition));+ zzval_(Zpartition)= 0;+ qh_settempfree(qh, &pointset);+ if (qh->IStracing >= 4)+ qh_printfacetlist(qh, qh->facet_list, NULL, True);+} /* partitionall */+++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="partitioncoplanar">-</a>++ qh_partitioncoplanar(qh, point, facet, dist )+ partition coplanar point to a facet+ dist is distance from point to facet+ if dist NULL,+ searches for bestfacet and does nothing if inside+ if qh.findbestnew set,+ searches new facets instead of using qh_findbest()++ returns:+ qh.max_ouside updated+ if qh.KEEPcoplanar or qh.KEEPinside+ point assigned to best coplanarset++ notes:+ facet->maxoutside is updated at end by qh_check_maxout++ design:+ if dist undefined+ find best facet for point+ if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)+ exit+ if keeping coplanar/nearinside/inside points+ if point is above furthest coplanar point+ append point to coplanar set (it is the new furthest)+ update qh.max_outside+ else+ append point one before end of coplanar set+ else if point is clearly outside of qh.max_outside and bestfacet->coplanarset+ and bestfacet is more than perpendicular to facet+ repartition the point using qh_findbest() -- it may be put on an outsideset+ else+ update qh.max_outside+*/+void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist) {+ facetT *bestfacet;+ pointT *oldfurthest;+ realT bestdist, dist2= 0, angle;+ int numpart= 0, oldfindbest;+ boolT isoutside;++ qh->WAScoplanar= True;+ if (!dist) {+ if (qh->findbestnew)+ bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);+ else+ bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,+ &bestdist, &isoutside, &numpart);+ zinc_(Ztotpartcoplanar);+ zzadd_(Zpartcoplanar, numpart);+ if (!qh->DELAUNAY && !qh->KEEPinside) { /* for 'd', bestdist skips upperDelaunay facets */+ if (qh->KEEPnearinside) {+ if (bestdist < -qh->NEARinside) {+ zinc_(Zcoplanarinside);+ trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",+ qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));+ return;+ }+ }else if (bestdist < -qh->MAXcoplanar) {+ trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",+ qh_pointid(qh, point), bestfacet->id, bestdist, qh->findbestnew));+ zinc_(Zcoplanarinside);+ return;+ }+ }+ }else {+ bestfacet= facet;+ bestdist= *dist;+ }+ if (bestdist > qh->max_outside) {+ if (!dist && facet != bestfacet) {+ zinc_(Zpartangle);+ angle= qh_getangle(qh, facet->normal, bestfacet->normal);+ if (angle < 0) {+ /* typically due to deleted vertex and coplanar facets, e.g.,+ RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */+ zinc_(Zpartflip);+ trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition point p%d from f%d. It is above flipped facet f%d dist %2.2g\n",+ qh_pointid(qh, point), facet->id, bestfacet->id, bestdist));+ oldfindbest= qh->findbestnew;+ qh->findbestnew= False;+ qh_partitionpoint(qh, point, bestfacet);+ qh->findbestnew= oldfindbest;+ return;+ }+ }+ qh->max_outside= bestdist;+ if (bestdist > qh->TRACEdist) {+ qh_fprintf(qh, qh->ferr, 8122, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",+ qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);+ qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);+ }+ }+ if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {+ oldfurthest= (pointT*)qh_setlast(bestfacet->coplanarset);+ if (oldfurthest) {+ zinc_(Zcomputefurthest);+ qh_distplane(qh, oldfurthest, bestfacet, &dist2);+ }+ if (!oldfurthest || dist2 < bestdist)+ qh_setappend(qh, &bestfacet->coplanarset, point);+ else+ qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);+ }+ trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d(or inside) dist %2.2g\n",+ qh_pointid(qh, point), bestfacet->id, bestdist));+} /* partitioncoplanar */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="partitionpoint">-</a>++ qh_partitionpoint(qh, point, facet )+ assigns point to an outside set, coplanar set, or inside set (i.e., dropt)+ if qh.findbestnew+ uses qh_findbestnew() to search all new facets+ else+ uses qh_findbest()++ notes:+ after qh_distplane(), this and qh_findbest() are most expensive in 3-d++ design:+ find best facet for point+ (either exhaustive search of new facets or directed search from facet)+ if qh.NARROWhull+ retain coplanar and nearinside points as outside points+ if point is outside bestfacet+ if point above furthest point for bestfacet+ append point to outside set (it becomes the new furthest)+ if outside set was empty+ move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)+ update bestfacet->furthestdist+ else+ append point one before end of outside set+ else if point is coplanar to bestfacet+ if keeping coplanar points or need to update qh.max_outside+ partition coplanar point into bestfacet+ else if near-inside point+ partition as coplanar point into bestfacet+ else is an inside point+ if keeping inside points+ partition as coplanar point into bestfacet+*/+void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {+ realT bestdist;+ boolT isoutside;+ facetT *bestfacet;+ int numpart;+#if qh_COMPUTEfurthest+ realT dist;+#endif++ if (qh->findbestnew)+ bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);+ else+ bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,+ &bestdist, &isoutside, &numpart);+ zinc_(Ztotpartition);+ zzadd_(Zpartition, numpart);+ if (qh->NARROWhull) {+ if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)+ qh_precision(qh, "nearly incident point(narrow hull)");+ if (qh->KEEPnearinside) {+ if (bestdist >= -qh->NEARinside)+ isoutside= True;+ }else if (bestdist >= -qh->MAXcoplanar)+ isoutside= True;+ }++ if (isoutside) {+ if (!bestfacet->outsideset+ || !qh_setlast(bestfacet->outsideset)) {+ qh_setappend(qh, &(bestfacet->outsideset), point);+ if (!bestfacet->newfacet) {+ qh_removefacet(qh, bestfacet); /* make sure it's after qh->facet_next */+ qh_appendfacet(qh, bestfacet);+ }+#if !qh_COMPUTEfurthest+ bestfacet->furthestdist= bestdist;+#endif+ }else {+#if qh_COMPUTEfurthest+ zinc_(Zcomputefurthest);+ qh_distplane(qh, oldfurthest, bestfacet, &dist);+ if (dist < bestdist)+ qh_setappend(qh, &(bestfacet->outsideset), point);+ else+ qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);+#else+ if (bestfacet->furthestdist < bestdist) {+ qh_setappend(qh, &(bestfacet->outsideset), point);+ bestfacet->furthestdist= bestdist;+ }else+ qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);+#endif+ }+ qh->num_outside++;+ trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d new? %d (or narrowhull)\n",+ qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet));+ }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */+ zzinc_(Zcoplanarpart);+ if (qh->DELAUNAY)+ qh_precision(qh, "nearly incident point");+ if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)+ qh_partitioncoplanar(qh, point, bestfacet, &bestdist);+ else {+ trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",+ qh_pointid(qh, point), bestfacet->id));+ }+ }else if (qh->KEEPnearinside && bestdist > -qh->NEARinside) {+ zinc_(Zpartnear);+ qh_partitioncoplanar(qh, point, bestfacet, &bestdist);+ }else {+ zinc_(Zpartinside);+ trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",+ qh_pointid(qh, point), bestfacet->id, bestdist));+ if (qh->KEEPinside)+ qh_partitioncoplanar(qh, point, bestfacet, &bestdist);+ }+} /* partitionpoint */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="partitionvisible">-</a>++ qh_partitionvisible(qh, allpoints, numoutside )+ partitions points in visible facets to qh.newfacet_list+ qh.visible_list= visible facets+ for visible facets+ 1st neighbor (if any) points to a horizon facet or a new facet+ if allpoints(!used),+ repartitions coplanar points++ returns:+ updates outside sets and coplanar sets of qh.newfacet_list+ updates qh.num_outside (count of outside points)++ notes:+ qh.findbest_notsharp should be clear (extra work if set)++ design:+ for all visible facets with outside set or coplanar set+ select a newfacet for visible facet+ if outside set+ partition outside set into new facets+ if coplanar set and keeping coplanar/near-inside/inside points+ if allpoints+ partition coplanar set into new facets, may be assigned outside+ else+ partition coplanar set into coplanar sets of new facets+ for each deleted vertex+ if allpoints+ partition vertex into new facets, may be assigned outside+ else+ partition vertex into coplanar sets of new facets+*/+void qh_partitionvisible(qhT *qh /*qh.visible_list*/, boolT allpoints, int *numoutside) {+ facetT *visible, *newfacet;+ pointT *point, **pointp;+ int coplanar=0, size;+ unsigned count;+ vertexT *vertex, **vertexp;++ if (qh->ONLYmax)+ maximize_(qh->MINoutside, qh->max_vertex);+ *numoutside= 0;+ FORALLvisible_facets {+ if (!visible->outsideset && !visible->coplanarset)+ continue;+ newfacet= visible->f.replace;+ count= 0;+ while (newfacet && newfacet->visible) {+ newfacet= newfacet->f.replace;+ if (count++ > qh->facet_id)+ qh_infiniteloop(qh, visible);+ }+ if (!newfacet)+ newfacet= qh->newfacet_list;+ if (newfacet == qh->facet_tail) {+ qh_fprintf(qh, qh->ferr, 6170, "qhull precision error (qh_partitionvisible): all new facets deleted as\n degenerate facets. Can not continue.\n");+ qh_errexit(qh, qh_ERRprec, NULL, NULL);+ }+ if (visible->outsideset) {+ size= qh_setsize(qh, visible->outsideset);+ *numoutside += size;+ qh->num_outside -= size;+ FOREACHpoint_(visible->outsideset)+ qh_partitionpoint(qh, point, newfacet);+ }+ if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {+ size= qh_setsize(qh, visible->coplanarset);+ coplanar += size;+ FOREACHpoint_(visible->coplanarset) {+ if (allpoints) /* not used */+ qh_partitionpoint(qh, point, newfacet);+ else+ qh_partitioncoplanar(qh, point, newfacet, NULL);+ }+ }+ }+ FOREACHvertex_(qh->del_vertices) {+ if (vertex->point) {+ if (allpoints) /* not used */+ qh_partitionpoint(qh, vertex->point, qh->newfacet_list);+ else+ qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL);+ }+ }+ trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));+} /* partitionvisible */++++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="precision">-</a>++ qh_precision(qh, reason )+ restart on precision errors if not merging and if 'QJn'+*/+void qh_precision(qhT *qh, const char *reason) {++ if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {+ if (qh->JOGGLEmax < REALmax/2) {+ trace0((qh, qh->ferr, 26, "qh_precision: qhull restart because of %s\n", reason));+ /* May be called repeatedly if qh->ALLOWrestart */+ longjmp(qh->restartexit, qh_ERRprec);+ }+ }+} /* qh_precision */++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="printsummary">-</a>++ qh_printsummary(qh, fp )+ prints summary to fp++ notes:+ not in io_r.c so that user_eg.c can prevent io_r.c from loading+ qh_printsummary and qh_countfacets must match counts++ design:+ determine number of points, vertices, and coplanar points+ print summary+*/+void qh_printsummary(qhT *qh, FILE *fp) {+ realT ratio, outerplane, innerplane;+ float cpu;+ int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;+ int goodused;+ facetT *facet;+ const char *s;+ int numdel= zzval_(Zdelvertextot);+ int numtricoplanars= 0;++ size= qh->num_points + qh_setsize(qh, qh->other_points);+ numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);+ id= qh_pointid(qh, qh->GOODpointp);+ FORALLfacets {+ if (facet->coplanarset)+ numcoplanars += qh_setsize(qh, facet->coplanarset);+ if (facet->good) {+ if (facet->simplicial) {+ if (facet->keepcentrum && facet->tricoplanar)+ numtricoplanars++;+ }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)+ nonsimplicial++;+ }+ }+ if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)+ size--;+ if (qh->STOPcone || qh->STOPpoint)+ qh_fprintf(qh, fp, 9288, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");+ if (qh->UPPERdelaunay)+ goodused= qh->GOODvertex + qh->GOODpoint + qh->SPLITthresholds;+ else if (qh->DELAUNAY)+ goodused= qh->GOODvertex + qh->GOODpoint + qh->GOODthreshold;+ else+ goodused= qh->num_good;+ nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);+ if (qh->VORONOI) {+ if (qh->UPPERdelaunay)+ qh_fprintf(qh, fp, 9289, "\n\+Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ else+ qh_fprintf(qh, fp, 9290, "\n\+Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ qh_fprintf(qh, fp, 9291, " Number of Voronoi regions%s: %d\n",+ qh->ATinfinity ? " and at-infinity" : "", numvertices);+ if (numdel)+ qh_fprintf(qh, fp, 9292, " Total number of deleted points due to merging: %d\n", numdel);+ if (numcoplanars - numdel > 0)+ qh_fprintf(qh, fp, 9293, " Number of nearly incident points: %d\n", numcoplanars - numdel);+ else if (size - numvertices - numdel > 0)+ qh_fprintf(qh, fp, 9294, " Total number of nearly incident points: %d\n", size - numvertices - numdel);+ qh_fprintf(qh, fp, 9295, " Number of%s Voronoi vertices: %d\n",+ goodused ? " 'good'" : "", qh->num_good);+ if (nonsimplicial)+ qh_fprintf(qh, fp, 9296, " Number of%s non-simplicial Voronoi vertices: %d\n",+ goodused ? " 'good'" : "", nonsimplicial);+ }else if (qh->DELAUNAY) {+ if (qh->UPPERdelaunay)+ qh_fprintf(qh, fp, 9297, "\n\+Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ else+ qh_fprintf(qh, fp, 9298, "\n\+Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ qh_fprintf(qh, fp, 9299, " Number of input sites%s: %d\n",+ qh->ATinfinity ? " and at-infinity" : "", numvertices);+ if (numdel)+ qh_fprintf(qh, fp, 9300, " Total number of deleted points due to merging: %d\n", numdel);+ if (numcoplanars - numdel > 0)+ qh_fprintf(qh, fp, 9301, " Number of nearly incident points: %d\n", numcoplanars - numdel);+ else if (size - numvertices - numdel > 0)+ qh_fprintf(qh, fp, 9302, " Total number of nearly incident points: %d\n", size - numvertices - numdel);+ qh_fprintf(qh, fp, 9303, " Number of%s Delaunay regions: %d\n",+ goodused ? " 'good'" : "", qh->num_good);+ if (nonsimplicial)+ qh_fprintf(qh, fp, 9304, " Number of%s non-simplicial Delaunay regions: %d\n",+ goodused ? " 'good'" : "", nonsimplicial);+ }else if (qh->HALFspace) {+ qh_fprintf(qh, fp, 9305, "\n\+Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ qh_fprintf(qh, fp, 9306, " Number of halfspaces: %d\n", size);+ qh_fprintf(qh, fp, 9307, " Number of non-redundant halfspaces: %d\n", numvertices);+ if (numcoplanars) {+ if (qh->KEEPinside && qh->KEEPcoplanar)+ s= "similar and redundant";+ else if (qh->KEEPinside)+ s= "redundant";+ else+ s= "similar";+ qh_fprintf(qh, fp, 9308, " Number of %s halfspaces: %d\n", s, numcoplanars);+ }+ qh_fprintf(qh, fp, 9309, " Number of intersection points: %d\n", qh->num_facets - qh->num_visible);+ if (goodused)+ qh_fprintf(qh, fp, 9310, " Number of 'good' intersection points: %d\n", qh->num_good);+ if (nonsimplicial)+ qh_fprintf(qh, fp, 9311, " Number of%s non-simplicial intersection points: %d\n",+ goodused ? " 'good'" : "", nonsimplicial);+ }else {+ qh_fprintf(qh, fp, 9312, "\n\+Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);+ qh_fprintf(qh, fp, 9313, " Number of vertices: %d\n", numvertices);+ if (numcoplanars) {+ if (qh->KEEPinside && qh->KEEPcoplanar)+ s= "coplanar and interior";+ else if (qh->KEEPinside)+ s= "interior";+ else+ s= "coplanar";+ qh_fprintf(qh, fp, 9314, " Number of %s points: %d\n", s, numcoplanars);+ }+ qh_fprintf(qh, fp, 9315, " Number of facets: %d\n", qh->num_facets - qh->num_visible);+ if (goodused)+ qh_fprintf(qh, fp, 9316, " Number of 'good' facets: %d\n", qh->num_good);+ if (nonsimplicial)+ qh_fprintf(qh, fp, 9317, " Number of%s non-simplicial facets: %d\n",+ goodused ? " 'good'" : "", nonsimplicial);+ }+ if (numtricoplanars)+ qh_fprintf(qh, fp, 9318, " Number of triangulated facets: %d\n", numtricoplanars);+ qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",+ qh->rbox_command, qh->qhull_command);+ if (qh->ROTATErandom != INT_MIN)+ qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);+ else+ qh_fprintf(qh, fp, 9321, "\n\n");+ qh_fprintf(qh, fp, 9322, " Number of points processed: %d\n", zzval_(Zprocessed));+ qh_fprintf(qh, fp, 9323, " Number of hyperplanes created: %d\n", zzval_(Zsetplane));+ if (qh->DELAUNAY)+ qh_fprintf(qh, fp, 9324, " Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);+ qh_fprintf(qh, fp, 9325, " Number of distance tests for qhull: %d\n", zzval_(Zpartition)++ zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));+#if 0 /* NOTE: must print before printstatistics() */+ {realT stddev, ave;+ qh_fprintf(qh, fp, 9326, " average new facet balance: %2.2g\n",+ wval_(Wnewbalance)/zval_(Zprocessed));+ stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),+ wval_(Wnewbalance2), &ave);+ qh_fprintf(qh, fp, 9327, " new facet standard deviation: %2.2g\n", stddev);+ qh_fprintf(qh, fp, 9328, " average partition balance: %2.2g\n",+ wval_(Wpbalance)/zval_(Zpbalance));+ stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),+ wval_(Wpbalance2), &ave);+ qh_fprintf(qh, fp, 9329, " partition standard deviation: %2.2g\n", stddev);+ }+#endif+ if (nummerged) {+ qh_fprintf(qh, fp, 9330," Number of distance tests for merging: %d\n",zzval_(Zbestdist)++ zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)++ zzval_(Zdistzero));+ qh_fprintf(qh, fp, 9331," Number of distance tests for checking: %d\n",zzval_(Zcheckpart));+ qh_fprintf(qh, fp, 9332," Number of merged facets: %d\n", nummerged);+ }+ if (!qh->RANDOMoutside && qh->QHULLfinished) {+ cpu= (float)qh->hulltime;+ cpu /= (float)qh_SECticks;+ wval_(Wcpu)= cpu;+ qh_fprintf(qh, fp, 9333, " CPU seconds to compute hull (after input): %2.4g\n", cpu);+ }+ if (qh->RERUN) {+ if (!qh->PREmerge && !qh->MERGEexact)+ qh_fprintf(qh, fp, 9334, " Percentage of runs with precision errors: %4.1f\n",+ zzval_(Zretry)*100.0/qh->build_cnt); /* careful of order */+ }else if (qh->JOGGLEmax < REALmax/2) {+ if (zzval_(Zretry))+ qh_fprintf(qh, fp, 9335, " After %d retries, input joggled by: %2.2g\n",+ zzval_(Zretry), qh->JOGGLEmax);+ else+ qh_fprintf(qh, fp, 9336, " Input joggled by: %2.2g\n", qh->JOGGLEmax);+ }+ if (qh->totarea != 0.0)+ qh_fprintf(qh, fp, 9337, " %s facet area: %2.8g\n",+ zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);+ if (qh->totvol != 0.0)+ qh_fprintf(qh, fp, 9338, " %s volume: %2.8g\n",+ zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);+ if (qh->MERGING) {+ qh_outerinner(qh, NULL, &outerplane, &innerplane);+ if (outerplane > 2 * qh->DISTround) {+ qh_fprintf(qh, fp, 9339, " Maximum distance of %spoint above facet: %2.2g",+ (qh->QHULLfinished ? "" : "merged "), outerplane);+ ratio= outerplane/(qh->ONEmerge + qh->DISTround);+ /* don't report ratio if MINoutside is large */+ if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)+ qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);+ else+ qh_fprintf(qh, fp, 9341, "\n");+ }+ if (innerplane < -2 * qh->DISTround) {+ qh_fprintf(qh, fp, 9342, " Maximum distance of %svertex below facet: %2.2g",+ (qh->QHULLfinished ? "" : "merged "), innerplane);+ ratio= -innerplane/(qh->ONEmerge+qh->DISTround);+ if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)+ qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);+ else+ qh_fprintf(qh, fp, 9344, "\n");+ }+ }+ qh_fprintf(qh, fp, 9345, "\n");+} /* printsummary */++
+ Cdir/mem_r.c view
@@ -0,0 +1,562 @@+/*<html><pre> -<a href="qh-mem_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ mem_r.c+ memory management routines for qhull++ See libqhull/mem_r.c for a standalone program.++ To initialize memory:++ qh_meminit(qh, stderr);+ qh_meminitbuffers(qh, qh->IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);+ qh_memsize(qh, (int)sizeof(facetT));+ qh_memsize(qh, (int)sizeof(facetT));+ ...+ qh_memsetup(qh);++ To free up all memory buffers:+ qh_memfreeshort(qh, &curlong, &totlong);++ if qh_NOmem,+ malloc/free is used instead of mem.c++ notes:+ uses Quickfit algorithm (freelists for commonly allocated sizes)+ assumes small sizes for freelists (it discards the tail of memory buffers)++ see:+ qh-mem_r.htm and mem_r.h+ global_r.c (qh_initbuffers) for an example of using mem_r.c++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/mem_r.c#5 $$Change: 2065 $+ $DateTime: 2016/01/18 13:51:04 $$Author: bbarber $+*/++#include "libqhull_r.h" /* includes user_r.h and mem_r.h */++#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#ifndef qh_NOmem++/*============= internal functions ==============*/++static int qh_intcompare(const void *i, const void *j);++/*========== functions in alphabetical order ======== */++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="intcompare">-</a>++ qh_intcompare( i, j )+ used by qsort and bsearch to compare two integers+*/+static int qh_intcompare(const void *i, const void *j) {+ return(*((const int *)i) - *((const int *)j));+} /* intcompare */+++/*-<a href="qh-mem_r.htm#TOC"+ >--------------------------------</a><a name="memalloc">-</a>++ qh_memalloc( qh, insize )+ returns object of insize bytes+ qhmem is the global memory structure++ returns:+ pointer to allocated memory+ errors if insufficient memory++ notes:+ use explicit type conversion to avoid type warnings on some compilers+ actual object may be larger than insize+ use qh_memalloc_() for inline code for quick allocations+ logs allocations if 'T5'+ caller is responsible for freeing the memory.+ short memory is freed on shutdown by qh_memfreeshort unless qh_NOmem++ design:+ if size < qh->qhmem.LASTsize+ if qh->qhmem.freelists[size] non-empty+ return first object on freelist+ else+ round up request to size of qh->qhmem.freelists[size]+ allocate new allocation buffer if necessary+ allocate object from allocation buffer+ else+ allocate object with qh_malloc() in user.c+*/+void *qh_memalloc(qhT *qh, int insize) {+ void **freelistp, *newbuffer;+ int idx, size, n;+ int outsize, bufsize;+ void *object;++ if (insize<0) {+ qh_fprintf(qh, qh->qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d). Did int overflow due to high-D?\n", insize); /* WARN64 */+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ if (insize>=0 && insize <= qh->qhmem.LASTsize) {+ idx= qh->qhmem.indextable[insize];+ outsize= qh->qhmem.sizetable[idx];+ qh->qhmem.totshort += outsize;+ freelistp= qh->qhmem.freelists+idx;+ if ((object= *freelistp)) {+ qh->qhmem.cntquick++;+ qh->qhmem.totfree -= outsize;+ *freelistp= *((void **)*freelistp); /* replace freelist with next object */+#ifdef qh_TRACEshort+ n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);+#endif+ return(object);+ }else {+ qh->qhmem.cntshort++;+ if (outsize > qh->qhmem.freesize) {+ qh->qhmem.totdropped += qh->qhmem.freesize;+ if (!qh->qhmem.curbuffer)+ bufsize= qh->qhmem.BUFinit;+ else+ bufsize= qh->qhmem.BUFsize;+ if (!(newbuffer= qh_malloc((size_t)bufsize))) {+ qh_fprintf(qh, qh->qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ *((void **)newbuffer)= qh->qhmem.curbuffer; /* prepend newbuffer to curbuffer+ list. newbuffer!=0 by QH6080 */+ qh->qhmem.curbuffer= newbuffer;+ size= (sizeof(void **) + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;+ qh->qhmem.freemem= (void *)((char *)newbuffer+size);+ qh->qhmem.freesize= bufsize - size;+ qh->qhmem.totbuffer += bufsize - size; /* easier to check */+ /* Periodically test totbuffer. It matches at beginning and exit of every call */+ n = qh->qhmem.totshort + qh->qhmem.totfree + qh->qhmem.totdropped + qh->qhmem.freesize - outsize;+ if (qh->qhmem.totbuffer != n) {+ qh_fprintf(qh, qh->qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qh->qhmem.totbuffer, n);+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ }+ object= qh->qhmem.freemem;+ qh->qhmem.freemem= (void *)((char *)qh->qhmem.freemem + outsize);+ qh->qhmem.freesize -= outsize;+ qh->qhmem.totunused += outsize - insize;+#ifdef qh_TRACEshort+ n= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);+#endif+ return object;+ }+ }else { /* long allocation */+ if (!qh->qhmem.indextable) {+ qh_fprintf(qh, qh->qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ outsize= insize;+ qh->qhmem.cntlong++;+ qh->qhmem.totlong += outsize;+ if (qh->qhmem.maxlong < qh->qhmem.totlong)+ qh->qhmem.maxlong= qh->qhmem.totlong;+ if (!(object= qh_malloc((size_t)outsize))) {+ qh_fprintf(qh, qh->qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, outsize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);+ }+ return(object);+} /* memalloc */+++/*-<a href="qh-mem_r.htm#TOC"+ >--------------------------------</a><a name="memcheck">-</a>++ qh_memcheck(qh)+*/+void qh_memcheck(qhT *qh) {+ int i, count, totfree= 0;+ void *object;++ if (!qh) {+ qh_fprintf_stderr(6243, "qh_memcheck(qh) error: qh is 0. It does not point to a qhT");+ qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */+ }+ if (qh->qhmem.ferr == 0 || qh->qhmem.IStracing < 0 || qh->qhmem.IStracing > 10 || (((qh->qhmem.ALIGNmask+1) & qh->qhmem.ALIGNmask) != 0)) {+ qh_fprintf_stderr(6244, "qh_memcheck error: either qh->qhmem is overwritten or qh->qhmem is not initialized. Call qh_mem_new() or qh_new_qhull() before calling qh_mem routines. ferr 0x%x IsTracing %d ALIGNmask 0x%x", qh->qhmem.ferr, qh->qhmem.IStracing, qh->qhmem.ALIGNmask);+ qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */+ return;+ }+ if (qh->qhmem.IStracing != 0)+ qh_fprintf(qh, qh->qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qh->qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qh->qhmem\n");+ for (i=0; i < qh->qhmem.TABLEsize; i++) {+ count=0;+ for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))+ count++;+ totfree += qh->qhmem.sizetable[i] * count;+ }+ if (totfree != qh->qhmem.totfree) {+ qh_fprintf(qh, qh->qhmem.ferr, 6211, "Qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qh->qhmem.totfree, totfree);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ if (qh->qhmem.IStracing != 0)+ qh_fprintf(qh, qh->qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree is the same as qh->qhmem.totfree\n", totfree);+} /* memcheck */++/*-<a href="qh-mem_r.htm#TOC"+ >--------------------------------</a><a name="memfree">-</a>++ qh_memfree(qh, object, insize )+ free up an object of size bytes+ size is insize from qh_memalloc++ notes:+ object may be NULL+ type checking warns if using (void **)object+ use qh_memfree_() for quick free's of small objects++ design:+ if size <= qh->qhmem.LASTsize+ append object to corresponding freelist+ else+ call qh_free(object)+*/+void qh_memfree(qhT *qh, void *object, int insize) {+ void **freelistp;+ int idx, outsize;++ if (!object)+ return;+ if (insize <= qh->qhmem.LASTsize) {+ qh->qhmem.freeshort++;+ idx= qh->qhmem.indextable[insize];+ outsize= qh->qhmem.sizetable[idx];+ qh->qhmem.totfree += outsize;+ qh->qhmem.totshort -= outsize;+ freelistp= qh->qhmem.freelists + idx;+ *((void **)object)= *freelistp;+ *freelistp= object;+#ifdef qh_TRACEshort+ idx= qh->qhmem.cntshort+qh->qhmem.cntquick+qh->qhmem.freeshort;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qh->qhmem.totshort, qh->qhmem.cntshort+qh->qhmem.cntquick-qh->qhmem.freeshort);+#endif+ }else {+ qh->qhmem.freelong++;+ qh->qhmem.totlong -= insize;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);+ qh_free(object);+ }+} /* memfree */+++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="memfreeshort">-</a>++ qh_memfreeshort(qh, curlong, totlong )+ frees up all short and qhmem memory allocations++ returns:+ number and size of current long allocations++ notes:+ if qh_NOmem (qh_malloc() for all allocations),+ short objects (e.g., facetT) are not recovered.+ use qh_freeqhull(qh, qh_ALL) instead.++ see:+ qh_freeqhull(qh, allMem)+ qh_memtotal(qh, curlong, totlong, curshort, totshort, maxlong, totbuffer);+*/+void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {+ void *buffer, *nextbuffer;+ FILE *ferr;++ *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;+ *totlong= qh->qhmem.totlong;+ for (buffer= qh->qhmem.curbuffer; buffer; buffer= nextbuffer) {+ nextbuffer= *((void **) buffer);+ qh_free(buffer);+ }+ qh->qhmem.curbuffer= NULL;+ if (qh->qhmem.LASTsize) {+ qh_free(qh->qhmem.indextable);+ qh_free(qh->qhmem.freelists);+ qh_free(qh->qhmem.sizetable);+ }+ ferr= qh->qhmem.ferr;+ memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */+ qh->qhmem.ferr= ferr;+} /* memfreeshort */+++/*-<a href="qh-mem_r.htm#TOC"+ >--------------------------------</a><a name="meminit">-</a>++ qh_meminit(qh, ferr )+ initialize qhmem and test sizeof( void*)+ Does not throw errors. qh_exit on failure+*/+void qh_meminit(qhT *qh, FILE *ferr) {++ memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */+ if (ferr)+ qh->qhmem.ferr= ferr;+ else+ qh->qhmem.ferr= stderr;+ if (sizeof(void*) < sizeof(int)) {+ qh_fprintf(qh, qh->qhmem.ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));+ qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */+ }+ if (sizeof(void*) > sizeof(ptr_intT)) {+ qh_fprintf(qh, qh->qhmem.ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));+ qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */+ }+ qh_memcheck(qh);+} /* meminit */++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="meminitbuffers">-</a>++ qh_meminitbuffers(qh, tracelevel, alignment, numsizes, bufsize, bufinit )+ initialize qhmem+ if tracelevel >= 5, trace memory allocations+ alignment= desired address alignment for memory allocations+ numsizes= number of freelists+ bufsize= size of additional memory buffers for short allocations+ bufinit= size of initial memory buffer for short allocations+*/+void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {++ qh->qhmem.IStracing= tracelevel;+ qh->qhmem.NUMsizes= numsizes;+ qh->qhmem.BUFsize= bufsize;+ qh->qhmem.BUFinit= bufinit;+ qh->qhmem.ALIGNmask= alignment-1;+ if (qh->qhmem.ALIGNmask & ~qh->qhmem.ALIGNmask) {+ qh_fprintf(qh, qh->qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ qh->qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));+ qh->qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));+ if (!qh->qhmem.sizetable || !qh->qhmem.freelists) {+ qh_fprintf(qh, qh->qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ if (qh->qhmem.IStracing >= 1)+ qh_fprintf(qh, qh->qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);+} /* meminitbuffers */++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="memsetup">-</a>++ qh_memsetup(qh)+ set up memory after running memsize()+*/+void qh_memsetup(qhT *qh) {+ int k,i;++ qsort(qh->qhmem.sizetable, (size_t)qh->qhmem.TABLEsize, sizeof(int), qh_intcompare);+ qh->qhmem.LASTsize= qh->qhmem.sizetable[qh->qhmem.TABLEsize-1];+ if(qh->qhmem.LASTsize >= qh->qhmem.BUFsize || qh->qhmem.LASTsize >= qh->qhmem.BUFinit) {+ qh_fprintf(qh, qh->qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",+ qh->qhmem.LASTsize, qh->qhmem.BUFsize, qh->qhmem.BUFinit);+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ if (!(qh->qhmem.indextable= (int *)qh_malloc((qh->qhmem.LASTsize+1) * sizeof(int)))) {+ qh_fprintf(qh, qh->qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ for (k=qh->qhmem.LASTsize+1; k--; )+ qh->qhmem.indextable[k]= k;+ i= 0;+ for (k=0; k <= qh->qhmem.LASTsize; k++) {+ if (qh->qhmem.indextable[k] <= qh->qhmem.sizetable[i])+ qh->qhmem.indextable[k]= i;+ else+ qh->qhmem.indextable[k]= ++i;+ }+} /* memsetup */++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="memsize">-</a>++ qh_memsize(qh, size )+ define a free list for this size+*/+void qh_memsize(qhT *qh, int size) {+ int k;++ if(qh->qhmem.LASTsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ size= (size + qh->qhmem.ALIGNmask) & ~qh->qhmem.ALIGNmask;+ for (k=qh->qhmem.TABLEsize; k--; ) {+ if (qh->qhmem.sizetable[k] == size)+ return;+ }+ if (qh->qhmem.TABLEsize < qh->qhmem.NUMsizes)+ qh->qhmem.sizetable[qh->qhmem.TABLEsize++]= size;+ else+ qh_fprintf(qh, qh->qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qh->qhmem.NUMsizes);+} /* memsize */+++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="memstatistics">-</a>++ qh_memstatistics(qh, fp )+ print out memory statistics++ Verifies that qh->qhmem.totfree == sum of freelists+*/+void qh_memstatistics(qhT *qh, FILE *fp) {+ int i;+ int count;+ void *object;++ qh_memcheck(qh);+ qh_fprintf(qh, fp, 9278, "\nmemory statistics:\n\+%7d quick allocations\n\+%7d short allocations\n\+%7d long allocations\n\+%7d short frees\n\+%7d long frees\n\+%7d bytes of short memory in use\n\+%7d bytes of short memory in freelists\n\+%7d bytes of dropped short memory\n\+%7d bytes of unused short memory (estimated)\n\+%7d bytes of long memory allocated (max, except for input)\n\+%7d bytes of long memory in use (in %d pieces)\n\+%7d bytes of short memory buffers (minus links)\n\+%7d bytes per short memory buffer (initially %d bytes)\n",+ qh->qhmem.cntquick, qh->qhmem.cntshort, qh->qhmem.cntlong,+ qh->qhmem.freeshort, qh->qhmem.freelong,+ qh->qhmem.totshort, qh->qhmem.totfree,+ qh->qhmem.totdropped + qh->qhmem.freesize, qh->qhmem.totunused,+ qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong,+ qh->qhmem.totbuffer, qh->qhmem.BUFsize, qh->qhmem.BUFinit);+ if (qh->qhmem.cntlarger) {+ qh_fprintf(qh, fp, 9279, "%7d calls to qh_setlarger\n%7.2g average copy size\n",+ qh->qhmem.cntlarger, ((float)qh->qhmem.totlarger)/(float)qh->qhmem.cntlarger);+ qh_fprintf(qh, fp, 9280, " freelists(bytes->count):");+ }+ for (i=0; i < qh->qhmem.TABLEsize; i++) {+ count=0;+ for (object= qh->qhmem.freelists[i]; object; object= *((void **)object))+ count++;+ qh_fprintf(qh, fp, 9281, " %d->%d", qh->qhmem.sizetable[i], count);+ }+ qh_fprintf(qh, fp, 9282, "\n\n");+} /* memstatistics */+++/*-<a href="qh-mem_r.htm#TOC"+ >-------------------------------</a><a name="NOmem">-</a>++ qh_NOmem+ turn off quick-fit memory allocation++ notes:+ uses qh_malloc() and qh_free() instead+*/+#else /* qh_NOmem */++void *qh_memalloc(qhT *qh, int insize) {+ void *object;++ if (!(object= qh_malloc((size_t)insize))) {+ qh_fprintf(qh, qh->qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ qh->qhmem.cntlong++;+ qh->qhmem.totlong += insize;+ if (qh->qhmem.maxlong < qh->qhmem.totlong)+ qh->qhmem.maxlong= qh->qhmem.totlong;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);+ return object;+}++void qh_memfree(qhT *qh, void *object, int insize) {++ if (!object)+ return;+ qh_free(object);+ qh->qhmem.freelong++;+ qh->qhmem.totlong -= insize;+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qh->qhmem.cntlong+qh->qhmem.freelong, insize, qh->qhmem.totlong, qh->qhmem.cntlong-qh->qhmem.freelong);+}++void qh_memfreeshort(qhT *qh, int *curlong, int *totlong) {+ *totlong= qh->qhmem.totlong;+ *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;+ memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */+}++void qh_meminit(qhT *qh, FILE *ferr) {++ memset((char *)&qh->qhmem, 0, sizeof(qh->qhmem)); /* every field is 0, FALSE, NULL */+ if (ferr)+ qh->qhmem.ferr= ferr;+ else+ qh->qhmem.ferr= stderr;+ if (sizeof(void*) < sizeof(int)) {+ qh_fprintf(qh, qh->qhmem.ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+}++void qh_meminitbuffers(qhT *qh, int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {++ qh->qhmem.IStracing= tracelevel;+}++void qh_memsetup(qhT *qh) {++}++void qh_memsize(qhT *qh, int size) {++}++void qh_memstatistics(qhT *qh, FILE *fp) {++ qh_fprintf(qh, fp, 9409, "\nmemory statistics:\n\+%7d long allocations\n\+%7d long frees\n\+%7d bytes of long memory allocated (max, except for input)\n\+%7d bytes of long memory in use (in %d pieces)\n",+ qh->qhmem.cntlong,+ qh->qhmem.freelong,+ qh->qhmem.maxlong, qh->qhmem.totlong, qh->qhmem.cntlong - qh->qhmem.freelong);+}++#endif /* qh_NOmem */++/*-<a href="qh-mem_r.htm#TOC"+>-------------------------------</a><a name="memtotlong">-</a>++ qh_memtotal(qh, totlong, curlong, totshort, curshort, maxlong, totbuffer )+ Return the total, allocated long and short memory++ returns:+ Returns the total current bytes of long and short allocations+ Returns the current count of long and short allocations+ Returns the maximum long memory and total short buffer (minus one link per buffer)+ Does not error (for deprecated UsingLibQhull.cpp (libqhullpcpp))+*/+void qh_memtotal(qhT *qh, int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {+ *totlong= qh->qhmem.totlong;+ *curlong= qh->qhmem.cntlong - qh->qhmem.freelong;+ *totshort= qh->qhmem.totshort;+ *curshort= qh->qhmem.cntshort + qh->qhmem.cntquick - qh->qhmem.freeshort;+ *maxlong= qh->qhmem.maxlong;+ *totbuffer= qh->qhmem.totbuffer;+} /* memtotlong */
+ Cdir/merge_r.c view
@@ -0,0 +1,3627 @@+/*<html><pre> -<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="TOP">-</a>++ merge_r.c+ merges non-convex facets++ see qh-merge_r.htm and merge_r.h++ other modules call qh_premerge() and qh_postmerge()++ the user may call qh_postmerge() to perform additional merges.++ To remove deleted facets and vertices (qhull() in libqhull_r.c):+ qh_partitionvisible(qh, !qh_ALL, &numoutside); // visible_list, newfacet_list+ qh_deletevisible(); // qh.visible_list+ qh_resetlists(qh, False, qh_RESETvisible); // qh.visible_list newvertex_list newfacet_list++ assumes qh.CENTERtype= centrum++ merges occur in qh_mergefacet and in qh_mergecycle+ vertex->neighbors not set until the first merge occurs++ Copyright (c) 1993-2015 C.B. Barber.+ $Id: //main/2015/qhull/src/libqhull_r/merge_r.c#5 $$Change: 2064 $+ $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $+*/++#include "qhull_ra.h"++#ifndef qh_NOmerge++/*===== functions(alphabetical after premerge and postmerge) ======*/++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="premerge">-</a>++ qh_premerge(qh, apex, maxcentrum )+ pre-merge nonconvex facets in qh.newfacet_list for apex+ maxcentrum defines coplanar and concave (qh_test_appendmerge)++ returns:+ deleted facets added to qh.visible_list with facet->visible set++ notes:+ uses globals, qh.MERGEexact, qh.PREmerge++ design:+ mark duplicate ridges in qh.newfacet_list+ merge facet cycles in qh.newfacet_list+ merge duplicate ridges and concave facets in qh.newfacet_list+ check merged facet cycles for degenerate and redundant facets+ merge degenerate and redundant facets+ collect coplanar and concave facets+ merge concave, coplanar, degenerate, and redundant facets+*/+void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {+ boolT othermerge= False;+ facetT *newfacet;++ if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))+ return;+ trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",+ maxcentrum, maxangle, apex->id, getid_(qh->newfacet_list)));+ if (qh->IStracing >= 4 && qh->num_facets < 50)+ qh_printlists(qh);+ qh->centrum_radius= maxcentrum;+ qh->cos_max= maxangle;+ qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);+ qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);+ if (qh->hull_dim >=3) {+ qh_mark_dupridges(qh, qh->newfacet_list); /* facet_mergeset */+ qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);+ qh_forcedmerges(qh, &othermerge /* qh->facet_mergeset */);+ FORALLnew_facets { /* test samecycle merges */+ if (!newfacet->simplicial && !newfacet->mergeridge)+ qh_degen_redundant_neighbors(qh, newfacet, NULL);+ }+ if (qh_merge_degenredundant(qh))+ othermerge= True;+ }else /* qh->hull_dim == 2 */+ qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);+ qh_flippedmerges(qh, qh->newfacet_list, &othermerge);+ if (!qh->MERGEexact || zzval_(Ztotmerge)) {+ zinc_(Zpremergetot);+ qh->POSTmerging= False;+ qh_getmergeset_initial(qh, qh->newfacet_list);+ qh_all_merges(qh, othermerge, False);+ }+ qh_settempfree(qh, &qh->facet_mergeset);+ qh_settempfree(qh, &qh->degen_mergeset);+} /* premerge */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="postmerge">-</a>++ qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )+ post-merge nonconvex facets as defined by maxcentrum and maxangle+ 'reason' is for reporting progress+ if vneighbors,+ calls qh_test_vneighbors at end of qh_all_merge+ if firstmerge,+ calls qh_reducevertices before qh_getmergeset++ returns:+ if first call (qh.visible_list != qh.facet_list),+ builds qh.facet_newlist, qh.newvertex_list+ deleted facets added to qh.visible_list with facet->visible+ qh.visible_list == qh.facet_list++ notes:+++ design:+ if first call+ set qh.visible_list and qh.newfacet_list to qh.facet_list+ add all facets to qh.newfacet_list+ mark non-simplicial facets, facet->newmerge+ set qh.newvertext_list to qh.vertex_list+ add all vertices to qh.newvertex_list+ if a pre-merge occured+ set vertex->delridge {will retest the ridge}+ if qh.MERGEexact+ call qh_reducevertices()+ if no pre-merging+ merge flipped facets+ determine non-convex facets+ merge all non-convex facets+*/+void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,+ boolT vneighbors) {+ facetT *newfacet;+ boolT othermerges= False;+ vertexT *vertex;++ if (qh->REPORTfreq || qh->IStracing) {+ qh_buildtracing(qh, NULL, NULL);+ qh_printsummary(qh, qh->ferr);+ if (qh->PRINTstatistics)+ qh_printallstatistics(qh, qh->ferr, "reason");+ qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",+ reason, maxcentrum, maxangle);+ }+ trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge. test vneighbors? %d\n",+ vneighbors));+ qh->centrum_radius= maxcentrum;+ qh->cos_max= maxangle;+ qh->POSTmerging= True;+ qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);+ qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);+ if (qh->visible_list != qh->facet_list) { /* first call */+ qh->NEWfacets= True;+ qh->visible_list= qh->newfacet_list= qh->facet_list;+ FORALLnew_facets {+ newfacet->newfacet= True;+ if (!newfacet->simplicial)+ newfacet->newmerge= True;+ zinc_(Zpostfacets);+ }+ qh->newvertex_list= qh->vertex_list;+ FORALLvertices+ vertex->newlist= True;+ if (qh->VERTEXneighbors) { /* a merge has occurred */+ FORALLvertices+ vertex->delridge= True; /* test for redundant, needed? */+ if (qh->MERGEexact) {+ if (qh->hull_dim <= qh_DIMreduceBuild)+ qh_reducevertices(qh); /* was skipped during pre-merging */+ }+ }+ if (!qh->PREmerge && !qh->MERGEexact)+ qh_flippedmerges(qh, qh->newfacet_list, &othermerges);+ }+ qh_getmergeset_initial(qh, qh->newfacet_list);+ qh_all_merges(qh, False, vneighbors);+ qh_settempfree(qh, &qh->facet_mergeset);+ qh_settempfree(qh, &qh->degen_mergeset);+} /* post_merge */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="all_merges">-</a>++ qh_all_merges(qh, othermerge, vneighbors )+ merge all non-convex facets++ set othermerge if already merged facets (for qh_reducevertices)+ if vneighbors+ tests vertex neighbors for convexity at end+ qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list+ qh.degen_mergeset is defined+ if qh.MERGEexact && !qh.POSTmerging,+ does not merge coplanar facets++ returns:+ deleted facets added to qh.visible_list with facet->visible+ deleted vertices added qh.delvertex_list with vertex->delvertex++ notes:+ unless !qh.MERGEindependent,+ merges facets in independent sets+ uses qh.newfacet_list as argument since merges call qh_removefacet()++ design:+ while merges occur+ for each merge in qh.facet_mergeset+ unless one of the facets was already merged in this pass+ merge the facets+ test merged facets for additional merges+ add merges to qh.facet_mergeset+ if vertices record neighboring facets+ rename redundant vertices+ update qh.facet_mergeset+ if vneighbors ??+ tests vertex neighbors for convexity at end+*/+void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {+ facetT *facet1, *facet2;+ mergeT *merge;+ boolT wasmerge= True, isreduce;+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */+ vertexT *vertex;+ mergeType mergetype;+ int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;++ trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge facets beginning from f%d\n",+ getid_(qh->newfacet_list)));+ while (True) {+ wasmerge= False;+ while (qh_setsize(qh, qh->facet_mergeset)) {+ while ((merge= (mergeT*)qh_setdellast(qh->facet_mergeset))) {+ facet1= merge->facet1;+ facet2= merge->facet2;+ mergetype= merge->type;+ qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp);+ if (facet1->visible || facet2->visible) /*deleted facet*/+ continue;+ if ((facet1->newfacet && !facet1->tested)+ || (facet2->newfacet && !facet2->tested)) {+ if (qh->MERGEindependent && mergetype <= MRGanglecoplanar)+ continue; /* perform independent sets of merges */+ }+ qh_merge_nonconvex(qh, facet1, facet2, mergetype);+ numdegenredun += qh_merge_degenredundant(qh);+ numnewmerges++;+ wasmerge= True;+ if (mergetype == MRGconcave)+ numconcave++;+ else /* MRGcoplanar or MRGanglecoplanar */+ numcoplanar++;+ } /* while setdellast */+ if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild+ && numnewmerges > qh_MAXnewmerges) {+ numnewmerges= 0;+ qh_reducevertices(qh); /* otherwise large post merges too slow */+ }+ qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */+ } /* while mergeset */+ if (qh->VERTEXneighbors) {+ isreduce= False;+ if (qh->hull_dim >=4 && qh->POSTmerging) {+ FORALLvertices+ vertex->delridge= True;+ isreduce= True;+ }+ if ((wasmerge || othermerge) && (!qh->MERGEexact || qh->POSTmerging)+ && qh->hull_dim <= qh_DIMreduceBuild) {+ othermerge= False;+ isreduce= True;+ }+ if (isreduce) {+ if (qh_reducevertices(qh)) {+ qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */+ continue;+ }+ }+ }+ if (vneighbors && qh_test_vneighbors(qh /* qh->newfacet_list */))+ continue;+ break;+ } /* while (True) */+ if (qh->CHECKfrequently && !qh->MERGEexact) {+ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);+ /* qh_checkconnect(qh); [this is slow and it changes the facet order] */+ qh->RANDOMdist= qh->old_randomdist;+ }+ trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",+ numcoplanar, numconcave, numdegenredun));+ if (qh->IStracing >= 4 && qh->num_facets < 50)+ qh_printlists(qh);+} /* all_merges */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="appendmergeset">-</a>++ qh_appendmergeset(qh, facet, neighbor, mergetype, angle )+ appends an entry to qh.facet_mergeset or qh.degen_mergeset++ angle ignored if NULL or !qh.ANGLEmerge++ returns:+ merge appended to facet_mergeset or degen_mergeset+ sets ->degenerate or ->redundant if degen_mergeset++ see:+ qh_test_appendmerge()++ design:+ allocate merge entry+ if regular merge+ append to qh.facet_mergeset+ else if degenerate merge and qh.facet_mergeset is all degenerate+ append to qh.degen_mergeset+ else if degenerate merge+ prepend to qh.degen_mergeset+ else if redundant merge+ append to qh.degen_mergeset+*/+void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {+ mergeT *merge, *lastmerge;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */++ if (facet->redundant)+ return;+ if (facet->degenerate && mergetype == MRGdegen)+ return;+ qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);+ merge->facet1= facet;+ merge->facet2= neighbor;+ merge->type= mergetype;+ if (angle && qh->ANGLEmerge)+ merge->angle= *angle;+ if (mergetype < MRGdegen)+ qh_setappend(qh, &(qh->facet_mergeset), merge);+ else if (mergetype == MRGdegen) {+ facet->degenerate= True;+ if (!(lastmerge= (mergeT*)qh_setlast(qh->degen_mergeset))+ || lastmerge->type == MRGdegen)+ qh_setappend(qh, &(qh->degen_mergeset), merge);+ else+ qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge);+ }else if (mergetype == MRGredundant) {+ facet->redundant= True;+ qh_setappend(qh, &(qh->degen_mergeset), merge);+ }else /* mergetype == MRGmirror */ {+ if (facet->redundant || neighbor->redundant) {+ qh_fprintf(qh, qh->ferr, 6092, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",+ facet->id, neighbor->id);+ qh_errexit2(qh, qh_ERRqhull, facet, neighbor);+ }+ if (!qh_setequal(facet->vertices, neighbor->vertices)) {+ qh_fprintf(qh, qh->ferr, 6093, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",+ facet->id, neighbor->id);+ qh_errexit2(qh, qh_ERRqhull, facet, neighbor);+ }+ facet->redundant= True;+ neighbor->redundant= True;+ qh_setappend(qh, &(qh->degen_mergeset), merge);+ }+} /* appendmergeset */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="basevertices">-</a>++ qh_basevertices(qh, samecycle )+ return temporary set of base vertices for samecycle+ samecycle is first facet in the cycle+ assumes apex is SETfirst_( samecycle->vertices )++ returns:+ vertices(settemp)+ all ->seen are cleared++ notes:+ uses qh_vertex_visit;++ design:+ for each facet in samecycle+ for each unseen vertex in facet->vertices+ append to result+*/+setT *qh_basevertices(qhT *qh, facetT *samecycle) {+ facetT *same;+ vertexT *apex, *vertex, **vertexp;+ setT *vertices= qh_settemp(qh, qh->TEMPsize);++ apex= SETfirstt_(samecycle->vertices, vertexT);+ apex->visitid= ++qh->vertex_visit;+ FORALLsame_cycle_(samecycle) {+ if (same->mergeridge)+ continue;+ FOREACHvertex_(same->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ qh_setappend(qh, &vertices, vertex);+ vertex->visitid= qh->vertex_visit;+ vertex->seen= False;+ }+ }+ }+ trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",+ qh_setsize(qh, vertices)));+ return vertices;+} /* basevertices */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="checkconnect">-</a>++ qh_checkconnect(qh)+ check that new facets are connected+ new facets are on qh.newfacet_list++ notes:+ this is slow and it changes the order of the facets+ uses qh.visit_id++ design:+ move first new facet to end of qh.facet_list+ for all newly appended facets+ append unvisited neighbors to end of qh.facet_list+ for all new facets+ report error if unvisited+*/+void qh_checkconnect(qhT *qh /* qh->newfacet_list */) {+ facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;++ facet= qh->newfacet_list;+ qh_removefacet(qh, facet);+ qh_appendfacet(qh, facet);+ facet->visitid= ++qh->visit_id;+ FORALLfacet_(facet) {+ FOREACHneighbor_(facet) {+ if (neighbor->visitid != qh->visit_id) {+ qh_removefacet(qh, neighbor);+ qh_appendfacet(qh, neighbor);+ neighbor->visitid= qh->visit_id;+ }+ }+ }+ FORALLnew_facets {+ if (newfacet->visitid == qh->visit_id)+ break;+ qh_fprintf(qh, qh->ferr, 6094, "qhull error: f%d is not attached to the new facets\n",+ newfacet->id);+ errfacet= newfacet;+ }+ if (errfacet)+ qh_errexit(qh, qh_ERRqhull, errfacet, NULL);+} /* checkconnect */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="checkzero">-</a>++ qh_checkzero(qh, testall )+ check that facets are clearly convex for qh.DISTround with qh.MERGEexact++ if testall,+ test all facets for qh.MERGEexact post-merging+ else+ test qh.newfacet_list++ if qh.MERGEexact,+ allows coplanar ridges+ skips convexity test while qh.ZEROall_ok++ returns:+ True if all facets !flipped, !dupridge, normal+ if all horizon facets are simplicial+ if all vertices are clearly below neighbor+ if all opposite vertices of horizon are below+ clears qh.ZEROall_ok if any problems or coplanar facets++ notes:+ uses qh.vertex_visit+ horizon facets may define multiple new facets++ design:+ for all facets in qh.newfacet_list or qh.facet_list+ check for flagged faults (flipped, etc.)+ for all facets in qh.newfacet_list or qh.facet_list+ for each neighbor of facet+ skip horizon facets for qh.newfacet_list+ test the opposite vertex+ if qh.newfacet_list+ test the other vertices in the facet's horizon facet+*/+boolT qh_checkzero(qhT *qh, boolT testall) {+ facetT *facet, *neighbor, **neighborp;+ facetT *horizon, *facetlist;+ int neighbor_i;+ vertexT *vertex, **vertexp;+ realT dist;++ if (testall)+ facetlist= qh->facet_list;+ else {+ facetlist= qh->newfacet_list;+ FORALLfacet_(facetlist) {+ horizon= SETfirstt_(facet->neighbors, facetT);+ if (!horizon->simplicial)+ goto LABELproblem;+ if (facet->flipped || facet->dupridge || !facet->normal)+ goto LABELproblem;+ }+ if (qh->MERGEexact && qh->ZEROall_ok) {+ trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));+ return True;+ }+ }+ FORALLfacet_(facetlist) {+ qh->vertex_visit++;+ neighbor_i= 0;+ horizon= NULL;+ FOREACHneighbor_(facet) {+ if (!neighbor_i && !testall) {+ horizon= neighbor;+ neighbor_i++;+ continue; /* horizon facet tested in qh_findhorizon */+ }+ vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);+ vertex->visitid= qh->vertex_visit;+ zzinc_(Zdistzero);+ qh_distplane(qh, vertex->point, neighbor, &dist);+ if (dist >= -qh->DISTround) {+ qh->ZEROall_ok= False;+ if (!qh->MERGEexact || testall || dist > qh->DISTround)+ goto LABELnonconvex;+ }+ }+ if (!testall && horizon) {+ FOREACHvertex_(horizon->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ zzinc_(Zdistzero);+ qh_distplane(qh, vertex->point, facet, &dist);+ if (dist >= -qh->DISTround) {+ qh->ZEROall_ok= False;+ if (!qh->MERGEexact || dist > qh->DISTround)+ goto LABELnonconvex;+ }+ break;+ }+ }+ }+ }+ trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,+ (qh->MERGEexact && !testall) ?+ "not concave, flipped, or duplicate ridged" : "clearly convex"));+ return True;++ LABELproblem:+ qh->ZEROall_ok= False;+ trace2((qh, qh->ferr, 2013, "qh_checkzero: facet f%d needs pre-merging\n",+ facet->id));+ return False;++ LABELnonconvex:+ trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex. v%d dist %.2g\n",+ facet->id, neighbor->id, vertex->id, dist));+ return False;+} /* checkzero */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="compareangle">-</a>++ qh_compareangle(angle1, angle2 )+ used by qsort() to order merges by angle+*/+int qh_compareangle(const void *p1, const void *p2) {+ const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);++ return((a->angle > b->angle) ? 1 : -1);+} /* compareangle */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="comparemerge">-</a>++ qh_comparemerge(merge1, merge2 )+ used by qsort() to order merges+*/+int qh_comparemerge(const void *p1, const void *p2) {+ const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);++ return(a->type - b->type);+} /* comparemerge */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="comparevisit">-</a>++ qh_comparevisit(vertex1, vertex2 )+ used by qsort() to order vertices by their visitid+*/+int qh_comparevisit(const void *p1, const void *p2) {+ const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);++ return(a->visitid - b->visitid);+} /* comparevisit */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="copynonconvex">-</a>++ qh_copynonconvex(qh, atridge )+ set non-convex flag on other ridges (if any) between same neighbors++ notes:+ may be faster if use smaller ridge set++ design:+ for each ridge of atridge's top facet+ if ridge shares the same neighbor+ set nonconvex flag+*/+void qh_copynonconvex(qhT *qh, ridgeT *atridge) {+ facetT *facet, *otherfacet;+ ridgeT *ridge, **ridgep;++ facet= atridge->top;+ otherfacet= atridge->bottom;+ FOREACHridge_(facet->ridges) {+ if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {+ ridge->nonconvex= True;+ trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",+ atridge->id, ridge->id));+ break;+ }+ }+} /* copynonconvex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="degen_redundant_facet">-</a>++ qh_degen_redundant_facet(qh, facet )+ check facet for degen. or redundancy++ notes:+ bumps vertex_visit+ called if a facet was redundant but no longer is (qh_merge_degenredundant)+ qh_appendmergeset() only appends first reference to facet (i.e., redundant)++ see:+ qh_degen_redundant_neighbors()++ design:+ test for redundant neighbor+ test for degenerate facet+*/+void qh_degen_redundant_facet(qhT *qh, facetT *facet) {+ vertexT *vertex, **vertexp;+ facetT *neighbor, **neighborp;++ trace4((qh, qh->ferr, 4021, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",+ facet->id));+ FOREACHneighbor_(facet) {+ qh->vertex_visit++;+ FOREACHvertex_(neighbor->vertices)+ vertex->visitid= qh->vertex_visit;+ FOREACHvertex_(facet->vertices) {+ if (vertex->visitid != qh->vertex_visit)+ break;+ }+ if (!vertex) {+ qh_appendmergeset(qh, facet, neighbor, MRGredundant, NULL);+ trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d. merge\n", facet->id, neighbor->id));+ return;+ }+ }+ if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {+ qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);+ trace2((qh, qh->ferr, 2016, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));+ }+} /* degen_redundant_facet */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="degen_redundant_neighbors">-</a>++ qh_degen_redundant_neighbors(qh, facet, delfacet, )+ append degenerate and redundant neighbors to facet_mergeset+ if delfacet,+ only checks neighbors of both delfacet and facet+ also checks current facet for degeneracy++ notes:+ bumps vertex_visit+ called for each qh_mergefacet() and qh_mergecycle()+ merge and statistics occur in merge_nonconvex+ qh_appendmergeset() only appends first reference to facet (i.e., redundant)+ it appends redundant facets after degenerate ones++ a degenerate facet has fewer than hull_dim neighbors+ a redundant facet's vertices is a subset of its neighbor's vertices+ tests for redundant merges first (appendmergeset is nop for others)+ in a merge, only needs to test neighbors of merged facet++ see:+ qh_merge_degenredundant() and qh_degen_redundant_facet()++ design:+ test for degenerate facet+ test for redundant neighbor+ test for degenerate neighbor+*/+void qh_degen_redundant_neighbors(qhT *qh, facetT *facet, facetT *delfacet) {+ vertexT *vertex, **vertexp;+ facetT *neighbor, **neighborp;+ int size;++ trace4((qh, qh->ferr, 4022, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n",+ facet->id, getid_(delfacet)));+ if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {+ qh_appendmergeset(qh, facet, facet, MRGdegen, NULL);+ trace2((qh, qh->ferr, 2017, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));+ }+ if (!delfacet)+ delfacet= facet;+ qh->vertex_visit++;+ FOREACHvertex_(facet->vertices)+ vertex->visitid= qh->vertex_visit;+ FOREACHneighbor_(delfacet) {+ /* uses early out instead of checking vertex count */+ if (neighbor == facet)+ continue;+ FOREACHvertex_(neighbor->vertices) {+ if (vertex->visitid != qh->vertex_visit)+ break;+ }+ if (!vertex) {+ qh_appendmergeset(qh, neighbor, facet, MRGredundant, NULL);+ trace2((qh, qh->ferr, 2018, "qh_degen_redundant_neighbors: f%d is contained in f%d. merge\n", neighbor->id, facet->id));+ }+ }+ FOREACHneighbor_(delfacet) { /* redundant merges occur first */+ if (neighbor == facet)+ continue;+ if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {+ qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, NULL);+ trace2((qh, qh->ferr, 2019, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors. Neighbor of f%d.\n", neighbor->id, size, facet->id));+ }+ }+} /* degen_redundant_neighbors */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="find_newvertex">-</a>++ qh_find_newvertex(qh, oldvertex, vertices, ridges )+ locate new vertex for renaming old vertex+ vertices is a set of possible new vertices+ vertices sorted by number of deleted ridges++ returns:+ newvertex or NULL+ each ridge includes both vertex and oldvertex+ vertices sorted by number of deleted ridges++ notes:+ modifies vertex->visitid+ new vertex is in one of the ridges+ renaming will not cause a duplicate ridge+ renaming will minimize the number of deleted ridges+ newvertex may not be adjacent in the dual (though unlikely)++ design:+ for each vertex in vertices+ set vertex->visitid to number of references in ridges+ remove unvisited vertices+ set qh.vertex_visit above all possible values+ sort vertices by number of references in ridges+ add each ridge to qh.hash_table+ for each vertex in vertices+ look for a vertex that would not cause a duplicate ridge after a rename+*/+vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {+ vertexT *vertex, **vertexp;+ setT *newridges;+ ridgeT *ridge, **ridgep;+ int size, hashsize;+ int hash;++#ifndef qh_NOtrace+ if (qh->IStracing >= 4) {+ qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",+ oldvertex->id);+ FOREACHvertex_(vertices)+ qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);+ FOREACHridge_(ridges)+ qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);+ qh_fprintf(qh, qh->ferr, 8066, "\n");+ }+#endif+ FOREACHvertex_(vertices)+ vertex->visitid= 0;+ FOREACHridge_(ridges) {+ FOREACHvertex_(ridge->vertices)+ vertex->visitid++;+ }+ FOREACHvertex_(vertices) {+ if (!vertex->visitid) {+ qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));+ vertexp--; /* repeat since deleted this vertex */+ }+ }+ qh->vertex_visit += (unsigned int)qh_setsize(qh, ridges);+ if (!qh_setsize(qh, vertices)) {+ trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",+ oldvertex->id));+ return NULL;+ }+ qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),+ sizeof(vertexT *), qh_comparevisit);+ /* can now use qh->vertex_visit */+ if (qh->PRINTstatistics) {+ size= qh_setsize(qh, vertices);+ zinc_(Zintersect);+ zadd_(Zintersecttot, size);+ zmax_(Zintersectmax, size);+ }+ hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));+ FOREACHridge_(ridges)+ qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);+ FOREACHvertex_(vertices) {+ newridges= qh_vertexridges(qh, vertex);+ FOREACHridge_(newridges) {+ if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {+ zinc_(Zdupridge);+ break;+ }+ }+ qh_settempfree(qh, &newridges);+ if (!ridge)+ break; /* found a rename */+ }+ if (vertex) {+ /* counted in qh_renamevertex */+ trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",+ vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));+ }else {+ zinc_(Zfindfail);+ trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d(all duplicated ridges) during p%d\n",+ oldvertex->id, qh->furthest_id));+ }+ qh_setfree(qh, &qh->hash_table);+ return vertex;+} /* find_newvertex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="findbest_test">-</a>++ qh_findbest_test(qh, testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )+ test neighbor of facet for qh_findbestneighbor()+ if testcentrum,+ tests centrum (assumes it is defined)+ else+ tests vertices++ returns:+ if a better facet (i.e., vertices/centrum of facet closer to neighbor)+ updates bestfacet, dist, mindist, and maxdist+*/+void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,+ facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {+ realT dist, mindist, maxdist;++ if (testcentrum) {+ zzinc_(Zbestdist);+ qh_distplane(qh, facet->center, neighbor, &dist);+ dist *= qh->hull_dim; /* estimate furthest vertex */+ if (dist < 0) {+ maxdist= 0;+ mindist= dist;+ dist= -dist;+ }else {+ mindist= 0;+ maxdist= dist;+ }+ }else+ dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);+ if (dist < *distp) {+ *bestfacet= neighbor;+ *mindistp= mindist;+ *maxdistp= maxdist;+ *distp= dist;+ }+} /* findbest_test */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="findbestneighbor">-</a>++ qh_findbestneighbor(qh, facet, dist, mindist, maxdist )+ finds best neighbor (least dist) of a facet for merging++ returns:+ returns min and max distances and their max absolute value++ notes:+ error if qh_ASvoronoi+ avoids merging old into new+ assumes ridge->nonconvex only set on one ridge between a pair of facets+ could use an early out predicate but not worth it++ design:+ if a large facet+ will test centrum+ else+ will test vertices+ if a large facet+ test nonconvex neighbors for best merge+ else+ test all neighbors for the best merge+ if testing centrum+ get distance information+*/+facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {+ facetT *neighbor, **neighborp, *bestfacet= NULL;+ ridgeT *ridge, **ridgep;+ boolT nonconvex= True, testcentrum= False;+ int size= qh_setsize(qh, facet->vertices);++ if(qh->CENTERtype==qh_ASvoronoi){+ qh_fprintf(qh, qh->ferr, 6272, "qhull error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ *distp= REALmax;+ if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {+ testcentrum= True;+ zinc_(Zbestcentrum);+ if (!facet->center)+ facet->center= qh_getcentrum(qh, facet);+ }+ if (size > qh->hull_dim + qh_BESTnonconvex) {+ FOREACHridge_(facet->ridges) {+ if (ridge->nonconvex) {+ neighbor= otherfacet_(ridge, facet);+ qh_findbest_test(qh, testcentrum, facet, neighbor,+ &bestfacet, distp, mindistp, maxdistp);+ }+ }+ }+ if (!bestfacet) {+ nonconvex= False;+ FOREACHneighbor_(facet)+ qh_findbest_test(qh, testcentrum, facet, neighbor,+ &bestfacet, distp, mindistp, maxdistp);+ }+ if (!bestfacet) {+ qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ if (testcentrum)+ qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);+ trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",+ bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));+ return(bestfacet);+} /* findbestneighbor */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="flippedmerges">-</a>++ qh_flippedmerges(qh, facetlist, wasmerge )+ merge flipped facets into best neighbor+ assumes qh.facet_mergeset at top of temporary stack++ returns:+ no flipped facets on facetlist+ sets wasmerge if merge occurred+ degen/redundant merges passed through++ notes:+ othermerges not needed since qh.facet_mergeset is empty before & after+ keep it in case of change++ design:+ append flipped facets to qh.facetmergeset+ for each flipped merge+ find best neighbor+ merge facet into neighbor+ merge degenerate and redundant facets+ remove flipped merges from qh.facet_mergeset+*/+void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {+ facetT *facet, *neighbor, *facet1;+ realT dist, mindist, maxdist;+ mergeT *merge, **mergep;+ setT *othermerges;+ int nummerge=0;++ trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));+ FORALLfacet_(facetlist) {+ if (facet->flipped && !facet->visible)+ qh_appendmergeset(qh, facet, facet, MRGflip, NULL);+ }+ othermerges= qh_settemppop(qh); /* was facet_mergeset */+ qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);+ qh_settemppush(qh, othermerges);+ FOREACHmerge_(othermerges) {+ facet1= merge->facet1;+ if (merge->type != MRGflip || facet1->visible)+ continue;+ if (qh->TRACEmerge-1 == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);+ trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",+ facet1->id, neighbor->id, dist, qh->furthest_id));+ qh_mergefacet(qh, facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);+ nummerge++;+ if (qh->PRINTstatistics) {+ zinc_(Zflipped);+ wadd_(Wflippedtot, dist);+ wmax_(Wflippedmax, dist);+ }+ qh_merge_degenredundant(qh);+ }+ FOREACHmerge_(othermerges) {+ if (merge->facet1->visible || merge->facet2->visible)+ qh_memfree(qh, merge, (int)sizeof(mergeT));+ else+ qh_setappend(qh, &qh->facet_mergeset, merge);+ }+ qh_settempfree(qh, &othermerges);+ if (nummerge)+ *wasmerge= True;+ trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));+} /* flippedmerges */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="forcedmerges">-</a>++ qh_forcedmerges(qh, wasmerge )+ merge duplicated ridges++ returns:+ removes all duplicate ridges on facet_mergeset+ wasmerge set if merge+ qh.facet_mergeset may include non-forced merges(none for now)+ qh.degen_mergeset includes degen/redun merges++ notes:+ duplicate ridges occur when the horizon is pinched,+ i.e. a subridge occurs in more than two horizon ridges.+ could rename vertices that pinch the horizon+ assumes qh_merge_degenredundant() has not be called+ othermerges isn't needed since facet_mergeset is empty afterwards+ keep it in case of change++ design:+ for each duplicate ridge+ find current facets by chasing f.replace links+ check for wide merge due to duplicate ridge+ determine best direction for facet+ merge one facet into the other+ remove duplicate ridges from qh.facet_mergeset+*/+void qh_forcedmerges(qhT *qh, boolT *wasmerge) {+ facetT *facet1, *facet2;+ mergeT *merge, **mergep;+ realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;+ setT *othermerges;+ int nummerge=0, numflip=0;++ if (qh->TRACEmerge-1 == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ trace4((qh, qh->ferr, 4025, "qh_forcedmerges: begin\n"));+ othermerges= qh_settemppop(qh); /* was facet_mergeset */+ qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);+ qh_settemppush(qh, othermerges);+ FOREACHmerge_(othermerges) {+ if (merge->type != MRGridge)+ continue;+ if (qh->TRACEmerge-1 == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ facet1= merge->facet1;+ facet2= merge->facet2;+ while (facet1->visible) /* must exist, no qh_merge_degenredunant */+ facet1= facet1->f.replace; /* previously merged facet */+ while (facet2->visible)+ facet2= facet2->f.replace; /* previously merged facet */+ if (facet1 == facet2)+ continue;+ if (!qh_setin(facet2->neighbors, facet1)) {+ qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",+ merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);+ qh_errexit2(qh, qh_ERRqhull, facet1, facet2);+ }+ dist1= qh_getdistance(qh, facet1, facet2, &mindist1, &maxdist1);+ dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);+ qh_check_dupridge(qh, facet1, dist1, facet2, dist2);+ if (dist1 < dist2)+ qh_mergefacet(qh, facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);+ else {+ qh_mergefacet(qh, facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);+ dist1= dist2;+ facet1= facet2;+ }+ if (facet1->flipped) {+ zinc_(Zmergeflipdup);+ numflip++;+ }else+ nummerge++;+ if (qh->PRINTstatistics) {+ zinc_(Zduplicate);+ wadd_(Wduplicatetot, dist1);+ wmax_(Wduplicatemax, dist1);+ }+ }+ FOREACHmerge_(othermerges) {+ if (merge->type == MRGridge)+ qh_memfree(qh, merge, (int)sizeof(mergeT));+ else+ qh_setappend(qh, &qh->facet_mergeset, merge);+ }+ qh_settempfree(qh, &othermerges);+ if (nummerge)+ *wasmerge= True;+ trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n",+ nummerge, numflip));+} /* forcedmerges */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="getmergeset">-</a>++ qh_getmergeset(qh, facetlist )+ determines nonconvex facets on facetlist+ tests !tested ridges and nonconvex ridges of !tested facets++ returns:+ returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged+ all ridges tested++ notes:+ assumes no nonconvex ridges with both facets tested+ uses facet->tested/ridge->tested to prevent duplicate tests+ can not limit tests to modified ridges since the centrum changed+ uses qh.visit_id++ see:+ qh_getmergeset_initial()++ design:+ for each facet on facetlist+ for each ridge of facet+ if untested ridge+ test ridge for convexity+ if non-convex+ append ridge to qh.facet_mergeset+ sort qh.facet_mergeset by angle+*/+void qh_getmergeset(qhT *qh, facetT *facetlist) {+ facetT *facet, *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;+ int nummerges;++ nummerges= qh_setsize(qh, qh->facet_mergeset);+ trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));+ qh->visit_id++;+ FORALLfacet_(facetlist) {+ if (facet->tested)+ continue;+ facet->visitid= qh->visit_id;+ facet->tested= True; /* must be non-simplicial due to merge */+ FOREACHneighbor_(facet)+ neighbor->seen= False;+ FOREACHridge_(facet->ridges) {+ if (ridge->tested && !ridge->nonconvex)+ continue;+ /* if tested & nonconvex, need to append merge */+ neighbor= otherfacet_(ridge, facet);+ if (neighbor->seen) {+ ridge->tested= True;+ ridge->nonconvex= False;+ }else if (neighbor->visitid != qh->visit_id) {+ ridge->tested= True;+ ridge->nonconvex= False;+ neighbor->seen= True; /* only one ridge is marked nonconvex */+ if (qh_test_appendmerge(qh, facet, neighbor))+ ridge->nonconvex= True;+ }+ }+ }+ nummerges= qh_setsize(qh, qh->facet_mergeset);+ if (qh->ANGLEmerge)+ qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);+ else+ qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);+ if (qh->POSTmerging) {+ zadd_(Zmergesettot2, nummerges);+ }else {+ zadd_(Zmergesettot, nummerges);+ zmax_(Zmergesetmax, nummerges);+ }+ trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));+} /* getmergeset */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="getmergeset_initial">-</a>++ qh_getmergeset_initial(qh, facetlist )+ determine initial qh.facet_mergeset for facets+ tests all facet/neighbor pairs on facetlist++ returns:+ sorted qh.facet_mergeset with nonconvex ridges+ sets facet->tested, ridge->tested, and ridge->nonconvex++ notes:+ uses visit_id, assumes ridge->nonconvex is False++ see:+ qh_getmergeset()++ design:+ for each facet on facetlist+ for each untested neighbor of facet+ test facet and neighbor for convexity+ if non-convex+ append merge to qh.facet_mergeset+ mark one of the ridges as nonconvex+ sort qh.facet_mergeset by angle+*/+void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {+ facetT *facet, *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;+ int nummerges;++ qh->visit_id++;+ FORALLfacet_(facetlist) {+ facet->visitid= qh->visit_id;+ facet->tested= True;+ FOREACHneighbor_(facet) {+ if (neighbor->visitid != qh->visit_id) {+ if (qh_test_appendmerge(qh, facet, neighbor)) {+ FOREACHridge_(neighbor->ridges) {+ if (facet == otherfacet_(ridge, neighbor)) {+ ridge->nonconvex= True;+ break; /* only one ridge is marked nonconvex */+ }+ }+ }+ }+ }+ FOREACHridge_(facet->ridges)+ ridge->tested= True;+ }+ nummerges= qh_setsize(qh, qh->facet_mergeset);+ if (qh->ANGLEmerge)+ qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle);+ else+ qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge);+ if (qh->POSTmerging) {+ zadd_(Zmergeinittot2, nummerges);+ }else {+ zadd_(Zmergeinittot, nummerges);+ zmax_(Zmergeinitmax, nummerges);+ }+ trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));+} /* getmergeset_initial */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="hashridge">-</a>++ qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )+ add ridge to hashtable without oldvertex++ notes:+ assumes hashtable is large enough++ design:+ determine hash value for ridge without oldvertex+ find next empty slot for ridge+*/+void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {+ int hash;+ ridgeT *ridgeA;++ hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);+ while (True) {+ if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {+ SETelem_(hashtable, hash)= ridge;+ break;+ }else if (ridgeA == ridge)+ break;+ if (++hash == hashsize)+ hash= 0;+ }+} /* hashridge */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="hashridge_find">-</a>++ qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )+ returns matching ridge without oldvertex in hashtable+ for ridge without vertex+ if oldvertex is NULL+ matches with any one skip++ returns:+ matching ridge or NULL+ if no match,+ if ridge already in table+ hashslot= -1+ else+ hashslot= next NULL index++ notes:+ assumes hashtable is large enough+ can't match ridge to itself++ design:+ get hash value for ridge without vertex+ for each hashslot+ return match if ridge matches ridgeA without oldvertex+*/+ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,+ vertexT *vertex, vertexT *oldvertex, int *hashslot) {+ int hash;+ ridgeT *ridgeA;++ *hashslot= 0;+ zinc_(Zhashridge);+ hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);+ while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {+ if (ridgeA == ridge)+ *hashslot= -1;+ else {+ zinc_(Zhashridgetest);+ if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))+ return ridgeA;+ }+ if (++hash == hashsize)+ hash= 0;+ }+ if (!*hashslot)+ *hashslot= hash;+ return NULL;+} /* hashridge_find */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="makeridges">-</a>++ qh_makeridges(qh, facet )+ creates explicit ridges between simplicial facets++ returns:+ facet with ridges and without qh_MERGEridge+ ->simplicial is False++ notes:+ allows qh_MERGEridge flag+ uses existing ridges+ duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)++ see:+ qh_mergecycle_ridges()++ design:+ look for qh_MERGEridge neighbors+ mark neighbors that already have ridges+ for each unprocessed neighbor of facet+ create a ridge for neighbor and facet+ if any qh_MERGEridge neighbors+ delete qh_MERGEridge flags (already handled by qh_mark_dupridges)+*/+void qh_makeridges(qhT *qh, facetT *facet) {+ facetT *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;+ int neighbor_i, neighbor_n;+ boolT toporient, mergeridge= False;++ if (!facet->simplicial)+ return;+ trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));+ facet->simplicial= False;+ FOREACHneighbor_(facet) {+ if (neighbor == qh_MERGEridge)+ mergeridge= True;+ else+ neighbor->seen= False;+ }+ FOREACHridge_(facet->ridges)+ otherfacet_(ridge, facet)->seen= True;+ FOREACHneighbor_i_(qh, facet) {+ if (neighbor == qh_MERGEridge)+ continue; /* fixed by qh_mark_dupridges */+ else if (!neighbor->seen) { /* no current ridges */+ ridge= qh_newridge(qh);+ ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,+ neighbor_i, 0);+ toporient= facet->toporient ^ (neighbor_i & 0x1);+ if (toporient) {+ ridge->top= facet;+ ridge->bottom= neighbor;+ }else {+ ridge->top= neighbor;+ ridge->bottom= facet;+ }+#if 0 /* this also works */+ flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);+ if (facet->toporient ^ (skip1 & 0x1) ^ flip) {+ ridge->top= neighbor;+ ridge->bottom= facet;+ }else {+ ridge->top= facet;+ ridge->bottom= neighbor;+ }+#endif+ qh_setappend(qh, &(facet->ridges), ridge);+ qh_setappend(qh, &(neighbor->ridges), ridge);+ }+ }+ if (mergeridge) {+ while (qh_setdel(facet->neighbors, qh_MERGEridge))+ ; /* delete each one */+ }+} /* makeridges */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mark_dupridges">-</a>++ qh_mark_dupridges(qh, facetlist )+ add duplicated ridges to qh.facet_mergeset+ facet->dupridge is true++ returns:+ duplicate ridges on qh.facet_mergeset+ ->mergeridge/->mergeridge2 set+ duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge+ no MERGEridges in neighbor sets++ notes:+ duplicate ridges occur when the horizon is pinched,+ i.e. a subridge occurs in more than two horizon ridges.+ could rename vertices that pinch the horizon (thus removing subridge)+ uses qh.visit_id++ design:+ for all facets on facetlist+ if facet contains a duplicate ridge+ for each neighbor of facet+ if neighbor marked qh_MERGEridge (one side of the merge)+ set facet->mergeridge+ else+ if neighbor contains a duplicate ridge+ and the back link is qh_MERGEridge+ append duplicate ridge to qh.facet_mergeset+ for each duplicate ridge+ make ridge sets in preparation for merging+ remove qh_MERGEridge from neighbor set+ for each duplicate ridge+ restore the missing neighbor from the neighbor set that was qh_MERGEridge+ add the missing ridge for this neighbor+*/+void qh_mark_dupridges(qhT *qh, facetT *facetlist) {+ facetT *facet, *neighbor, **neighborp;+ int nummerge=0;+ mergeT *merge, **mergep;+++ trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify duplicate ridges\n"));+ FORALLfacet_(facetlist) {+ if (facet->dupridge) {+ FOREACHneighbor_(facet) {+ if (neighbor == qh_MERGEridge) {+ facet->mergeridge= True;+ continue;+ }+ if (neighbor->dupridge+ && !qh_setin(neighbor->neighbors, facet)) { /* qh_MERGEridge */+ qh_appendmergeset(qh, facet, neighbor, MRGridge, NULL);+ facet->mergeridge2= True;+ facet->mergeridge= True;+ nummerge++;+ }+ }+ }+ }+ if (!nummerge)+ return;+ FORALLfacet_(facetlist) { /* gets rid of qh_MERGEridge */+ if (facet->mergeridge && !facet->mergeridge2)+ qh_makeridges(qh, facet);+ }+ FOREACHmerge_(qh->facet_mergeset) { /* restore the missing neighbors */+ if (merge->type == MRGridge) {+ qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);+ qh_makeridges(qh, merge->facet1); /* and the missing ridges */+ }+ }+ trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges\n",+ nummerge));+} /* mark_dupridges */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="maydropneighbor">-</a>++ qh_maydropneighbor(qh, facet )+ drop neighbor relationship if no ridge between facet and neighbor++ returns:+ neighbor sets updated+ appends degenerate facets to qh.facet_mergeset++ notes:+ won't cause redundant facets since vertex inclusion is the same+ may drop vertex and neighbor if no ridge+ uses qh.visit_id++ design:+ visit all neighbors with ridges+ for each unvisited neighbor of facet+ delete neighbor and facet from the neighbor sets+ if neighbor becomes degenerate+ append neighbor to qh.degen_mergeset+ if facet is degenerate+ append facet to qh.degen_mergeset+*/+void qh_maydropneighbor(qhT *qh, facetT *facet) {+ ridgeT *ridge, **ridgep;+ realT angledegen= qh_ANGLEdegen;+ facetT *neighbor, **neighborp;++ qh->visit_id++;+ trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",+ facet->id));+ FOREACHridge_(facet->ridges) {+ ridge->top->visitid= qh->visit_id;+ ridge->bottom->visitid= qh->visit_id;+ }+ FOREACHneighbor_(facet) {+ if (neighbor->visitid != qh->visit_id) {+ trace0((qh, qh->ferr, 17, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",+ facet->id, neighbor->id, qh->furthest_id));+ zinc_(Zdropneighbor);+ qh_setdel(facet->neighbors, neighbor);+ neighborp--; /* repeat, deleted a neighbor */+ qh_setdel(neighbor->neighbors, facet);+ if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {+ zinc_(Zdropdegen);+ qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, &angledegen);+ trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));+ }+ }+ }+ if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {+ zinc_(Zdropdegen);+ qh_appendmergeset(qh, facet, facet, MRGdegen, &angledegen);+ trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));+ }+} /* maydropneighbor */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="merge_degenredundant">-</a>++ qh_merge_degenredundant(qh)+ merge all degenerate and redundant facets+ qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()++ returns:+ number of merges performed+ resets facet->degenerate/redundant+ if deleted (visible) facet has no neighbors+ sets ->f.replace to NULL++ notes:+ redundant merges happen before degenerate ones+ merging and renaming vertices can result in degen/redundant facets++ design:+ for each merge on qh.degen_mergeset+ if redundant merge+ if non-redundant facet merged into redundant facet+ recheck facet for redundancy+ else+ merge redundant facet into other facet+*/+int qh_merge_degenredundant(qhT *qh) {+ int size;+ mergeT *merge;+ facetT *bestneighbor, *facet1, *facet2;+ realT dist, mindist, maxdist;+ vertexT *vertex, **vertexp;+ int nummerges= 0;+ mergeType mergetype;++ while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {+ facet1= merge->facet1;+ facet2= merge->facet2;+ mergetype= merge->type;+ qh_memfree(qh, merge, (int)sizeof(mergeT));+ if (facet1->visible)+ continue;+ facet1->degenerate= False;+ facet1->redundant= False;+ if (qh->TRACEmerge-1 == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ if (mergetype == MRGredundant) {+ zinc_(Zneighbor);+ while (facet2->visible) {+ if (!facet2->f.replace) {+ qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",+ facet1->id, facet2->id);+ qh_errexit2(qh, qh_ERRqhull, facet1, facet2);+ }+ facet2= facet2->f.replace;+ }+ if (facet1 == facet2) {+ qh_degen_redundant_facet(qh, facet1); /* in case of others */+ continue;+ }+ trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",+ facet1->id, facet2->id));+ qh_mergefacet(qh, facet1, facet2, NULL, NULL, !qh_MERGEapex);+ /* merge distance is already accounted for */+ nummerges++;+ }else { /* mergetype == MRGdegen, other merges may have fixed */+ if (!(size= qh_setsize(qh, facet1->neighbors))) {+ zinc_(Zdelfacetdup);+ trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors. Deleted\n", facet1->id));+ qh_willdelete(qh, facet1, NULL);+ FOREACHvertex_(facet1->vertices) {+ qh_setdel(vertex->neighbors, facet1);+ if (!SETfirst_(vertex->neighbors)) {+ zinc_(Zdegenvertex);+ trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",+ vertex->id, facet1->id));+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+ }+ }+ nummerges++;+ }else if (size < qh->hull_dim) {+ bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);+ trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",+ facet1->id, size, bestneighbor->id, dist));+ qh_mergefacet(qh, facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);+ nummerges++;+ if (qh->PRINTstatistics) {+ zinc_(Zdegen);+ wadd_(Wdegentot, dist);+ wmax_(Wdegenmax, dist);+ }+ } /* else, another merge fixed the degeneracy and redundancy tested */+ }+ }+ return nummerges;+} /* merge_degenredundant */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="merge_nonconvex">-</a>++ qh_merge_nonconvex(qh, facet1, facet2, mergetype )+ remove non-convex ridge between facet1 into facet2+ mergetype gives why the facet's are non-convex++ returns:+ merges one of the facets into the best neighbor++ design:+ if one of the facets is a new facet+ prefer merging new facet into old facet+ find best neighbors for both facets+ merge the nearest facet into its best neighbor+ update the statistics+*/+void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {+ facetT *bestfacet, *bestneighbor, *neighbor;+ realT dist, dist2, mindist, mindist2, maxdist, maxdist2;++ if (qh->TRACEmerge-1 == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",+ zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));+ /* concave or coplanar */+ if (!facet1->newfacet) {+ bestfacet= facet2; /* avoid merging old facet if new is ok */+ facet2= facet1;+ facet1= bestfacet;+ }else+ bestfacet= facet1;+ bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);+ neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);+ if (dist < dist2) {+ qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);+ }else if (qh->AVOIDold && !facet2->newfacet+ && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)+ || dist * 1.5 < dist2)) {+ zinc_(Zavoidold);+ wadd_(Wavoidoldtot, dist);+ wmax_(Wavoidoldmax, dist);+ trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g. Use f%d dist %2.2g instead\n",+ facet2->id, dist2, facet1->id, dist2));+ qh_mergefacet(qh, bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);+ }else {+ qh_mergefacet(qh, facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);+ dist= dist2;+ }+ if (qh->PRINTstatistics) {+ if (mergetype == MRGanglecoplanar) {+ zinc_(Zacoplanar);+ wadd_(Wacoplanartot, dist);+ wmax_(Wacoplanarmax, dist);+ }else if (mergetype == MRGconcave) {+ zinc_(Zconcave);+ wadd_(Wconcavetot, dist);+ wmax_(Wconcavemax, dist);+ }else { /* MRGcoplanar */+ zinc_(Zcoplanar);+ wadd_(Wcoplanartot, dist);+ wmax_(Wcoplanarmax, dist);+ }+ }+} /* merge_nonconvex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle">-</a>++ qh_mergecycle(qh, samecycle, newfacet )+ merge a cycle of facets starting at samecycle into a newfacet+ newfacet is a horizon facet with ->normal+ samecycle facets are simplicial from an apex++ returns:+ initializes vertex neighbors on first merge+ samecycle deleted (placed on qh.visible_list)+ newfacet at end of qh.facet_list+ deleted vertices on qh.del_vertices++ see:+ qh_mergefacet()+ called by qh_mergecycle_all() for multiple, same cycle facets++ design:+ make vertex neighbors if necessary+ make ridges for newfacet+ merge neighbor sets of samecycle into newfacet+ merge ridges of samecycle into newfacet+ merge vertex neighbors of samecycle into newfacet+ make apex of samecycle the apex of newfacet+ if newfacet wasn't a new facet+ add its vertices to qh.newvertex_list+ delete samecycle facets a make newfacet a newfacet+*/+void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {+ int traceonce= False, tracerestore= 0;+ vertexT *apex;+#ifndef qh_NOtrace+ facetT *same;+#endif++ if (newfacet->tricoplanar) {+ if (!qh->TRInormals) {+ qh_fprintf(qh, qh->ferr, 6224, "Qhull internal error (qh_mergecycle): does not work for tricoplanar facets. Use option 'Q11'\n");+ qh_errexit(qh, qh_ERRqhull, newfacet, NULL);+ }+ newfacet->tricoplanar= False;+ newfacet->keepcentrum= False;+ }+ if (!qh->VERTEXneighbors)+ qh_vertexneighbors(qh);+ zzinc_(Ztotmerge);+ if (qh->REPORTfreq2 && qh->POSTmerging) {+ if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)+ qh_tracemerging(qh);+ }+#ifndef qh_NOtrace+ if (qh->TRACEmerge == zzval_(Ztotmerge))+ qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;+ trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",+ zzval_(Ztotmerge), samecycle->id, newfacet->id));+ if (newfacet == qh->tracefacet) {+ tracerestore= qh->IStracing;+ qh->IStracing= 4;+ qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",+ zzval_(Ztotmerge), samecycle->id, newfacet->id, qh->furthest_id);+ traceonce= True;+ }+ if (qh->IStracing >=4) {+ qh_fprintf(qh, qh->ferr, 8069, " same cycle:");+ FORALLsame_cycle_(samecycle)+ qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);+ qh_fprintf(qh, qh->ferr, 8071, "\n");+ }+ if (qh->IStracing >=4)+ qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);+#endif /* !qh_NOtrace */+ apex= SETfirstt_(samecycle->vertices, vertexT);+ qh_makeridges(qh, newfacet);+ qh_mergecycle_neighbors(qh, samecycle, newfacet);+ qh_mergecycle_ridges(qh, samecycle, newfacet);+ qh_mergecycle_vneighbors(qh, samecycle, newfacet);+ if (SETfirstt_(newfacet->vertices, vertexT) != apex)+ qh_setaddnth(qh, &newfacet->vertices, 0, apex); /* apex has last id */+ if (!newfacet->newfacet)+ qh_newvertices(qh, newfacet->vertices);+ qh_mergecycle_facets(qh, samecycle, newfacet);+ qh_tracemerge(qh, samecycle, newfacet);+ /* check for degen_redundant_neighbors after qh_forcedmerges() */+ if (traceonce) {+ qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");+ qh->IStracing= tracerestore;+ }+} /* mergecycle */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle_all">-</a>++ qh_mergecycle_all(qh, facetlist, wasmerge )+ merge all samecycles of coplanar facets into horizon+ don't merge facets with ->mergeridge (these already have ->normal)+ all facets are simplicial from apex+ all facet->cycledone == False++ returns:+ all newfacets merged into coplanar horizon facets+ deleted vertices on qh.del_vertices+ sets wasmerge if any merge++ see:+ calls qh_mergecycle for multiple, same cycle facets++ design:+ for each facet on facetlist+ skip facets with duplicate ridges and normals+ check that facet is in a samecycle (->mergehorizon)+ if facet only member of samecycle+ sets vertex->delridge for all vertices except apex+ merge facet into horizon+ else+ mark all facets in samecycle+ remove facets with duplicate ridges from samecycle+ merge samecycle into horizon (deletes facets from facetlist)+*/+void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {+ facetT *facet, *same, *prev, *horizon;+ facetT *samecycle= NULL, *nextfacet, *nextsame;+ vertexT *apex, *vertex, **vertexp;+ int cycles=0, total=0, facets, nummerge;++ trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: begin\n"));+ for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {+ if (facet->normal)+ continue;+ if (!facet->mergehorizon) {+ qh_fprintf(qh, qh->ferr, 6225, "Qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ horizon= SETfirstt_(facet->neighbors, facetT);+ if (facet->f.samecycle == facet) {+ zinc_(Zonehorizon);+ /* merge distance done in qh_findhorizon */+ apex= SETfirstt_(facet->vertices, vertexT);+ FOREACHvertex_(facet->vertices) {+ if (vertex != apex)+ vertex->delridge= True;+ }+ horizon->f.newcycle= NULL;+ qh_mergefacet(qh, facet, horizon, NULL, NULL, qh_MERGEapex);+ }else {+ samecycle= facet;+ facets= 0;+ prev= facet;+ for (same= facet->f.samecycle; same; /* FORALLsame_cycle_(facet) */+ same= (same == facet ? NULL :nextsame)) { /* ends at facet */+ nextsame= same->f.samecycle;+ if (same->cycledone || same->visible)+ qh_infiniteloop(qh, same);+ same->cycledone= True;+ if (same->normal) {+ prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */+ same->f.samecycle= NULL;+ }else {+ prev= same;+ facets++;+ }+ }+ while (nextfacet && nextfacet->cycledone) /* will delete samecycle */+ nextfacet= nextfacet->next;+ horizon->f.newcycle= NULL;+ qh_mergecycle(qh, samecycle, horizon);+ nummerge= horizon->nummerge + facets;+ if (nummerge > qh_MAXnummerge)+ horizon->nummerge= qh_MAXnummerge;+ else+ horizon->nummerge= (short unsigned int)nummerge;+ zzinc_(Zcyclehorizon);+ total += facets;+ zzadd_(Zcyclefacettot, facets);+ zmax_(Zcyclefacetmax, facets);+ }+ cycles++;+ }+ if (cycles)+ *wasmerge= True;+ trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));+} /* mergecycle_all */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle_facets">-</a>++ qh_mergecycle_facets(qh, samecycle, newfacet )+ finish merge of samecycle into newfacet++ returns:+ samecycle prepended to visible_list for later deletion and partitioning+ each facet->f.replace == newfacet++ newfacet moved to end of qh.facet_list+ makes newfacet a newfacet (get's facet1->id if it was old)+ sets newfacet->newmerge+ clears newfacet->center (unless merging into a large facet)+ clears newfacet->tested and ridge->tested for facet1++ adds neighboring facets to facet_mergeset if redundant or degenerate++ design:+ make newfacet a new facet and set its flags+ move samecycle facets to qh.visible_list for later deletion+ unless newfacet is large+ remove its centrum+*/+void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {+ facetT *same, *next;++ trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));+ qh_removefacet(qh, newfacet); /* append as a newfacet to end of qh->facet_list */+ qh_appendfacet(qh, newfacet);+ newfacet->newfacet= True;+ newfacet->simplicial= False;+ newfacet->newmerge= True;++ for (same= samecycle->f.samecycle; same; same= (same == samecycle ? NULL : next)) {+ next= same->f.samecycle; /* reused by willdelete */+ qh_willdelete(qh, same, newfacet);+ }+ if (newfacet->center+ && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {+ qh_memfree(qh, newfacet->center, qh->normal_size);+ newfacet->center= NULL;+ }+ trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",+ samecycle->id, newfacet->id));+} /* mergecycle_facets */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle_neighbors">-</a>++ qh_mergecycle_neighbors(qh, samecycle, newfacet )+ add neighbors for samecycle facets to newfacet++ returns:+ newfacet with updated neighbors and vice-versa+ newfacet has ridges+ all neighbors of newfacet marked with qh.visit_id+ samecycle facets marked with qh.visit_id-1+ ridges updated for simplicial neighbors of samecycle with a ridge++ notes:+ assumes newfacet not in samecycle+ usually, samecycle facets are new, simplicial facets without internal ridges+ not so if horizon facet is coplanar to two different samecycles++ see:+ qh_mergeneighbors()++ design:+ check samecycle+ delete neighbors from newfacet that are also in samecycle+ for each neighbor of a facet in samecycle+ if neighbor is simplicial+ if first visit+ move the neighbor relation to newfacet+ update facet links for its ridges+ else+ make ridges for neighbor+ remove samecycle reference+ else+ update neighbor sets+*/+void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {+ facetT *same, *neighbor, **neighborp;+ int delneighbors= 0, newneighbors= 0;+ unsigned int samevisitid;+ ridgeT *ridge, **ridgep;++ samevisitid= ++qh->visit_id;+ FORALLsame_cycle_(samecycle) {+ if (same->visitid == samevisitid || same->visible)+ qh_infiniteloop(qh, samecycle);+ same->visitid= samevisitid;+ }+ newfacet->visitid= ++qh->visit_id;+ trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));+ FOREACHneighbor_(newfacet) {+ if (neighbor->visitid == samevisitid) {+ SETref_(neighbor)= NULL; /* samecycle neighbors deleted */+ delneighbors++;+ }else+ neighbor->visitid= qh->visit_id;+ }+ qh_setcompact(qh, newfacet->neighbors);++ trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));+ FORALLsame_cycle_(samecycle) {+ FOREACHneighbor_(same) {+ if (neighbor->visitid == samevisitid)+ continue;+ if (neighbor->simplicial) {+ if (neighbor->visitid != qh->visit_id) {+ qh_setappend(qh, &newfacet->neighbors, neighbor);+ qh_setreplace(qh, neighbor->neighbors, same, newfacet);+ newneighbors++;+ neighbor->visitid= qh->visit_id;+ FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */+ if (ridge->top == same) {+ ridge->top= newfacet;+ break;+ }else if (ridge->bottom == same) {+ ridge->bottom= newfacet;+ break;+ }+ }+ }else {+ qh_makeridges(qh, neighbor);+ qh_setdel(neighbor->neighbors, same);+ /* same can't be horizon facet for neighbor */+ }+ }else { /* non-simplicial neighbor */+ qh_setdel(neighbor->neighbors, same);+ if (neighbor->visitid != qh->visit_id) {+ qh_setappend(qh, &neighbor->neighbors, newfacet);+ qh_setappend(qh, &newfacet->neighbors, neighbor);+ neighbor->visitid= qh->visit_id;+ newneighbors++;+ }+ }+ }+ }+ trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",+ delneighbors, newneighbors));+} /* mergecycle_neighbors */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle_ridges">-</a>++ qh_mergecycle_ridges(qh, samecycle, newfacet )+ add ridges/neighbors for facets in samecycle to newfacet+ all new/old neighbors of newfacet marked with qh.visit_id+ facets in samecycle marked with qh.visit_id-1+ newfacet marked with qh.visit_id++ returns:+ newfacet has merged ridges++ notes:+ ridge already updated for simplicial neighbors of samecycle with a ridge++ see:+ qh_mergeridges()+ qh_makeridges()++ design:+ remove ridges between newfacet and samecycle+ for each facet in samecycle+ for each ridge in facet+ update facet pointers in ridge+ skip ridges processed in qh_mergecycle_neighors+ free ridges between newfacet and samecycle+ free ridges between facets of samecycle (on 2nd visit)+ append remaining ridges to newfacet+ if simpilicial facet+ for each neighbor of facet+ if simplicial facet+ and not samecycle facet or newfacet+ make ridge between neighbor and newfacet+*/+void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {+ facetT *same, *neighbor= NULL;+ int numold=0, numnew=0;+ int neighbor_i, neighbor_n;+ unsigned int samevisitid;+ ridgeT *ridge, **ridgep;+ boolT toporient;+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */++ trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));+ samevisitid= qh->visit_id -1;+ FOREACHridge_(newfacet->ridges) {+ neighbor= otherfacet_(ridge, newfacet);+ if (neighbor->visitid == samevisitid)+ SETref_(ridge)= NULL; /* ridge free'd below */+ }+ qh_setcompact(qh, newfacet->ridges);++ trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));+ FORALLsame_cycle_(samecycle) {+ FOREACHridge_(same->ridges) {+ if (ridge->top == same) {+ ridge->top= newfacet;+ neighbor= ridge->bottom;+ }else if (ridge->bottom == same) {+ ridge->bottom= newfacet;+ neighbor= ridge->top;+ }else if (ridge->top == newfacet || ridge->bottom == newfacet) {+ qh_setappend(qh, &newfacet->ridges, ridge);+ numold++; /* already set by qh_mergecycle_neighbors */+ continue;+ }else {+ qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);+ qh_errexit(qh, qh_ERRqhull, NULL, ridge);+ }+ if (neighbor == newfacet) {+ qh_setfree(qh, &(ridge->vertices));+ qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);+ numold++;+ }else if (neighbor->visitid == samevisitid) {+ qh_setdel(neighbor->ridges, ridge);+ qh_setfree(qh, &(ridge->vertices));+ qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);+ numold++;+ }else {+ qh_setappend(qh, &newfacet->ridges, ridge);+ numold++;+ }+ }+ if (same->ridges)+ qh_settruncate(qh, same->ridges, 0);+ if (!same->simplicial)+ continue;+ FOREACHneighbor_i_(qh, same) { /* note: !newfact->simplicial */+ if (neighbor->visitid != samevisitid && neighbor->simplicial) {+ ridge= qh_newridge(qh);+ ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,+ neighbor_i, 0);+ toporient= same->toporient ^ (neighbor_i & 0x1);+ if (toporient) {+ ridge->top= newfacet;+ ridge->bottom= neighbor;+ }else {+ ridge->top= neighbor;+ ridge->bottom= newfacet;+ }+ qh_setappend(qh, &(newfacet->ridges), ridge);+ qh_setappend(qh, &(neighbor->ridges), ridge);+ numnew++;+ }+ }+ }++ trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",+ numold, numnew));+} /* mergecycle_ridges */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergecycle_vneighbors">-</a>++ qh_mergecycle_vneighbors(qh, samecycle, newfacet )+ create vertex neighbors for newfacet from vertices of facets in samecycle+ samecycle marked with visitid == qh.visit_id - 1++ returns:+ newfacet vertices with updated neighbors+ marks newfacet with qh.visit_id-1+ deletes vertices that are merged away+ sets delridge on all vertices (faster here than in mergecycle_ridges)++ see:+ qh_mergevertex_neighbors()++ design:+ for each vertex of samecycle facet+ set vertex->delridge+ delete samecycle facets from vertex neighbors+ append newfacet to vertex neighbors+ if vertex only in newfacet+ delete it from newfacet+ add it to qh.del_vertices for later deletion+*/+void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {+ facetT *neighbor, **neighborp;+ unsigned int mergeid;+ vertexT *vertex, **vertexp, *apex;+ setT *vertices;++ trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));+ mergeid= qh->visit_id - 1;+ newfacet->visitid= mergeid;+ vertices= qh_basevertices(qh, samecycle); /* temp */+ apex= SETfirstt_(samecycle->vertices, vertexT);+ qh_setappend(qh, &vertices, apex);+ FOREACHvertex_(vertices) {+ vertex->delridge= True;+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid == mergeid)+ SETref_(neighbor)= NULL;+ }+ qh_setcompact(qh, vertex->neighbors);+ qh_setappend(qh, &vertex->neighbors, newfacet);+ if (!SETsecond_(vertex->neighbors)) {+ zinc_(Zcyclevertex);+ trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",+ vertex->id, samecycle->id, newfacet->id));+ qh_setdelsorted(newfacet->vertices, vertex);+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+ }+ }+ qh_settempfree(qh, &vertices);+ trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",+ samecycle->id, newfacet->id));+} /* mergecycle_vneighbors */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergefacet">-</a>++ qh_mergefacet(qh, facet1, facet2, mindist, maxdist, mergeapex )+ merges facet1 into facet2+ mergeapex==qh_MERGEapex if merging new facet into coplanar horizon++ returns:+ qh.max_outside and qh.min_vertex updated+ initializes vertex neighbors on first merge++ returns:+ facet2 contains facet1's vertices, neighbors, and ridges+ facet2 moved to end of qh.facet_list+ makes facet2 a newfacet+ sets facet2->newmerge set+ clears facet2->center (unless merging into a large facet)+ clears facet2->tested and ridge->tested for facet1++ facet1 prepended to visible_list for later deletion and partitioning+ facet1->f.replace == facet2++ adds neighboring facets to facet_mergeset if redundant or degenerate++ notes:+ mindist/maxdist may be NULL (only if both NULL)+ traces merge if fmax_(maxdist,-mindist) > TRACEdist++ see:+ qh_mergecycle()++ design:+ trace merge and check for degenerate simplex+ make ridges for both facets+ update qh.max_outside, qh.max_vertex, qh.min_vertex+ update facet2->maxoutside and keepcentrum+ update facet2->nummerge+ update tested flags for facet2+ if facet1 is simplicial+ merge facet1 into facet2+ else+ merge facet1's neighbors into facet2+ merge facet1's ridges into facet2+ merge facet1's vertices into facet2+ merge facet1's vertex neighbors into facet2+ add facet2's vertices to qh.new_vertexlist+ unless qh_MERGEapex+ test facet2 for degenerate or redundant neighbors+ move facet1 to qh.visible_list for later deletion+ move facet2 to end of qh.newfacet_list+*/+void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {+ boolT traceonce= False;+ vertexT *vertex, **vertexp;+ int tracerestore=0, nummerge;++ if (facet1->tricoplanar || facet2->tricoplanar) {+ if (!qh->TRInormals) {+ qh_fprintf(qh, qh->ferr, 6226, "Qhull internal error (qh_mergefacet): does not work for tricoplanar facets. Use option 'Q11'\n");+ qh_errexit2(qh, qh_ERRqhull, facet1, facet2);+ }+ if (facet2->tricoplanar) {+ facet2->tricoplanar= False;+ facet2->keepcentrum= False;+ }+ }+ zzinc_(Ztotmerge);+ if (qh->REPORTfreq2 && qh->POSTmerging) {+ if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)+ qh_tracemerging(qh);+ }+#ifndef qh_NOtrace+ if (qh->build_cnt >= qh->RERUN) {+ if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {+ tracerestore= 0;+ qh->IStracing= qh->TRACElevel;+ traceonce= True;+ qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),+ fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh->furthest_id);+ }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {+ tracerestore= qh->IStracing;+ qh->IStracing= 4;+ traceonce= True;+ qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",+ zzval_(Ztotmerge), qh->tracefacet_id, qh->furthest_id);+ }+ }+ if (qh->IStracing >= 2) {+ realT mergemin= -2;+ realT mergemax= -2;++ if (mindist) {+ mergemin= *mindist;+ mergemax= *maxdist;+ }+ qh_fprintf(qh, qh->ferr, 8077, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n",+ zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);+ }+#endif /* !qh_NOtrace */+ if (facet1 == facet2 || facet1->visible || facet2->visible) {+ qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",+ facet1->id, facet2->id);+ qh_errexit2(qh, qh_ERRqhull, facet1, facet2);+ }+ if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {+ qh_fprintf(qh, qh->ferr, 6227, "\n\+qhull precision error: Only %d facets remain. Can not merge another\n\+pair. The input is too degenerate or the convexity constraints are\n\+too strong.\n", qh->hull_dim+1);+ if (qh->hull_dim >= 5 && !qh->MERGEexact)+ qh_fprintf(qh, qh->ferr, 8079, "Option 'Qx' may avoid this problem.\n");+ qh_errexit(qh, qh_ERRprec, NULL, NULL);+ }+ if (!qh->VERTEXneighbors)+ qh_vertexneighbors(qh);+ qh_makeridges(qh, facet1);+ qh_makeridges(qh, facet2);+ if (qh->IStracing >=4)+ qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);+ if (mindist) {+ maximize_(qh->max_outside, *maxdist);+ maximize_(qh->max_vertex, *maxdist);+#if qh_MAXoutside+ maximize_(facet2->maxoutside, *maxdist);+#endif+ minimize_(qh->min_vertex, *mindist);+ if (!facet2->keepcentrum+ && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {+ facet2->keepcentrum= True;+ zinc_(Zwidefacet);+ }+ }+ nummerge= facet1->nummerge + facet2->nummerge + 1;+ if (nummerge >= qh_MAXnummerge)+ facet2->nummerge= qh_MAXnummerge;+ else+ facet2->nummerge= (short unsigned int)nummerge;+ facet2->newmerge= True;+ facet2->dupridge= False;+ qh_updatetested(qh, facet1, facet2);+ if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)+ qh_mergesimplex(qh, facet1, facet2, mergeapex);+ else {+ qh->vertex_visit++;+ FOREACHvertex_(facet2->vertices)+ vertex->visitid= qh->vertex_visit;+ if (qh->hull_dim == 2)+ qh_mergefacet2d(qh, facet1, facet2);+ else {+ qh_mergeneighbors(qh, facet1, facet2);+ qh_mergevertices(qh, facet1->vertices, &facet2->vertices);+ }+ qh_mergeridges(qh, facet1, facet2);+ qh_mergevertex_neighbors(qh, facet1, facet2);+ if (!facet2->newfacet)+ qh_newvertices(qh, facet2->vertices);+ }+ if (!mergeapex)+ qh_degen_redundant_neighbors(qh, facet2, facet1);+ if (facet2->coplanar || !facet2->newfacet) {+ zinc_(Zmergeintohorizon);+ }else if (!facet1->newfacet && facet2->newfacet) {+ zinc_(Zmergehorizon);+ }else {+ zinc_(Zmergenew);+ }+ qh_willdelete(qh, facet1, facet2);+ qh_removefacet(qh, facet2); /* append as a newfacet to end of qh->facet_list */+ qh_appendfacet(qh, facet2);+ facet2->newfacet= True;+ facet2->tested= False;+ qh_tracemerge(qh, facet1, facet2);+ if (traceonce) {+ qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");+ qh->IStracing= tracerestore;+ }+} /* mergefacet */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergefacet2d">-</a>++ qh_mergefacet2d(qh, facet1, facet2 )+ in 2d, merges neighbors and vertices of facet1 into facet2++ returns:+ build ridges for neighbors if necessary+ facet2 looks like a simplicial facet except for centrum, ridges+ neighbors are opposite the corresponding vertex+ maintains orientation of facet2++ notes:+ qh_mergefacet() retains non-simplicial structures+ they are not needed in 2d, but later routines may use them+ preserves qh.vertex_visit for qh_mergevertex_neighbors()++ design:+ get vertices and neighbors+ determine new vertices and neighbors+ set new vertices and neighbors and adjust orientation+ make ridges for new neighbor if needed+*/+void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {+ vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;+ facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;++ vertex1A= SETfirstt_(facet1->vertices, vertexT);+ vertex1B= SETsecondt_(facet1->vertices, vertexT);+ vertex2A= SETfirstt_(facet2->vertices, vertexT);+ vertex2B= SETsecondt_(facet2->vertices, vertexT);+ neighbor1A= SETfirstt_(facet1->neighbors, facetT);+ neighbor1B= SETsecondt_(facet1->neighbors, facetT);+ neighbor2A= SETfirstt_(facet2->neighbors, facetT);+ neighbor2B= SETsecondt_(facet2->neighbors, facetT);+ if (vertex1A == vertex2A) {+ vertexA= vertex1B;+ vertexB= vertex2B;+ neighborA= neighbor2A;+ neighborB= neighbor1A;+ }else if (vertex1A == vertex2B) {+ vertexA= vertex1B;+ vertexB= vertex2A;+ neighborA= neighbor2B;+ neighborB= neighbor1A;+ }else if (vertex1B == vertex2A) {+ vertexA= vertex1A;+ vertexB= vertex2B;+ neighborA= neighbor2A;+ neighborB= neighbor1B;+ }else { /* 1B == 2B */+ vertexA= vertex1A;+ vertexB= vertex2A;+ neighborA= neighbor2B;+ neighborB= neighbor1B;+ }+ /* vertexB always from facet2, neighborB always from facet1 */+ if (vertexA->id > vertexB->id) {+ SETfirst_(facet2->vertices)= vertexA;+ SETsecond_(facet2->vertices)= vertexB;+ if (vertexB == vertex2A)+ facet2->toporient= !facet2->toporient;+ SETfirst_(facet2->neighbors)= neighborA;+ SETsecond_(facet2->neighbors)= neighborB;+ }else {+ SETfirst_(facet2->vertices)= vertexB;+ SETsecond_(facet2->vertices)= vertexA;+ if (vertexB == vertex2B)+ facet2->toporient= !facet2->toporient;+ SETfirst_(facet2->neighbors)= neighborB;+ SETsecond_(facet2->neighbors)= neighborA;+ }+ qh_makeridges(qh, neighborB);+ qh_setreplace(qh, neighborB->neighbors, facet1, facet2);+ trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",+ vertexA->id, neighborB->id, facet1->id, facet2->id));+} /* mergefacet2d */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergeneighbors">-</a>++ qh_mergeneighbors(qh, facet1, facet2 )+ merges the neighbors of facet1 into facet2++ see:+ qh_mergecycle_neighbors()++ design:+ for each neighbor of facet1+ if neighbor is also a neighbor of facet2+ if neighbor is simpilicial+ make ridges for later deletion as a degenerate facet+ update its neighbor set+ else+ move the neighbor relation to facet2+ remove the neighbor relation for facet1 and facet2+*/+void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {+ facetT *neighbor, **neighborp;++ trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",+ facet1->id, facet2->id));+ qh->visit_id++;+ FOREACHneighbor_(facet2) {+ neighbor->visitid= qh->visit_id;+ }+ FOREACHneighbor_(facet1) {+ if (neighbor->visitid == qh->visit_id) {+ if (neighbor->simplicial) /* is degen, needs ridges */+ qh_makeridges(qh, neighbor);+ if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/+ qh_setdel(neighbor->neighbors, facet1);+ else {+ qh_setdel(neighbor->neighbors, facet2);+ qh_setreplace(qh, neighbor->neighbors, facet1, facet2);+ }+ }else if (neighbor != facet2) {+ qh_setappend(qh, &(facet2->neighbors), neighbor);+ qh_setreplace(qh, neighbor->neighbors, facet1, facet2);+ }+ }+ qh_setdel(facet1->neighbors, facet2); /* here for makeridges */+ qh_setdel(facet2->neighbors, facet1);+} /* mergeneighbors */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergeridges">-</a>++ qh_mergeridges(qh, facet1, facet2 )+ merges the ridge set of facet1 into facet2++ returns:+ may delete all ridges for a vertex+ sets vertex->delridge on deleted ridges++ see:+ qh_mergecycle_ridges()++ design:+ delete ridges between facet1 and facet2+ mark (delridge) vertices on these ridges for later testing+ for each remaining ridge+ rename facet1 to facet2+*/+void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {+ ridgeT *ridge, **ridgep;+ vertexT *vertex, **vertexp;++ trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d and f%d\n",+ facet1->id, facet2->id));+ FOREACHridge_(facet2->ridges) {+ if ((ridge->top == facet1) || (ridge->bottom == facet1)) {+ FOREACHvertex_(ridge->vertices)+ vertex->delridge= True;+ qh_delridge(qh, ridge); /* expensive in high-d, could rebuild */+ ridgep--; /*repeat*/+ }+ }+ FOREACHridge_(facet1->ridges) {+ if (ridge->top == facet1)+ ridge->top= facet2;+ else+ ridge->bottom= facet2;+ qh_setappend(qh, &(facet2->ridges), ridge);+ }+} /* mergeridges */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergesimplex">-</a>++ qh_mergesimplex(qh, facet1, facet2, mergeapex )+ merge simplicial facet1 into facet2+ mergeapex==qh_MERGEapex if merging samecycle into horizon facet+ vertex id is latest (most recently created)+ facet1 may be contained in facet2+ ridges exist for both facets++ returns:+ facet2 with updated vertices, ridges, neighbors+ updated neighbors for facet1's vertices+ facet1 not deleted+ sets vertex->delridge on deleted ridges++ notes:+ special case code since this is the most common merge+ called from qh_mergefacet()++ design:+ if qh_MERGEapex+ add vertices of facet2 to qh.new_vertexlist if necessary+ add apex to facet2+ else+ for each ridge between facet1 and facet2+ set vertex->delridge+ determine the apex for facet1 (i.e., vertex to be merged)+ unless apex already in facet2+ insert apex into vertices for facet2+ add vertices of facet2 to qh.new_vertexlist if necessary+ add apex to qh.new_vertexlist if necessary+ for each vertex of facet1+ if apex+ rename facet1 to facet2 in its vertex neighbors+ else+ delete facet1 from vertex neighors+ if only in facet2+ add vertex to qh.del_vertices for later deletion+ for each ridge of facet1+ delete ridges between facet1 and facet2+ append other ridges to facet2 after renaming facet to facet2+*/+void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {+ vertexT *vertex, **vertexp, *apex;+ ridgeT *ridge, **ridgep;+ boolT issubset= False;+ int vertex_i= -1, vertex_n;+ facetT *neighbor, **neighborp, *otherfacet;++ if (mergeapex) {+ if (!facet2->newfacet)+ qh_newvertices(qh, facet2->vertices); /* apex is new */+ apex= SETfirstt_(facet1->vertices, vertexT);+ if (SETfirstt_(facet2->vertices, vertexT) != apex)+ qh_setaddnth(qh, &facet2->vertices, 0, apex); /* apex has last id */+ else+ issubset= True;+ }else {+ zinc_(Zmergesimplex);+ FOREACHvertex_(facet1->vertices)+ vertex->seen= False;+ FOREACHridge_(facet1->ridges) {+ if (otherfacet_(ridge, facet1) == facet2) {+ FOREACHvertex_(ridge->vertices) {+ vertex->seen= True;+ vertex->delridge= True;+ }+ break;+ }+ }+ FOREACHvertex_(facet1->vertices) {+ if (!vertex->seen)+ break; /* must occur */+ }+ apex= vertex;+ trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",+ apex->id, facet1->id, facet2->id));+ FOREACHvertex_i_(qh, facet2->vertices) {+ if (vertex->id < apex->id) {+ break;+ }else if (vertex->id == apex->id) {+ issubset= True;+ break;+ }+ }+ if (!issubset)+ qh_setaddnth(qh, &facet2->vertices, vertex_i, apex);+ if (!facet2->newfacet)+ qh_newvertices(qh, facet2->vertices);+ else if (!apex->newlist) {+ qh_removevertex(qh, apex);+ qh_appendvertex(qh, apex);+ }+ }+ trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",+ facet1->id));+ FOREACHvertex_(facet1->vertices) {+ if (vertex == apex && !issubset)+ qh_setreplace(qh, vertex->neighbors, facet1, facet2);+ else {+ qh_setdel(vertex->neighbors, facet1);+ if (!SETsecond_(vertex->neighbors))+ qh_mergevertex_del(qh, vertex, facet1, facet2);+ }+ }+ trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",+ facet1->id, facet2->id));+ qh->visit_id++;+ FOREACHneighbor_(facet2)+ neighbor->visitid= qh->visit_id;+ FOREACHridge_(facet1->ridges) {+ otherfacet= otherfacet_(ridge, facet1);+ if (otherfacet == facet2) {+ qh_setdel(facet2->ridges, ridge);+ qh_setfree(qh, &(ridge->vertices));+ qh_memfree(qh, ridge, (int)sizeof(ridgeT));+ qh_setdel(facet2->neighbors, facet1);+ }else {+ qh_setappend(qh, &facet2->ridges, ridge);+ if (otherfacet->visitid != qh->visit_id) {+ qh_setappend(qh, &facet2->neighbors, otherfacet);+ qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);+ otherfacet->visitid= qh->visit_id;+ }else {+ if (otherfacet->simplicial) /* is degen, needs ridges */+ qh_makeridges(qh, otherfacet);+ if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)+ qh_setdel(otherfacet->neighbors, facet1);+ else { /*keep newfacet->neighbors->horizon*/+ qh_setdel(otherfacet->neighbors, facet2);+ qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);+ }+ }+ if (ridge->top == facet1) /* wait until after qh_makeridges */+ ridge->top= facet2;+ else+ ridge->bottom= facet2;+ }+ }+ SETfirst_(facet1->ridges)= NULL; /* it will be deleted */+ trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",+ facet1->id, getid_(apex), facet2->id));+} /* mergesimplex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergevertex_del">-</a>++ qh_mergevertex_del(qh, vertex, facet1, facet2 )+ delete a vertex because of merging facet1 into facet2++ returns:+ deletes vertex from facet2+ adds vertex to qh.del_vertices for later deletion+*/+void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {++ zinc_(Zmergevertex);+ trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",+ vertex->id, facet1->id, facet2->id));+ qh_setdelsorted(facet2->vertices, vertex);+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+} /* mergevertex_del */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergevertex_neighbors">-</a>++ qh_mergevertex_neighbors(qh, facet1, facet2 )+ merge the vertex neighbors of facet1 to facet2++ returns:+ if vertex is current qh.vertex_visit+ deletes facet1 from vertex->neighbors+ else+ renames facet1 to facet2 in vertex->neighbors+ deletes vertices if only one neighbor++ notes:+ assumes vertex neighbor sets are good+*/+void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {+ vertexT *vertex, **vertexp;++ trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",+ facet1->id, facet2->id));+ if (qh->tracevertex) {+ qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",+ facet1->id, facet2->id, qh->furthest_id, qh->tracevertex->neighbors->e[0].p);+ qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);+ }+ FOREACHvertex_(facet1->vertices) {+ if (vertex->visitid != qh->vertex_visit)+ qh_setreplace(qh, vertex->neighbors, facet1, facet2);+ else {+ qh_setdel(vertex->neighbors, facet1);+ if (!SETsecond_(vertex->neighbors))+ qh_mergevertex_del(qh, vertex, facet1, facet2);+ }+ }+ if (qh->tracevertex)+ qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);+} /* mergevertex_neighbors */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="mergevertices">-</a>++ qh_mergevertices(qh, vertices1, vertices2 )+ merges the vertex set of facet1 into facet2++ returns:+ replaces vertices2 with merged set+ preserves vertex_visit for qh_mergevertex_neighbors+ updates qh.newvertex_list++ design:+ create a merged set of both vertices (in inverse id order)+*/+void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {+ int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;+ setT *mergedvertices;+ vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);++ mergedvertices= qh_settemp(qh, newsize);+ FOREACHvertex_(vertices1) {+ if (!*vertex2 || vertex->id > (*vertex2)->id)+ qh_setappend(qh, &mergedvertices, vertex);+ else {+ while (*vertex2 && (*vertex2)->id > vertex->id)+ qh_setappend(qh, &mergedvertices, *vertex2++);+ if (!*vertex2 || (*vertex2)->id < vertex->id)+ qh_setappend(qh, &mergedvertices, vertex);+ else+ qh_setappend(qh, &mergedvertices, *vertex2++);+ }+ }+ while (*vertex2)+ qh_setappend(qh, &mergedvertices, *vertex2++);+ if (newsize < qh_setsize(qh, mergedvertices)) {+ qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ qh_setfree(qh, vertices2);+ *vertices2= mergedvertices;+ qh_settemppop(qh);+} /* mergevertices */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="neighbor_intersections">-</a>++ qh_neighbor_intersections(qh, vertex )+ return intersection of all vertices in vertex->neighbors except for vertex++ returns:+ returns temporary set of vertices+ does not include vertex+ NULL if a neighbor is simplicial+ NULL if empty set++ notes:+ used for renaming vertices++ design:+ initialize the intersection set with vertices of the first two neighbors+ delete vertex from the intersection+ for each remaining neighbor+ intersect its vertex set with the intersection set+ return NULL if empty+ return the intersection set+*/+setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {+ facetT *neighbor, **neighborp, *neighborA, *neighborB;+ setT *intersect;+ int neighbor_i, neighbor_n;++ FOREACHneighbor_(vertex) {+ if (neighbor->simplicial)+ return NULL;+ }+ neighborA= SETfirstt_(vertex->neighbors, facetT);+ neighborB= SETsecondt_(vertex->neighbors, facetT);+ zinc_(Zintersectnum);+ if (!neighborA)+ return NULL;+ if (!neighborB)+ intersect= qh_setcopy(qh, neighborA->vertices, 0);+ else+ intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);+ qh_settemppush(qh, intersect);+ qh_setdelsorted(intersect, vertex);+ FOREACHneighbor_i_(qh, vertex) {+ if (neighbor_i >= 2) {+ zinc_(Zintersectnum);+ qh_vertexintersect(qh, &intersect, neighbor->vertices);+ if (!SETfirst_(intersect)) {+ zinc_(Zintersectfail);+ qh_settempfree(qh, &intersect);+ return NULL;+ }+ }+ }+ trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",+ qh_setsize(qh, intersect), vertex->id));+ return intersect;+} /* neighbor_intersections */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="newvertices">-</a>++ qh_newvertices(qh, vertices )+ add vertices to end of qh.vertex_list (marks as new vertices)++ returns:+ vertices on qh.newvertex_list+ vertex->newlist set+*/+void qh_newvertices(qhT *qh, setT *vertices) {+ vertexT *vertex, **vertexp;++ FOREACHvertex_(vertices) {+ if (!vertex->newlist) {+ qh_removevertex(qh, vertex);+ qh_appendvertex(qh, vertex);+ }+ }+} /* newvertices */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="reducevertices">-</a>++ qh_reducevertices(qh)+ reduce extra vertices, shared vertices, and redundant vertices+ facet->newmerge is set if merged since last call+ if !qh.MERGEvertices, only removes extra vertices++ returns:+ True if also merged degen_redundant facets+ vertices are renamed if possible+ clears facet->newmerge and vertex->delridge++ notes:+ ignored if 2-d++ design:+ merge any degenerate or redundant facets+ for each newly merged facet+ remove extra vertices+ if qh.MERGEvertices+ for each newly merged facet+ for each vertex+ if vertex was on a deleted ridge+ rename vertex if it is shared+ remove delridge flag from new vertices+*/+boolT qh_reducevertices(qhT *qh) {+ int numshare=0, numrename= 0;+ boolT degenredun= False;+ facetT *newfacet;+ vertexT *vertex, **vertexp;++ if (qh->hull_dim == 2)+ return False;+ if (qh_merge_degenredundant(qh))+ degenredun= True;+ LABELrestart:+ FORALLnew_facets {+ if (newfacet->newmerge) {+ if (!qh->MERGEvertices)+ newfacet->newmerge= False;+ qh_remove_extravertices(qh, newfacet);+ }+ }+ if (!qh->MERGEvertices)+ return False;+ FORALLnew_facets {+ if (newfacet->newmerge) {+ newfacet->newmerge= False;+ FOREACHvertex_(newfacet->vertices) {+ if (vertex->delridge) {+ if (qh_rename_sharedvertex(qh, vertex, newfacet)) {+ numshare++;+ vertexp--; /* repeat since deleted vertex */+ }+ }+ }+ }+ }+ FORALLvertex_(qh->newvertex_list) {+ if (vertex->delridge && !vertex->deleted) {+ vertex->delridge= False;+ if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {+ numrename++;+ if (qh_merge_degenredundant(qh)) {+ degenredun= True;+ goto LABELrestart;+ }+ }+ }+ }+ trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",+ numshare, numrename, degenredun));+ return degenredun;+} /* reducevertices */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="redundant_vertex">-</a>++ qh_redundant_vertex(qh, vertex )+ detect and rename a redundant vertex+ vertices have full vertex->neighbors++ returns:+ returns true if find a redundant vertex+ deletes vertex(vertex->deleted)++ notes:+ only needed if vertex->delridge and hull_dim >= 4+ may add degenerate facets to qh.facet_mergeset+ doesn't change vertex->neighbors or create redundant facets++ design:+ intersect vertices of all facet neighbors of vertex+ determine ridges for these vertices+ if find a new vertex for vertex amoung these ridges and vertices+ rename vertex to the new vertex+*/+vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {+ vertexT *newvertex= NULL;+ setT *vertices, *ridges;++ trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));+ if ((vertices= qh_neighbor_intersections(qh, vertex))) {+ ridges= qh_vertexridges(qh, vertex);+ if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))+ qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL);+ qh_settempfree(qh, &ridges);+ qh_settempfree(qh, &vertices);+ }+ return newvertex;+} /* redundant_vertex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="remove_extravertices">-</a>++ qh_remove_extravertices(qh, facet )+ remove extra vertices from non-simplicial facets++ returns:+ returns True if it finds them++ design:+ for each vertex in facet+ if vertex not in a ridge (i.e., no longer used)+ delete vertex from facet+ delete facet from vertice's neighbors+ unless vertex in another facet+ add vertex to qh.del_vertices for later deletion+*/+boolT qh_remove_extravertices(qhT *qh, facetT *facet) {+ ridgeT *ridge, **ridgep;+ vertexT *vertex, **vertexp;+ boolT foundrem= False;++ trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test f%d for extra vertices\n",+ facet->id));+ FOREACHvertex_(facet->vertices)+ vertex->seen= False;+ FOREACHridge_(facet->ridges) {+ FOREACHvertex_(ridge->vertices)+ vertex->seen= True;+ }+ FOREACHvertex_(facet->vertices) {+ if (!vertex->seen) {+ foundrem= True;+ zinc_(Zremvertex);+ qh_setdelsorted(facet->vertices, vertex);+ qh_setdel(vertex->neighbors, facet);+ if (!qh_setsize(qh, vertex->neighbors)) {+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+ zinc_(Zremvertexdel);+ trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));+ }else+ trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));+ vertexp--; /*repeat*/+ }+ }+ return foundrem;+} /* remove_extravertices */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="rename_sharedvertex">-</a>++ qh_rename_sharedvertex(qh, vertex, facet )+ detect and rename if shared vertex in facet+ vertices have full ->neighbors++ returns:+ newvertex or NULL+ the vertex may still exist in other facets (i.e., a neighbor was pinched)+ does not change facet->neighbors+ updates vertex->neighbors++ notes:+ a shared vertex for a facet is only in ridges to one neighbor+ this may undo a pinched facet++ it does not catch pinches involving multiple facets. These appear+ to be difficult to detect, since an exhaustive search is too expensive.++ design:+ if vertex only has two neighbors+ determine the ridges that contain the vertex+ determine the vertices shared by both neighbors+ if can find a new vertex in this set+ rename the vertex to the new vertex+*/+vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {+ facetT *neighbor, **neighborp, *neighborA= NULL;+ setT *vertices, *ridges;+ vertexT *newvertex;++ if (qh_setsize(qh, vertex->neighbors) == 2) {+ neighborA= SETfirstt_(vertex->neighbors, facetT);+ if (neighborA == facet)+ neighborA= SETsecondt_(vertex->neighbors, facetT);+ }else if (qh->hull_dim == 3)+ return NULL;+ else {+ qh->visit_id++;+ FOREACHneighbor_(facet)+ neighbor->visitid= qh->visit_id;+ FOREACHneighbor_(vertex) {+ if (neighbor->visitid == qh->visit_id) {+ if (neighborA)+ return NULL;+ neighborA= neighbor;+ }+ }+ if (!neighborA) {+ qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",+ vertex->id, facet->id);+ qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ }+ /* the vertex is shared by facet and neighborA */+ ridges= qh_settemp(qh, qh->TEMPsize);+ neighborA->visitid= ++qh->visit_id;+ qh_vertexridges_facet(qh, vertex, facet, &ridges);+ trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",+ qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));+ zinc_(Zintersectnum);+ vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);+ qh_setdel(vertices, vertex);+ qh_settemppush(qh, vertices);+ if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))+ qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA);+ qh_settempfree(qh, &vertices);+ qh_settempfree(qh, &ridges);+ return newvertex;+} /* rename_sharedvertex */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="renameridgevertex">-</a>++ qh_renameridgevertex(qh, ridge, oldvertex, newvertex )+ renames oldvertex as newvertex in ridge++ returns:++ design:+ delete oldvertex from ridge+ if newvertex already in ridge+ copy ridge->noconvex to another ridge if possible+ delete the ridge+ else+ insert newvertex into the ridge+ adjust the ridge's orientation+*/+void qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {+ int nth= 0, oldnth;+ facetT *temp;+ vertexT *vertex, **vertexp;++ oldnth= qh_setindex(ridge->vertices, oldvertex);+ qh_setdelnthsorted(qh, ridge->vertices, oldnth);+ FOREACHvertex_(ridge->vertices) {+ if (vertex == newvertex) {+ zinc_(Zdelridge);+ if (ridge->nonconvex) /* only one ridge has nonconvex set */+ qh_copynonconvex(qh, ridge);+ trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted. It contained both v%d and v%d\n",+ ridge->id, oldvertex->id, newvertex->id));+ qh_delridge(qh, ridge);+ return;+ }+ if (vertex->id < newvertex->id)+ break;+ nth++;+ }+ qh_setaddnth(qh, &ridge->vertices, nth, newvertex);+ if (abs(oldnth - nth)%2) {+ trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",+ ridge->id));+ temp= ridge->top;+ ridge->top= ridge->bottom;+ ridge->bottom= temp;+ }+} /* renameridgevertex */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="renamevertex">-</a>++ qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )+ renames oldvertex as newvertex in ridges+ gives oldfacet/neighborA if oldvertex is shared between two facets++ returns:+ oldvertex may still exist afterwards+++ notes:+ can not change neighbors of newvertex (since it's a subset)++ design:+ for each ridge in ridges+ rename oldvertex to newvertex and delete degenerate ridges+ if oldfacet not defined+ for each neighbor of oldvertex+ delete oldvertex from neighbor's vertices+ remove extra vertices from neighbor+ add oldvertex to qh.del_vertices+ else if oldvertex only between oldfacet and neighborA+ delete oldvertex from oldfacet and neighborA+ add oldvertex to qh.del_vertices+ else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)+ delete oldvertex from oldfacet+ delete oldfacet from oldvertice's neighbors+ remove extra vertices (e.g., oldvertex) from neighborA+*/+void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {+ facetT *neighbor, **neighborp;+ ridgeT *ridge, **ridgep;+ boolT istrace= False;++ if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||+ newvertex->id == qh->tracevertex_id)+ istrace= True;+ FOREACHridge_(ridges)+ qh_renameridgevertex(qh, ridge, oldvertex, newvertex);+ if (!oldfacet) {+ zinc_(Zrenameall);+ if (istrace)+ qh_fprintf(qh, qh->ferr, 8082, "qh_renamevertex: renamed v%d to v%d in several facets\n",+ oldvertex->id, newvertex->id);+ FOREACHneighbor_(oldvertex) {+ qh_maydropneighbor(qh, neighbor);+ qh_setdelsorted(neighbor->vertices, oldvertex);+ if (qh_remove_extravertices(qh, neighbor))+ neighborp--; /* neighbor may be deleted */+ }+ if (!oldvertex->deleted) {+ oldvertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, oldvertex);+ }+ }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {+ zinc_(Zrenameshare);+ if (istrace)+ qh_fprintf(qh, qh->ferr, 8083, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n",+ oldvertex->id, newvertex->id, oldfacet->id);+ FOREACHneighbor_(oldvertex)+ qh_setdelsorted(neighbor->vertices, oldvertex);+ oldvertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, oldvertex);+ }else {+ zinc_(Zrenamepinch);+ if (istrace || qh->IStracing)+ qh_fprintf(qh, qh->ferr, 8084, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n",+ oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);+ qh_setdelsorted(oldfacet->vertices, oldvertex);+ qh_setdel(oldvertex->neighbors, oldfacet);+ qh_remove_extravertices(qh, neighborA);+ }+} /* renamevertex */+++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="test_appendmerge">-</a>++ qh_test_appendmerge(qh, facet, neighbor )+ tests facet/neighbor for convexity+ appends to mergeset if non-convex+ if pre-merging,+ nop if qh.SKIPconvex, or qh.MERGEexact and coplanar++ returns:+ true if appends facet/neighbor to mergeset+ sets facet->center as needed+ does not change facet->seen++ design:+ if qh.cos_max is defined+ if the angle between facet normals is too shallow+ append an angle-coplanar merge to qh.mergeset+ return True+ make facet's centrum if needed+ if facet's centrum is above the neighbor+ set isconcave+ else+ if facet's centrum is not below the neighbor+ set iscoplanar+ make neighbor's centrum if needed+ if neighbor's centrum is above the facet+ set isconcave+ else if neighbor's centrum is not below the facet+ set iscoplanar+ if isconcave or iscoplanar+ get angle if needed+ append concave or coplanar merge to qh.mergeset+*/+boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor) {+ realT dist, dist2= -REALmax, angle= -REALmax;+ boolT isconcave= False, iscoplanar= False, okangle= False;++ if (qh->SKIPconvex && !qh->POSTmerging)+ return False;+ if ((!qh->MERGEexact || qh->POSTmerging) && qh->cos_max < REALmax/2) {+ angle= qh_getangle(qh, facet->normal, neighbor->normal);+ zinc_(Zangletests);+ if (angle > qh->cos_max) {+ zinc_(Zcoplanarangle);+ qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, &angle);+ trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",+ angle, facet->id, neighbor->id));+ return True;+ }else+ okangle= True;+ }+ if (!facet->center)+ facet->center= qh_getcentrum(qh, facet);+ zzinc_(Zcentrumtests);+ qh_distplane(qh, facet->center, neighbor, &dist);+ if (dist > qh->centrum_radius)+ isconcave= True;+ else {+ if (dist > -qh->centrum_radius)+ iscoplanar= True;+ if (!neighbor->center)+ neighbor->center= qh_getcentrum(qh, neighbor);+ zzinc_(Zcentrumtests);+ qh_distplane(qh, neighbor->center, facet, &dist2);+ if (dist2 > qh->centrum_radius)+ isconcave= True;+ else if (!iscoplanar && dist2 > -qh->centrum_radius)+ iscoplanar= True;+ }+ if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))+ return False;+ if (!okangle && qh->ANGLEmerge) {+ angle= qh_getangle(qh, facet->normal, neighbor->normal);+ zinc_(Zangletests);+ }+ if (isconcave) {+ zinc_(Zconcaveridge);+ if (qh->ANGLEmerge)+ angle += qh_ANGLEconcave + 0.5;+ qh_appendmergeset(qh, facet, neighbor, MRGconcave, &angle);+ trace0((qh, qh->ferr, 18, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",+ facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));+ }else /* iscoplanar */ {+ zinc_(Zcoplanarcentrum);+ qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, &angle);+ trace2((qh, qh->ferr, 2040, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",+ facet->id, neighbor->id, dist, dist2, angle));+ }+ return True;+} /* test_appendmerge */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="test_vneighbors">-</a>++ qh_test_vneighbors(qh)+ test vertex neighbors for convexity+ tests all facets on qh.newfacet_list++ returns:+ true if non-convex vneighbors appended to qh.facet_mergeset+ initializes vertex neighbors if needed++ notes:+ assumes all facet neighbors have been tested+ this can be expensive+ this does not guarantee that a centrum is below all facets+ but it is unlikely+ uses qh.visit_id++ design:+ build vertex neighbors if necessary+ for all new facets+ for all vertices+ for each unvisited facet neighbor of the vertex+ test new facet and neighbor for convexity+*/+boolT qh_test_vneighbors(qhT *qh /* qh->newfacet_list */) {+ facetT *newfacet, *neighbor, **neighborp;+ vertexT *vertex, **vertexp;+ int nummerges= 0;++ trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));+ if (!qh->VERTEXneighbors)+ qh_vertexneighbors(qh);+ FORALLnew_facets+ newfacet->seen= False;+ FORALLnew_facets {+ newfacet->seen= True;+ newfacet->visitid= qh->visit_id++;+ FOREACHneighbor_(newfacet)+ newfacet->visitid= qh->visit_id;+ FOREACHvertex_(newfacet->vertices) {+ FOREACHneighbor_(vertex) {+ if (neighbor->seen || neighbor->visitid == qh->visit_id)+ continue;+ if (qh_test_appendmerge(qh, newfacet, neighbor))+ nummerges++;+ }+ }+ }+ zadd_(Ztestvneighbor, nummerges);+ trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",+ nummerges));+ return (nummerges > 0);+} /* test_vneighbors */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="tracemerge">-</a>++ qh_tracemerge(qh, facet1, facet2 )+ print trace message after merge+*/+void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2) {+ boolT waserror= False;++#ifndef qh_NOtrace+ if (qh->IStracing >= 4)+ qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);+ if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newlist)) {+ qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh->furthest_id);+ if (facet2 != qh->tracefacet)+ qh_errprint(qh, "TRACE", qh->tracefacet,+ (qh->tracevertex && qh->tracevertex->neighbors) ?+ SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,+ NULL, qh->tracevertex);+ }+ if (qh->tracevertex) {+ if (qh->tracevertex->deleted)+ qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",+ qh->furthest_id);+ else+ qh_checkvertex(qh, qh->tracevertex);+ }+ if (qh->tracefacet) {+ qh_checkfacet(qh, qh->tracefacet, True, &waserror);+ if (waserror)+ qh_errexit(qh, qh_ERRqhull, qh->tracefacet, NULL);+ }+#endif /* !qh_NOtrace */+ if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */+ qh_checkfacet(qh, facet2, True, &waserror);+ if (waserror)+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+} /* tracemerge */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="tracemerging">-</a>++ qh_tracemerging(qh)+ print trace message during POSTmerging++ returns:+ updates qh.mergereport++ notes:+ called from qh_mergecycle() and qh_mergefacet()++ see:+ qh_buildtracing()+*/+void qh_tracemerging(qhT *qh) {+ realT cpu;+ int total;+ time_t timedata;+ struct tm *tp;++ qh->mergereport= zzval_(Ztotmerge);+ time(&timedata);+ tp= localtime(&timedata);+ cpu= qh_CPUclock;+ cpu /= qh_SECticks;+ total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);+ qh_fprintf(qh, qh->ferr, 8087, "\n\+At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets. The hull\n\+ contains %d facets and %d vertices.\n",+ tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,+ total, qh->num_facets - qh->num_visible,+ qh->num_vertices-qh_setsize(qh, qh->del_vertices));+} /* tracemerging */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="updatetested">-</a>++ qh_updatetested(qh, facet1, facet2 )+ clear facet2->tested and facet1->ridge->tested for merge++ returns:+ deletes facet2->center unless it's already large+ if so, clears facet2->ridge->tested++ design:+ clear facet2->tested+ clear ridge->tested for facet1's ridges+ if facet2 has a centrum+ if facet2 is large+ set facet2->keepcentrum+ else if facet2 has 3 vertices due to many merges, or not large and post merging+ clear facet2->keepcentrum+ unless facet2->keepcentrum+ clear facet2->center to recompute centrum later+ clear ridge->tested for facet2's ridges+*/+void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {+ ridgeT *ridge, **ridgep;+ int size;++ facet2->tested= False;+ FOREACHridge_(facet1->ridges)+ ridge->tested= False;+ if (!facet2->center)+ return;+ size= qh_setsize(qh, facet2->vertices);+ if (!facet2->keepcentrum) {+ if (size > qh->hull_dim + qh_MAXnewcentrum) {+ facet2->keepcentrum= True;+ zinc_(Zwidevertices);+ }+ }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {+ /* center and keepcentrum was set */+ if (size == qh->hull_dim || qh->POSTmerging)+ facet2->keepcentrum= False; /* if many merges need to recompute centrum */+ }+ if (!facet2->keepcentrum) {+ qh_memfree(qh, facet2->center, qh->normal_size);+ facet2->center= NULL;+ FOREACHridge_(facet2->ridges)+ ridge->tested= False;+ }+} /* updatetested */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="vertexridges">-</a>++ qh_vertexridges(qh, vertex )+ return temporary set of ridges adjacent to a vertex+ vertex->neighbors defined++ ntoes:+ uses qh.visit_id+ does not include implicit ridges for simplicial facets++ design:+ for each neighbor of vertex+ add ridges that include the vertex to ridges+*/+setT *qh_vertexridges(qhT *qh, vertexT *vertex) {+ facetT *neighbor, **neighborp;+ setT *ridges= qh_settemp(qh, qh->TEMPsize);+ int size;++ qh->visit_id++;+ FOREACHneighbor_(vertex)+ neighbor->visitid= qh->visit_id;+ FOREACHneighbor_(vertex) {+ if (*neighborp) /* no new ridges in last neighbor */+ qh_vertexridges_facet(qh, vertex, neighbor, &ridges);+ }+ if (qh->PRINTstatistics || qh->IStracing) {+ size= qh_setsize(qh, ridges);+ zinc_(Zvertexridge);+ zadd_(Zvertexridgetot, size);+ zmax_(Zvertexridgemax, size);+ trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",+ size, vertex->id));+ }+ return ridges;+} /* vertexridges */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="vertexridges_facet">-</a>++ qh_vertexridges_facet(qh, vertex, facet, ridges )+ add adjacent ridges for vertex in facet+ neighbor->visitid==qh.visit_id if it hasn't been visited++ returns:+ ridges updated+ sets facet->visitid to qh.visit_id-1++ design:+ for each ridge of facet+ if ridge of visited neighbor (i.e., unprocessed)+ if vertex in ridge+ append ridge to vertex+ mark facet processed+*/+void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {+ ridgeT *ridge, **ridgep;+ facetT *neighbor;++ FOREACHridge_(facet->ridges) {+ neighbor= otherfacet_(ridge, facet);+ if (neighbor->visitid == qh->visit_id+ && qh_setin(ridge->vertices, vertex))+ qh_setappend(qh, ridges, ridge);+ }+ facet->visitid= qh->visit_id-1;+} /* vertexridges_facet */++/*-<a href="qh-merge_r.htm#TOC"+ >-------------------------------</a><a name="willdelete">-</a>++ qh_willdelete(qh, facet, replace )+ moves facet to visible list+ sets facet->f.replace to replace (may be NULL)++ returns:+ bumps qh.num_visible+*/+void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {++ qh_removefacet(qh, facet);+ qh_prependfacet(qh, facet, &qh->visible_list);+ qh->num_visible++;+ facet->visible= True;+ facet->f.replace= replace;+} /* willdelete */++#else /* qh_NOmerge */+void qh_premerge(qhT *qh, vertexT *apex, realT maxcentrum, realT maxangle) {+}+void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,+ boolT vneighbors) {+}+boolT qh_checkzero(qhT *qh, boolT testall) {+ }+#endif /* qh_NOmerge */+
+ Cdir/poly2_r.c view
@@ -0,0 +1,3222 @@+/*<html><pre> -<a href="qh-poly_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ poly2_r.c+ implements polygons and simplicies++ see qh-poly_r.htm, poly_r.h and libqhull_r.h++ frequently used code is in poly_r.c++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/poly2_r.c#10 $$Change: 2069 $+ $DateTime: 2016/01/18 22:05:03 $$Author: bbarber $+*/++#include "qhull_ra.h"++/*======== functions in alphabetical order ==========*/++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="addhash">-</a>++ qh_addhash( newelem, hashtable, hashsize, hash )+ add newelem to linear hash table at hash if not already there+*/+void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {+ int scan;+ void *elem;++ for (scan= (int)hash; (elem= SETelem_(hashtable, scan));+ scan= (++scan >= hashsize ? 0 : scan)) {+ if (elem == newelem)+ break;+ }+ /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */+ if (!elem)+ SETelem_(hashtable, scan)= newelem;+} /* addhash */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_bestdist">-</a>++ qh_check_bestdist(qh)+ check that all points are within max_outside of the nearest facet+ if qh.ONLYgood,+ ignores !good facets++ see:+ qh_check_maxout(), qh_outerinner()++ notes:+ only called from qh_check_points()+ seldom used since qh.MERGING is almost always set+ if notverified>0 at end of routine+ some points were well inside the hull. If the hull contains+ a lens-shaped component, these points were not verified. Use+ options 'Qi Tv' to verify all points. (Exhaustive check also verifies)++ design:+ determine facet for each point (if any)+ for each point+ start with the assigned facet or with the first facet+ find the best facet for the point and check all coplanar facets+ error if point is outside of facet+*/+void qh_check_bestdist(qhT *qh) {+ boolT waserror= False, unassigned;+ facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;+ facetT *facetlist;+ realT dist, maxoutside, maxdist= -REALmax;+ pointT *point;+ int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;+ setT *facets;++ trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet. Facet_list f%d\n",+ qh->facet_list->id));+ maxoutside= qh_maxouter(qh);+ maxoutside += qh->DISTround;+ /* one more qh.DISTround for check computation */+ trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));+ facets= qh_pointfacet(qh /*qh.facet_list*/);+ if (!qh_QUICKhelp && qh->PRINTprecision)+ qh_fprintf(qh, qh->ferr, 8091, "\n\+qhull output completed. Verifying that %d points are\n\+below %2.2g of the nearest %sfacet.\n",+ qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ? "good " : ""));+ FOREACHfacet_i_(qh, facets) { /* for each point with facet assignment */+ if (facet)+ unassigned= False;+ else {+ unassigned= True;+ facet= qh->facet_list;+ }+ point= qh_point(qh, facet_i);+ if (point == qh->GOODpointp)+ continue;+ qh_distplane(qh, point, facet, &dist);+ numpart++;+ bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);+ /* occurs after statistics reported */+ maximize_(maxdist, dist);+ if (dist > maxoutside) {+ if (qh->ONLYgood && !bestfacet->good+ && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))+ && dist > maxoutside))+ notgood++;+ else {+ waserror= True;+ qh_fprintf(qh, qh->ferr, 6109, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",+ facet_i, bestfacet->id, dist, maxoutside);+ if (errfacet1 != bestfacet) {+ errfacet2= errfacet1;+ errfacet1= bestfacet;+ }+ }+ }else if (unassigned && dist < -qh->MAXcoplanar)+ notverified++;+ }+ qh_settempfree(qh, &facets);+ if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)+ qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull. If the hull contains\n\+a lens-shaped component, these points were not verified. Use\n\+options 'Qci Tv' to verify all points.\n", notverified);+ if (maxdist > qh->outside_err) {+ qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n",+ maxdist, qh->outside_err);+ qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);+ }else if (waserror && qh->outside_err > REALmax/2)+ qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);+ /* else if waserror, the error was logged to qh.ferr but does not effect the output */+ trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));+} /* check_bestdist */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_dupridge">-</a>++ qh_check_dupridge(qh, facet1, dist1, facet2, dist2)+ Check duplicate ridge between facet1 and facet2 for wide merge+ dist1 is the maximum distance of facet1's vertices to facet2+ dist2 is the maximum distance of facet2's vertices to facet1++ Returns+ Level 1 log of the duplicate ridge with the minimum distance between vertices+ Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)++ called from:+ qh_forcedmerges()+*/+#ifndef qh_NOmerge+void qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2) {+ vertexT *vertex, **vertexp, *vertexA, **vertexAp;+ realT dist, innerplane, mergedist, outerplane, prevdist, ratio;+ realT minvertex= REALmax;++ mergedist= fmin_(dist1, dist2);+ qh_outerinner(qh, NULL, &outerplane, &innerplane); /* ratio from qh_printsummary */+ prevdist= fmax_(outerplane, innerplane);+ maximize_(prevdist, qh->ONEmerge + qh->DISTround);+ maximize_(prevdist, qh->MINoutside + qh->DISTround);+ ratio= mergedist/prevdist;+ FOREACHvertex_(facet1->vertices) { /* The duplicate ridge is between facet1 and facet2, so either facet can be tested */+ FOREACHvertexA_(facet1->vertices) {+ if (vertex > vertexA){ /* Test each pair once */+ dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);+ minimize_(minvertex, dist);+ }+ }+ }+ trace0((qh, qh->ferr, 16, "qh_check_dupridge: duplicate ridge between f%d and f%d due to nearly-coincident vertices (%2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",+ facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh->furthest_id));+ if (ratio > qh_WIDEduplicate) {+ qh_fprintf(qh, qh->ferr, 6271, "qhull precision error (qh_check_dupridge): wide merge (%.0f times wider) due to duplicate ridge with nearly coincident points (%2.2g) between f%d and f%d, merge dist %2.2g, while processing p%d\n- Ignore error with option 'Q12'\n- To be fixed in a later version of Qhull\n",+ ratio, minvertex, facet1->id, facet2->id, mergedist, qh->furthest_id);+ if (qh->DELAUNAY)+ qh_fprintf(qh, qh->ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");+ if(minvertex > qh_WIDEduplicate*prevdist)+ qh_fprintf(qh, qh->ferr, 8146, "- Vertex distance %2.2g is greater than %d times maximum distance %2.2g\n Please report to bradb@shore.net with steps to reproduce and all output\n",+ minvertex, qh_WIDEduplicate, prevdist);+ if (!qh->NOwide)+ qh_errexit2(qh, qh_ERRqhull, facet1, facet2);+ }+} /* check_dupridge */+#endif++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_maxout">-</a>++ qh_check_maxout(qh)+ updates qh.max_outside by checking all points against bestfacet+ if qh.ONLYgood, ignores !good facets++ returns:+ updates facet->maxoutside via qh_findbesthorizon()+ sets qh.maxoutdone+ if printing qh.min_vertex (qh_outerinner),+ it is updated to the current vertices+ removes inside/coplanar points from coplanarset as needed++ notes:+ defines coplanar as min_vertex instead of MAXcoplanar+ may not need to check near-inside points because of qh.MAXcoplanar+ and qh.KEEPnearinside (before it was -DISTround)++ see also:+ qh_check_bestdist()++ design:+ if qh.min_vertex is needed+ for all neighbors of all vertices+ test distance from vertex to neighbor+ determine facet for each point (if any)+ for each point with an assigned facet+ find the best facet for the point and check all coplanar facets+ (updates outer planes)+ remove near-inside points from coplanar sets+*/+#ifndef qh_NOmerge+void qh_check_maxout(qhT *qh) {+ facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;+ realT dist, maxoutside, minvertex, old_maxoutside;+ pointT *point;+ int numpart= 0, facet_i, facet_n, notgood= 0;+ setT *facets, *vertices;+ vertexT *vertex;++ trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update maxoutside for each facet.\n"));+ maxoutside= minvertex= 0;+ if (qh->VERTEXneighbors+ && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar+ || qh->TRACElevel || qh->PRINTstatistics+ || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {+ trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual maxoutside and minvertex\n"));+ vertices= qh_pointvertex(qh /*qh.facet_list*/);+ FORALLvertices {+ FOREACHneighbor_(vertex) {+ zinc_(Zdistvertex); /* distance also computed by main loop below */+ qh_distplane(qh, vertex->point, neighbor, &dist);+ minimize_(minvertex, dist);+ if (-dist > qh->TRACEdist || dist > qh->TRACEdist+ || neighbor == qh->tracefacet || vertex == qh->tracevertex)+ qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d\n",+ qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);+ }+ }+ if (qh->MERGING) {+ wmin_(Wminvertex, qh->min_vertex);+ }+ qh->min_vertex= minvertex;+ qh_settempfree(qh, &vertices);+ }+ facets= qh_pointfacet(qh /*qh.facet_list*/);+ do {+ old_maxoutside= fmax_(qh->max_outside, maxoutside);+ FOREACHfacet_i_(qh, facets) { /* for each point with facet assignment */+ if (facet) {+ point= qh_point(qh, facet_i);+ if (point == qh->GOODpointp)+ continue;+ zzinc_(Ztotcheck);+ qh_distplane(qh, point, facet, &dist);+ numpart++;+ bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);+ if (bestfacet && dist > maxoutside) {+ if (qh->ONLYgood && !bestfacet->good+ && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))+ && dist > maxoutside))+ notgood++;+ else+ maxoutside= dist;+ }+ if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))+ qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",+ qh_pointid(qh, point), dist, (bestfacet ? bestfacet->id : UINT_MAX));+ }+ }+ }while+ (maxoutside > 2*old_maxoutside);+ /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid+ e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */+ zzadd_(Zcheckpart, numpart);+ qh_settempfree(qh, &facets);+ wval_(Wmaxout)= maxoutside - qh->max_outside;+ wmax_(Wmaxoutside, qh->max_outside);+ qh->max_outside= maxoutside;+ qh_nearcoplanar(qh /*qh.facet_list*/);+ qh->maxoutdone= True;+ trace1((qh, qh->ferr, 1024, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",+ maxoutside, qh->min_vertex, notgood));+} /* check_maxout */+#else /* qh_NOmerge */+void qh_check_maxout(qhT *qh) {+}+#endif++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_output">-</a>++ qh_check_output(qh)+ performs the checks at the end of qhull algorithm+ Maybe called after voronoi output. Will recompute otherwise centrums are Voronoi centers instead+*/+void qh_check_output(qhT *qh) {+ int i;++ if (qh->STOPcone)+ return;+ if (qh->VERIFYoutput | qh->IStracing | qh->CHECKfrequently) {+ qh_checkpolygon(qh, qh->facet_list);+ qh_checkflipped_all(qh, qh->facet_list);+ qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);+ }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {+ qh_checkflipped_all(qh, qh->facet_list);+ qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);+ }+} /* check_output */++++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_point">-</a>++ qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2 )+ check that point is less than maxoutside from facet+*/+void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {+ realT dist;++ /* occurs after statistics reported */+ qh_distplane(qh, point, facet, &dist);+ if (dist > *maxoutside) {+ if (*errfacet1 != facet) {+ *errfacet2= *errfacet1;+ *errfacet1= facet;+ }+ qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",+ qh_pointid(qh, point), facet->id, dist, *maxoutside);+ }+ maximize_(*maxdist, dist);+} /* qh_check_point */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="check_points">-</a>++ qh_check_points(qh)+ checks that all points are inside all facets++ notes:+ if many points and qh_check_maxout not called (i.e., !qh.MERGING),+ calls qh_findbesthorizon (seldom done).+ ignores flipped facets+ maxoutside includes 2 qh.DISTrounds+ one qh.DISTround for the computed distances in qh_check_points+ qh_printafacet and qh_printsummary needs only one qh.DISTround+ the computation for qh.VERIFYdirect does not account for qh.other_points++ design:+ if many points+ use qh_check_bestdist()+ else+ for all facets+ for all points+ check that point is inside facet+*/+void qh_check_points(qhT *qh) {+ facetT *facet, *errfacet1= NULL, *errfacet2= NULL;+ realT total, maxoutside, maxdist= -REALmax;+ pointT *point, **pointp, *pointtemp;+ boolT testouter;++ maxoutside= qh_maxouter(qh);+ maxoutside += qh->DISTround;+ /* one more qh.DISTround for check computation */+ trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",+ maxoutside));+ if (qh->num_good) /* miss counts other_points and !good facets */+ total= (float)qh->num_good * (float)qh->num_points;+ else+ total= (float)qh->num_facets * (float)qh->num_points;+ if (total >= qh_VERIFYdirect && !qh->maxoutdone) {+ if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)+ qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').\n\+Verify may report that a point is outside of a facet.\n");+ qh_check_bestdist(qh);+ }else {+ if (qh_MAXoutside && qh->maxoutdone)+ testouter= True;+ else+ testouter= False;+ if (!qh_QUICKhelp) {+ if (qh->MERGEexact)+ qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx'). Verify may report that a point\n\+is outside of a facet. See qh-optq.htm#Qx\n");+ else if (qh->SKIPcheckmax || qh->NOnearinside)+ qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of\n\+near-inside points ('Q8'). Verify may report that a point is outside\n\+of a facet.\n");+ }+ if (qh->PRINTprecision) {+ if (testouter)+ qh_fprintf(qh, qh->ferr, 8098, "\n\+Output completed. Verifying that all points are below outer planes of\n\+all %sfacets. Will make %2.0f distance computations.\n",+ (qh->ONLYgood ? "good " : ""), total);+ else+ qh_fprintf(qh, qh->ferr, 8099, "\n\+Output completed. Verifying that all points are below %2.2g of\n\+all %sfacets. Will make %2.0f distance computations.\n",+ maxoutside, (qh->ONLYgood ? "good " : ""), total);+ }+ FORALLfacets {+ if (!facet->good && qh->ONLYgood)+ continue;+ if (facet->flipped)+ continue;+ if (!facet->normal) {+ qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);+ continue;+ }+ if (testouter) {+#if qh_MAXoutside+ maxoutside= facet->maxoutside + 2* qh->DISTround;+ /* one DISTround to actual point and another to computed point */+#endif+ }+ FORALLpoints {+ if (point != qh->GOODpointp)+ qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);+ }+ FOREACHpoint_(qh->other_points) {+ if (point != qh->GOODpointp)+ qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);+ }+ }+ if (maxdist > qh->outside_err) {+ qh_fprintf(qh, qh->ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n",+ maxdist, qh->outside_err );+ qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );+ }else if (errfacet1 && qh->outside_err > REALmax/2)+ qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );+ /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */+ trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));+ }+} /* check_points */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkconvex">-</a>++ qh_checkconvex(qh, facetlist, fault )+ check that each ridge in facetlist is convex+ fault = qh_DATAfault if reporting errors+ = qh_ALGORITHMfault otherwise++ returns:+ counts Zconcaveridges and Zcoplanarridges+ errors if concaveridge or if merging an coplanar ridge++ note:+ if not merging,+ tests vertices for neighboring simplicial facets+ else if ZEROcentrum,+ tests vertices for neighboring simplicial facets+ else+ tests centrums of neighboring facets++ design:+ for all facets+ report flipped facets+ if ZEROcentrum and simplicial neighbors+ test vertices for neighboring simplicial facets+ else+ test centrum against all neighbors+*/+void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {+ facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;+ vertexT *vertex;+ realT dist;+ pointT *centrum;+ boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;+ int neighbor_i;++ trace1((qh, qh->ferr, 1026, "qh_checkconvex: check all ridges are convex\n"));+ if (!qh->RERUN) {+ zzval_(Zconcaveridges)= 0;+ zzval_(Zcoplanarridges)= 0;+ }+ FORALLfacet_(facetlist) {+ if (facet->flipped) {+ qh_precision(qh, "flipped facet");+ qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped(interior point is outside)\n",+ facet->id);+ errfacet1= facet;+ waserror= True;+ continue;+ }+ if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial || facet->tricoplanar))+ allsimplicial= False;+ else {+ allsimplicial= True;+ neighbor_i= 0;+ FOREACHneighbor_(facet) {+ vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);+ if (!neighbor->simplicial || neighbor->tricoplanar) {+ allsimplicial= False;+ continue;+ }+ qh_distplane(qh, vertex->point, neighbor, &dist);+ if (dist > -qh->DISTround) {+ if (fault == qh_DATAfault) {+ qh_precision(qh, "coplanar or concave ridge");+ qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);+ qh_errexit(qh, qh_ERRsingular, NULL, NULL);+ }+ if (dist > qh->DISTround) {+ zzinc_(Zconcaveridges);+ qh_precision(qh, "concave ridge");+ qh_fprintf(qh, qh->ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above\n",+ facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);+ errfacet1= facet;+ errfacet2= neighbor;+ waserror= True;+ }else if (qh->ZEROcentrum) {+ if (dist > 0) { /* qh_checkzero checks that dist < - qh->DISTround */+ zzinc_(Zcoplanarridges);+ qh_precision(qh, "coplanar ridge");+ qh_fprintf(qh, qh->ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above\n",+ facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist);+ errfacet1= facet;+ errfacet2= neighbor;+ waserror= True;+ }+ }else {+ zzinc_(Zcoplanarridges);+ qh_precision(qh, "coplanar ridge");+ trace0((qh, qh->ferr, 22, "qhull precision error: f%d may be coplanar to f%d, since p%d(v%d) is within %6.4g during p%d\n",+ facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, qh->furthest_id));+ }+ }+ }+ }+ if (!allsimplicial) {+ if (qh->CENTERtype == qh_AScentrum) {+ if (!facet->center)+ facet->center= qh_getcentrum(qh, facet);+ centrum= facet->center;+ }else {+ if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {+ centrum_warning= True;+ qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test. This may lead to false, precision errors.\n");+ }+ centrum= qh_getcentrum(qh, facet);+ tempcentrum= True;+ }+ FOREACHneighbor_(facet) {+ if (qh->ZEROcentrum && facet->simplicial && neighbor->simplicial)+ continue;+ if (facet->tricoplanar || neighbor->tricoplanar)+ continue;+ zzinc_(Zdistconvex);+ qh_distplane(qh, centrum, neighbor, &dist);+ if (dist > qh->DISTround) {+ zzinc_(Zconcaveridges);+ qh_precision(qh, "concave ridge");+ qh_fprintf(qh, qh->ferr, 6117, "qhull precision error: f%d is concave to f%d. Centrum of f%d is %6.4g above f%d\n",+ facet->id, neighbor->id, facet->id, dist, neighbor->id);+ errfacet1= facet;+ errfacet2= neighbor;+ waserror= True;+ }else if (dist >= 0.0) { /* if arithmetic always rounds the same,+ can test against centrum radius instead */+ zzinc_(Zcoplanarridges);+ qh_precision(qh, "coplanar ridge");+ qh_fprintf(qh, qh->ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d. Centrum of f%d is %6.4g above f%d\n",+ facet->id, neighbor->id, facet->id, dist, neighbor->id);+ errfacet1= facet;+ errfacet2= neighbor;+ waserror= True;+ }+ }+ if (tempcentrum)+ qh_memfree(qh, centrum, qh->normal_size);+ }+ }+ if (waserror && !qh->FORCEoutput)+ qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);+} /* checkconvex */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkfacet">-</a>++ qh_checkfacet(qh, facet, newmerge, waserror )+ checks for consistency errors in facet+ newmerge set if from merge_r.c++ returns:+ sets waserror if any error occurs++ checks:+ vertex ids are inverse sorted+ unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)+ if non-simplicial, at least as many ridges as neighbors+ neighbors are not duplicated+ ridges are not duplicated+ in 3-d, ridges=verticies+ (qh.hull_dim-1) ridge vertices+ neighbors are reciprocated+ ridge neighbors are facet neighbors and a ridge for every neighbor+ simplicial neighbors match facetintersect+ vertex intersection matches vertices of common ridges+ vertex neighbors and facet vertices agree+ all ridges have distinct vertex sets++ notes:+ uses neighbor->seen++ design:+ check sets+ check vertices+ check sizes of neighbors and vertices+ check for qh_MERGEridge and qh_DUPLICATEridge flags+ check neighbor set+ check ridge set+ check ridges, neighbors, and vertices+*/+void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {+ facetT *neighbor, **neighborp, *errother=NULL;+ ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;+ vertexT *vertex, **vertexp;+ unsigned previousid= INT_MAX;+ int numneighbors, numvertices, numridges=0, numRvertices=0;+ boolT waserror= False;+ int skipA, skipB, ridge_i, ridge_n, i;+ setT *intersection;++ if (facet->visible) {+ qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",+ facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ if (!facet->normal) {+ qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",+ facet->id);+ waserror= True;+ }+ qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);+ qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);+ qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);+ qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);+ qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);+ FOREACHvertex_(facet->vertices) {+ if (vertex->deleted) {+ qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);+ qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);+ waserror= True;+ }+ if (vertex->id >= previousid) {+ qh_fprintf(qh, qh->ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);+ waserror= True;+ break;+ }+ previousid= vertex->id;+ }+ numneighbors= qh_setsize(qh, facet->neighbors);+ numvertices= qh_setsize(qh, facet->vertices);+ numridges= qh_setsize(qh, facet->ridges);+ if (facet->simplicial) {+ if (numvertices+numneighbors != 2*qh->hull_dim+ && !facet->degenerate && !facet->redundant) {+ qh_fprintf(qh, qh->ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh->hull_dim\n",+ facet->id, numvertices, numneighbors);+ qh_setprint(qh, qh->ferr, "", facet->neighbors);+ waserror= True;+ }+ }else { /* non-simplicial */+ if (!newmerge+ &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)+ && !facet->degenerate && !facet->redundant) {+ qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",+ facet->id, numvertices, numneighbors);+ waserror= True;+ }+ /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */+ if (numridges < numneighbors+ ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)+ ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {+ if (!facet->degenerate && !facet->redundant) {+ qh_fprintf(qh, qh->ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n",+ facet->id, numridges, numneighbors, numvertices);+ waserror= True;+ }+ }+ }+ FOREACHneighbor_(facet) {+ if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {+ qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ neighbor->seen= True;+ }+ FOREACHneighbor_(facet) {+ if (!qh_setin(neighbor->neighbors, facet)) {+ qh_fprintf(qh, qh->ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",+ facet->id, neighbor->id, neighbor->id, facet->id);+ errother= neighbor;+ waserror= True;+ }+ if (!neighbor->seen) {+ qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",+ facet->id, neighbor->id);+ errother= neighbor;+ waserror= True;+ }+ neighbor->seen= False;+ }+ FOREACHridge_(facet->ridges) {+ qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);+ ridge->seen= False;+ }+ FOREACHridge_(facet->ridges) {+ if (ridge->seen) {+ qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",+ facet->id, ridge->id);+ errridge= ridge;+ waserror= True;+ }+ ridge->seen= True;+ numRvertices= qh_setsize(qh, ridge->vertices);+ if (numRvertices != qh->hull_dim - 1) {+ qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",+ ridge->top->id, ridge->bottom->id, numRvertices);+ errridge= ridge;+ waserror= True;+ }+ neighbor= otherfacet_(ridge, facet);+ neighbor->seen= True;+ if (!qh_setin(facet->neighbors, neighbor)) {+ qh_fprintf(qh, qh->ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",+ facet->id, neighbor->id, ridge->id);+ errridge= ridge;+ waserror= True;+ }+ }+ if (!facet->simplicial) {+ FOREACHneighbor_(facet) {+ if (!neighbor->seen) {+ qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",+ facet->id, neighbor->id);+ errother= neighbor;+ waserror= True;+ }+ intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);+ qh_settemppush(qh, intersection);+ FOREACHvertex_(facet->vertices) {+ vertex->seen= False;+ vertex->seen2= False;+ }+ FOREACHvertex_(intersection)+ vertex->seen= True;+ FOREACHridge_(facet->ridges) {+ if (neighbor != otherfacet_(ridge, facet))+ continue;+ FOREACHvertex_(ridge->vertices) {+ if (!vertex->seen) {+ qh_fprintf(qh, qh->ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",+ vertex->id, ridge->id, facet->id, neighbor->id);+ qh_errexit(qh, qh_ERRqhull, facet, ridge);+ }+ vertex->seen2= True;+ }+ }+ if (!newmerge) {+ FOREACHvertex_(intersection) {+ if (!vertex->seen2) {+ if (qh->IStracing >=3 || !qh->MERGING) {+ qh_fprintf(qh, qh->ferr, 6134, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\+ not in a ridge. This is ok under merging. Last point was p%d\n",+ vertex->id, facet->id, neighbor->id, qh->furthest_id);+ if (!qh->FORCEoutput && !qh->MERGING) {+ qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);+ if (!qh->MERGING)+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ }+ }+ }+ }+ qh_settempfree(qh, &intersection);+ }+ }else { /* simplicial */+ FOREACHneighbor_(facet) {+ if (neighbor->simplicial) {+ skipA= SETindex_(facet->neighbors, neighbor);+ skipB= qh_setindex(neighbor->neighbors, facet);+ if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {+ qh_fprintf(qh, qh->ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",+ facet->id, skipA, neighbor->id, skipB);+ errother= neighbor;+ waserror= True;+ }+ }+ }+ }+ if (qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {+ FOREACHridge_i_(qh, facet->ridges) { /* expensive */+ for (i=ridge_i+1; i < ridge_n; i++) {+ ridge2= SETelemt_(facet->ridges, i, ridgeT);+ if (qh_setequal(ridge->vertices, ridge2->vertices)) {+ qh_fprintf(qh, qh->ferr, 6227, "Qhull internal error (qh_checkfacet): ridges r%d and r%d have the same vertices\n",+ ridge->id, ridge2->id);+ errridge= ridge;+ waserror= True;+ }+ }+ }+ }+ if (waserror) {+ qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);+ *waserrorp= True;+ }+} /* checkfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkflipped_all">-</a>++ qh_checkflipped_all(qh, facetlist )+ checks orientation of facets in list against interior point+*/+void qh_checkflipped_all(qhT *qh, facetT *facetlist) {+ facetT *facet;+ boolT waserror= False;+ realT dist;++ if (facetlist == qh->facet_list)+ zzval_(Zflippedfacets)= 0;+ FORALLfacet_(facetlist) {+ if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {+ qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",+ facet->id, dist);+ if (!qh->FORCEoutput) {+ qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);+ waserror= True;+ }+ }+ }+ if (waserror) {+ qh_fprintf(qh, qh->ferr, 8101, "\n\+A flipped facet occurs when its distance to the interior point is\n\+greater than %2.2g, the maximum roundoff error.\n", -qh->DISTround);+ qh_errexit(qh, qh_ERRprec, NULL, NULL);+ }+} /* checkflipped_all */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkpolygon">-</a>++ qh_checkpolygon(qh, facetlist )+ checks the correctness of the structure++ notes:+ call with either qh.facet_list or qh.newfacet_list+ checks num_facets and num_vertices if qh.facet_list++ design:+ for each facet+ checks facet and outside set+ initializes vertexlist+ for each facet+ checks vertex set+ if checking all facets(qh.facetlist)+ check facet count+ if qh.VERTEXneighbors+ check vertex neighbors and count+ check vertex count+*/+void qh_checkpolygon(qhT *qh, facetT *facetlist) {+ facetT *facet;+ vertexT *vertex, **vertexp, *vertexlist;+ int numfacets= 0, numvertices= 0, numridges= 0;+ int totvneighbors= 0, totvertices= 0;+ boolT waserror= False, nextseen= False, visibleseen= False;++ trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));+ if (facetlist != qh->facet_list || qh->ONLYgood)+ nextseen= True;+ FORALLfacet_(facetlist) {+ if (facet == qh->visible_list)+ visibleseen= True;+ if (!facet->visible) {+ if (!nextseen) {+ if (facet == qh->facet_next)+ nextseen= True;+ else if (qh_setsize(qh, facet->outsideset)) {+ if (!qh->NARROWhull+#if !qh_COMPUTEfurthest+ || facet->furthestdist >= qh->MINoutside+#endif+ ) {+ qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh->facet_next\n",+ facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ }+ }+ numfacets++;+ qh_checkfacet(qh, facet, False, &waserror);+ }+ }+ if (qh->visible_list && !visibleseen && facetlist == qh->facet_list) {+ qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh->visible_list->id);+ qh_printlists(qh);+ qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);+ }+ if (facetlist == qh->facet_list)+ vertexlist= qh->vertex_list;+ else if (facetlist == qh->newfacet_list)+ vertexlist= qh->newvertex_list;+ else+ vertexlist= NULL;+ FORALLvertex_(vertexlist) {+ vertex->seen= False;+ vertex->visitid= 0;+ }+ FORALLfacet_(facetlist) {+ if (facet->visible)+ continue;+ if (facet->simplicial)+ numridges += qh->hull_dim;+ else+ numridges += qh_setsize(qh, facet->ridges);+ FOREACHvertex_(facet->vertices) {+ vertex->visitid++;+ if (!vertex->seen) {+ vertex->seen= True;+ numvertices++;+ if (qh_pointid(qh, vertex->point) == qh_IDunknown) {+ qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",+ vertex->point, vertex->id, qh->first_point);+ waserror= True;+ }+ }+ }+ }+ qh->vertex_visit += (unsigned int)numfacets;+ if (facetlist == qh->facet_list) {+ if (numfacets != qh->num_facets - qh->num_visible) {+ qh_fprintf(qh, qh->ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",+ numfacets, qh->num_facets, qh->num_visible);+ waserror= True;+ }+ qh->vertex_visit++;+ if (qh->VERTEXneighbors) {+ FORALLvertices {+ qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);+ if (vertex->deleted)+ continue;+ totvneighbors += qh_setsize(qh, vertex->neighbors);+ }+ FORALLfacet_(facetlist)+ totvertices += qh_setsize(qh, facet->vertices);+ if (totvneighbors != totvertices) {+ qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent. Totvneighbors %d, totvertices %d\n",+ totvneighbors, totvertices);+ waserror= True;+ }+ }+ if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {+ qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",+ numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));+ waserror= True;+ }+ if (qh->hull_dim == 2 && numvertices != numfacets) {+ qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",+ numvertices, numfacets);+ waserror= True;+ }+ if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {+ qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\+ A vertex appears twice in a edge list. May occur during merging.",+ numvertices, numfacets, numridges/2);+ /* occurs if lots of merging and a vertex ends up twice in an edge list. e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */+ }+ }+ if (waserror)+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+} /* checkpolygon */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkvertex">-</a>++ qh_checkvertex(qh, vertex )+ check vertex for consistency+ checks vertex->neighbors++ notes:+ neighbors checked efficiently in checkpolygon+*/+void qh_checkvertex(qhT *qh, vertexT *vertex) {+ boolT waserror= False;+ facetT *neighbor, **neighborp, *errfacet=NULL;++ if (qh_pointid(qh, vertex->point) == qh_IDunknown) {+ qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);+ waserror= True;+ }+ if (vertex->id >= qh->vertex_id) {+ qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);+ waserror= True;+ }+ if (!waserror && !vertex->deleted) {+ if (qh_setsize(qh, vertex->neighbors)) {+ FOREACHneighbor_(vertex) {+ if (!qh_setin(neighbor->vertices, vertex)) {+ qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);+ errfacet= neighbor;+ waserror= True;+ }+ }+ }+ }+ if (waserror) {+ qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);+ qh_errexit(qh, qh_ERRqhull, errfacet, NULL);+ }+} /* checkvertex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="clearcenters">-</a>++ qh_clearcenters(qh, type )+ clear old data from facet->center++ notes:+ sets new centertype+ nop if CENTERtype is the same+*/+void qh_clearcenters(qhT *qh, qh_CENTER type) {+ facetT *facet;++ if (qh->CENTERtype != type) {+ FORALLfacets {+ if (facet->tricoplanar && !facet->keepcentrum)+ facet->center= NULL; /* center is owned by the ->keepcentrum facet */+ else if (qh->CENTERtype == qh_ASvoronoi){+ if (facet->center) {+ qh_memfree(qh, facet->center, qh->center_size);+ facet->center= NULL;+ }+ }else /* qh->CENTERtype == qh_AScentrum */ {+ if (facet->center) {+ qh_memfree(qh, facet->center, qh->normal_size);+ facet->center= NULL;+ }+ }+ }+ qh->CENTERtype= type;+ }+ trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));+} /* clearcenters */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="createsimplex">-</a>++ qh_createsimplex(qh, vertices )+ creates a simplex from a set of vertices++ returns:+ initializes qh.facet_list to the simplex+ initializes qh.newfacet_list, .facet_tail+ initializes qh.vertex_list, .newvertex_list, .vertex_tail++ design:+ initializes lists+ for each vertex+ create a new facet+ for each new facet+ create its neighbor set+*/+void qh_createsimplex(qhT *qh, setT *vertices) {+ facetT *facet= NULL, *newfacet;+ boolT toporient= True;+ int vertex_i, vertex_n, nth;+ setT *newfacets= qh_settemp(qh, qh->hull_dim+1);+ vertexT *vertex;++ qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);+ qh->num_facets= qh->num_vertices= qh->num_visible= 0;+ qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);+ FOREACHvertex_i_(qh, vertices) {+ newfacet= qh_newfacet(qh);+ newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n,+ vertex_i, 0);+ newfacet->toporient= (unsigned char)toporient;+ qh_appendfacet(qh, newfacet);+ newfacet->newfacet= True;+ qh_appendvertex(qh, vertex);+ qh_setappend(qh, &newfacets, newfacet);+ toporient ^= True;+ }+ FORALLnew_facets {+ nth= 0;+ FORALLfacet_(qh->newfacet_list) {+ if (facet != newfacet)+ SETelem_(newfacet->neighbors, nth++)= facet;+ }+ qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);+ }+ qh_settempfree(qh, &newfacets);+ trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));+} /* createsimplex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="delridge">-</a>++ qh_delridge(qh, ridge )+ deletes ridge from data structures it belongs to+ frees up its memory++ notes:+ in merge_r.c, caller sets vertex->delridge for each vertex+ ridges also freed in qh_freeqhull+*/+void qh_delridge(qhT *qh, ridgeT *ridge) {+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */++ qh_setdel(ridge->top->ridges, ridge);+ qh_setdel(ridge->bottom->ridges, ridge);+ qh_setfree(qh, &(ridge->vertices));+ qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);+} /* delridge */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="delvertex">-</a>++ qh_delvertex(qh, vertex )+ deletes a vertex and frees its memory++ notes:+ assumes vertex->adjacencies have been updated if needed+ unlinks from vertex_list+*/+void qh_delvertex(qhT *qh, vertexT *vertex) {++ if (vertex == qh->tracevertex)+ qh->tracevertex= NULL;+ qh_removevertex(qh, vertex);+ qh_setfree(qh, &vertex->neighbors);+ qh_memfree(qh, vertex, (int)sizeof(vertexT));+} /* delvertex */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="facet3vertex">-</a>++ qh_facet3vertex(qh, )+ return temporary set of 3-d vertices in qh_ORIENTclock order++ design:+ if simplicial facet+ build set from facet->vertices with facet->toporient+ else+ for each ridge in order+ build set from ridge's vertices+*/+setT *qh_facet3vertex(qhT *qh, facetT *facet) {+ ridgeT *ridge, *firstridge;+ vertexT *vertex;+ int cntvertices, cntprojected=0;+ setT *vertices;++ cntvertices= qh_setsize(qh, facet->vertices);+ vertices= qh_settemp(qh, cntvertices);+ if (facet->simplicial) {+ if (cntvertices != 3) {+ qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",+ cntvertices, facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ qh_setappend(qh, &vertices, SETfirst_(facet->vertices));+ if (facet->toporient ^ qh_ORIENTclock)+ qh_setappend(qh, &vertices, SETsecond_(facet->vertices));+ else+ qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));+ qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));+ }else {+ ridge= firstridge= SETfirstt_(facet->ridges, ridgeT); /* no infinite */+ while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {+ qh_setappend(qh, &vertices, vertex);+ if (++cntprojected > cntvertices || ridge == firstridge)+ break;+ }+ if (!ridge || cntprojected != cntvertices) {+ qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up. got at least %d\n",+ facet->id, cntprojected);+ qh_errexit(qh, qh_ERRqhull, facet, ridge);+ }+ }+ return vertices;+} /* facet3vertex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="findbestfacet">-</a>++ qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )+ find facet that is furthest below a point++ for Delaunay triangulations,+ Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed+ Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.++ returns:+ if bestoutside is set (e.g., qh_ALL)+ returns best facet that is not upperdelaunay+ if Delaunay and inside, point is outside circumsphere of bestfacet+ else+ returns first facet below point+ if point is inside, returns nearest, !upperdelaunay facet+ distance to facet+ isoutside set if outside of facet++ notes:+ For tricoplanar facets, this finds one of the tricoplanar facets closest+ to the point. For Delaunay triangulations, the point may be inside a+ different tricoplanar facet. See <a href="../html/qh-code.htm#findfacet">locate a facet with qh_findbestfacet()</a>++ If inside, qh_findbestfacet performs an exhaustive search+ this may be too conservative. Sometimes it is clearly required.++ qh_findbestfacet is not used by qhull.+ uses qh.visit_id and qh.coplanarset++ see:+ <a href="geom_r.c#findbest">qh_findbest</a>+*/+facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,+ realT *bestdist, boolT *isoutside) {+ facetT *bestfacet= NULL;+ int numpart, totpart= 0;++ bestfacet= qh_findbest(qh, point, qh->facet_list,+ bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,+ bestdist, isoutside, &totpart);+ if (*bestdist < -qh->DISTround) {+ bestfacet= qh_findfacet_all(qh, point, bestdist, isoutside, &numpart);+ totpart += numpart;+ if ((isoutside && *isoutside && bestoutside)+ || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {+ bestfacet= qh_findbest(qh, point, bestfacet,+ bestoutside, False, bestoutside,+ bestdist, isoutside, &totpart);+ totpart += numpart;+ }+ }+ trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",+ bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));+ return bestfacet;+} /* findbestfacet */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="findbestlower">-</a>++ qh_findbestlower(qh, facet, point, bestdist, numpart )+ returns best non-upper, non-flipped neighbor of facet for point+ if needed, searches vertex neighbors++ returns:+ returns bestdist and updates numpart++ notes:+ if Delaunay and inside, point is outside of circumsphere of bestfacet+ called by qh_findbest() for points above an upperdelaunay facet++*/+facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {+ facetT *neighbor, **neighborp, *bestfacet= NULL;+ realT bestdist= -REALmax/2 /* avoid underflow */;+ realT dist;+ vertexT *vertex;+ boolT isoutside= False; /* not used */++ zinc_(Zbestlower);+ FOREACHneighbor_(upperfacet) {+ if (neighbor->upperdelaunay || neighbor->flipped)+ continue;+ (*numpart)++;+ qh_distplane(qh, point, neighbor, &dist);+ if (dist > bestdist) {+ bestfacet= neighbor;+ bestdist= dist;+ }+ }+ if (!bestfacet) {+ zinc_(Zbestlowerv);+ /* rarely called, numpart does not count nearvertex computations */+ vertex= qh_nearvertex(qh, upperfacet, point, &dist);+ qh_vertexneighbors(qh);+ FOREACHneighbor_(vertex) {+ if (neighbor->upperdelaunay || neighbor->flipped)+ continue;+ (*numpart)++;+ qh_distplane(qh, point, neighbor, &dist);+ if (dist > bestdist) {+ bestfacet= neighbor;+ bestdist= dist;+ }+ }+ }+ if (!bestfacet) {+ zinc_(Zbestlowerall); /* invoked once per point in outsideset */+ zmax_(Zbestloweralln, qh->num_facets);+ /* [dec'15] Previously reported as QH6228 */+ trace3((qh, qh->ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay. Search all facets\n",+ upperfacet->id));+ /* rarely called */+ bestfacet= qh_findfacet_all(qh, point, &bestdist, &isoutside, numpart);+ }+ *bestdistp= bestdist;+ trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",+ bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));+ return bestfacet;+} /* findbestlower */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="findfacet_all">-</a>++ qh_findfacet_all(qh, point, bestdist, isoutside, numpart )+ exhaustive search for facet below a point++ for Delaunay triangulations,+ Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed+ Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.++ returns:+ returns first facet below point+ if point is inside,+ returns nearest facet+ distance to facet+ isoutside if point is outside of the hull+ number of distance tests++ notes:+ primarily for library users, rarely used by Qhull+*/+facetT *qh_findfacet_all(qhT *qh, pointT *point, realT *bestdist, boolT *isoutside,+ int *numpart) {+ facetT *bestfacet= NULL, *facet;+ realT dist;+ int totpart= 0;++ *bestdist= -REALmax;+ *isoutside= False;+ FORALLfacets {+ if (facet->flipped || !facet->normal)+ continue;+ totpart++;+ qh_distplane(qh, point, facet, &dist);+ if (dist > *bestdist) {+ *bestdist= dist;+ bestfacet= facet;+ if (dist > qh->MINoutside) {+ *isoutside= True;+ break;+ }+ }+ }+ *numpart= totpart;+ trace3((qh, qh->ferr, 3016, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",+ getid_(bestfacet), *bestdist, *isoutside, totpart));+ return bestfacet;+} /* findfacet_all */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="findgood">-</a>++ qh_findgood(qh, facetlist, goodhorizon )+ identify good facets for qh.PRINTgood+ if qh.GOODvertex>0+ facet includes point as vertex+ if !match, returns goodhorizon+ inactive if qh.MERGING+ if qh.GOODpoint+ facet is visible or coplanar (>0) or not visible (<0)+ if qh.GOODthreshold+ facet->normal matches threshold+ if !goodhorizon and !match,+ selects facet with closest angle+ sets GOODclosest++ returns:+ number of new, good facets found+ determines facet->good+ may update qh.GOODclosest++ notes:+ qh_findgood_all further reduces the good region++ design:+ count good facets+ mark good facets for qh.GOODpoint+ mark good facets for qh.GOODthreshold+ if necessary+ update qh.GOODclosest+*/+int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {+ facetT *facet, *bestfacet= NULL;+ realT angle, bestangle= REALmax, dist;+ int numgood=0;++ FORALLfacet_(facetlist) {+ if (facet->good)+ numgood++;+ }+ if (qh->GOODvertex>0 && !qh->MERGING) {+ FORALLfacet_(facetlist) {+ if (!qh_isvertex(qh->GOODvertexp, facet->vertices)) {+ facet->good= False;+ numgood--;+ }+ }+ }+ if (qh->GOODpoint && numgood) {+ FORALLfacet_(facetlist) {+ if (facet->good && facet->normal) {+ zinc_(Zdistgood);+ qh_distplane(qh, qh->GOODpointp, facet, &dist);+ if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {+ facet->good= False;+ numgood--;+ }+ }+ }+ }+ if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {+ FORALLfacet_(facetlist) {+ if (facet->good && facet->normal) {+ if (!qh_inthresholds(qh, facet->normal, &angle)) {+ facet->good= False;+ numgood--;+ if (angle < bestangle) {+ bestangle= angle;+ bestfacet= facet;+ }+ }+ }+ }+ if (!numgood && (!goodhorizon || qh->GOODclosest)) {+ if (qh->GOODclosest) {+ if (qh->GOODclosest->visible)+ qh->GOODclosest= NULL;+ else {+ qh_inthresholds(qh, qh->GOODclosest->normal, &angle);+ if (angle < bestangle)+ bestfacet= qh->GOODclosest;+ }+ }+ if (bestfacet && bestfacet != qh->GOODclosest) {+ if (qh->GOODclosest)+ qh->GOODclosest->good= False;+ qh->GOODclosest= bestfacet;+ bestfacet->good= True;+ numgood++;+ trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",+ bestfacet->id, bestangle));+ return numgood;+ }+ }else if (qh->GOODclosest) { /* numgood > 0 */+ qh->GOODclosest->good= False;+ qh->GOODclosest= NULL;+ }+ }+ zadd_(Zgoodfacet, numgood);+ trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon\n",+ numgood, goodhorizon));+ if (!numgood && qh->GOODvertex>0 && !qh->MERGING)+ return goodhorizon;+ return numgood;+} /* findgood */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="findgood_all">-</a>++ qh_findgood_all(qh, facetlist )+ apply other constraints for good facets (used by qh.PRINTgood)+ if qh.GOODvertex+ facet includes (>0) or doesn't include (<0) point as vertex+ if last good facet and ONLYgood, prints warning and continues+ if qh.SPLITthresholds+ facet->normal matches threshold, or if none, the closest one+ calls qh_findgood+ nop if good not used++ returns:+ clears facet->good if not good+ sets qh.num_good++ notes:+ this is like qh_findgood but more restrictive++ design:+ uses qh_findgood to mark good facets+ marks facets for qh.GOODvertex+ marks facets for qh.SPLITthreholds+*/+void qh_findgood_all(qhT *qh, facetT *facetlist) {+ facetT *facet, *bestfacet=NULL;+ realT angle, bestangle= REALmax;+ int numgood=0, startgood;++ if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint+ && !qh->SPLITthresholds)+ return;+ if (!qh->ONLYgood)+ qh_findgood(qh, qh->facet_list, 0);+ FORALLfacet_(facetlist) {+ if (facet->good)+ numgood++;+ }+ if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {+ FORALLfacet_(facetlist) {+ if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh->GOODvertexp, facet->vertices))) {+ if (!--numgood) {+ if (qh->ONLYgood) {+ qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d. Ignored.\n",+ qh_pointid(qh, qh->GOODvertexp), facet->id);+ return;+ }else if (qh->GOODvertex > 0)+ qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",+ qh->GOODvertex-1, qh->GOODvertex-1);+ else+ qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",+ -qh->GOODvertex - 1, -qh->GOODvertex - 1);+ }+ facet->good= False;+ }+ }+ }+ startgood= numgood;+ if (qh->SPLITthresholds) {+ FORALLfacet_(facetlist) {+ if (facet->good) {+ if (!qh_inthresholds(qh, facet->normal, &angle)) {+ facet->good= False;+ numgood--;+ if (angle < bestangle) {+ bestangle= angle;+ bestfacet= facet;+ }+ }+ }+ }+ if (!numgood && bestfacet) {+ bestfacet->good= True;+ numgood++;+ trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to thresholds\n",+ bestfacet->id, bestangle));+ return;+ }+ }+ qh->num_good= numgood;+ trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",+ numgood, startgood));+} /* findgood_all */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="furthestnext">-</a>++ qh_furthestnext()+ set qh.facet_next to facet with furthest of all furthest points+ searches all facets on qh.facet_list++ notes:+ this may help avoid precision problems+*/+void qh_furthestnext(qhT *qh /* qh->facet_list */) {+ facetT *facet, *bestfacet= NULL;+ realT dist, bestdist= -REALmax;++ FORALLfacets {+ if (facet->outsideset) {+#if qh_COMPUTEfurthest+ pointT *furthest;+ furthest= (pointT*)qh_setlast(facet->outsideset);+ zinc_(Zcomputefurthest);+ qh_distplane(qh, furthest, facet, &dist);+#else+ dist= facet->furthestdist;+#endif+ if (dist > bestdist) {+ bestfacet= facet;+ bestdist= dist;+ }+ }+ }+ if (bestfacet) {+ qh_removefacet(qh, bestfacet);+ qh_prependfacet(qh, bestfacet, &qh->facet_next);+ trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",+ bestfacet->id, bestdist));+ }+} /* furthestnext */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="furthestout">-</a>++ qh_furthestout(qh, facet )+ make furthest outside point the last point of outsideset++ returns:+ updates facet->outsideset+ clears facet->notfurthest+ sets facet->furthestdist++ design:+ determine best point of outsideset+ make it the last point of outsideset+*/+void qh_furthestout(qhT *qh, facetT *facet) {+ pointT *point, **pointp, *bestpoint= NULL;+ realT dist, bestdist= -REALmax;++ FOREACHpoint_(facet->outsideset) {+ qh_distplane(qh, point, facet, &dist);+ zinc_(Zcomputefurthest);+ if (dist > bestdist) {+ bestpoint= point;+ bestdist= dist;+ }+ }+ if (bestpoint) {+ qh_setdel(facet->outsideset, point);+ qh_setappend(qh, &facet->outsideset, point);+#if !qh_COMPUTEfurthest+ facet->furthestdist= bestdist;+#endif+ }+ facet->notfurthest= False;+ trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",+ qh_pointid(qh, point), facet->id));+} /* furthestout */+++/*-<a href="qh-qhull_r.htm#TOC"+ >-------------------------------</a><a name="infiniteloop">-</a>++ qh_infiniteloop(qh, facet )+ report infinite loop error due to facet+*/+void qh_infiniteloop(qhT *qh, facetT *facet) {++ qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+} /* qh_infiniteloop */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="initbuild">-</a>++ qh_initbuild()+ initialize hull and outside sets with point array+ qh.FIRSTpoint/qh.NUMpoints is point array+ if qh.GOODpoint+ adds qh.GOODpoint to initial hull++ returns:+ qh_facetlist with initial hull+ points partioned into outside sets, coplanar sets, or inside+ initializes qh.GOODpointp, qh.GOODvertexp,++ design:+ initialize global variables used during qh_buildhull+ determine precision constants and points with max/min coordinate values+ if qh.SCALElast, scale last coordinate(for 'd')+ build initial simplex+ partition input points into facets of initial simplex+ set up lists+ if qh.ONLYgood+ check consistency+ add qh.GOODvertex if defined+*/+void qh_initbuild(qhT *qh) {+ setT *maxpoints, *vertices;+ facetT *facet;+ int i, numpart;+ realT dist;+ boolT isoutside;++ qh->furthest_id= qh_IDunknown;+ qh->lastreport= 0;+ qh->facet_id= qh->vertex_id= qh->ridge_id= 0;+ qh->visit_id= qh->vertex_visit= 0;+ qh->maxoutdone= False;++ if (qh->GOODpoint > 0)+ qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);+ else if (qh->GOODpoint < 0)+ qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);+ if (qh->GOODvertex > 0)+ qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);+ else if (qh->GOODvertex < 0)+ qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);+ if ((qh->GOODpoint+ && (qh->GOODpointp < qh->first_point /* also catches !GOODpointp */+ || qh->GOODpointp > qh_point(qh, qh->num_points-1)))+ || (qh->GOODvertex+ && (qh->GOODvertexp < qh->first_point /* also catches !GOODvertexp */+ || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {+ qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",+ qh->num_points-1);+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);+ if (qh->SCALElast)+ qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim,+ qh->MINlastcoord, qh->MAXlastcoord, qh->MAXwidth);+ qh_detroundoff(qh);+ if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2+ && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {+ for (i=qh_PRINTEND; i--; ) {+ if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0+ && !qh->GOODthreshold && !qh->SPLITthresholds)+ break; /* in this case, don't set upper_threshold */+ }+ if (i < 0) {+ if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */+ qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;+ qh->GOODthreshold= True;+ }else {+ qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;+ if (!qh->GOODthreshold)+ qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */+ /* qh_initqhull_globals errors if Qg without Pdk/etc. */+ }+ }+ }+ vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);+ qh_initialhull(qh, vertices); /* initial qh->facet_list */+ qh_partitionall(qh, vertices, qh->first_point, qh->num_points);+ if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {+ if (qh->TRACElevel || qh->IStracing)+ qh_fprintf(qh, qh->ferr, 8103, "\nTrace level %d for %s | %s\n",+ qh->IStracing ? qh->IStracing : qh->TRACElevel, qh->rbox_command, qh->qhull_command);+ qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);+ }+ qh_resetlists(qh, False, qh_RESETvisible /*qh.visible_list newvertex_list newfacet_list */);+ qh->facet_next= qh->facet_list;+ qh_furthestnext(qh /* qh->facet_list */);+ if (qh->PREmerge) {+ qh->cos_max= qh->premerge_cos;+ qh->centrum_radius= qh->premerge_centrum;+ }+ if (qh->ONLYgood) {+ if (qh->GOODvertex > 0 && qh->MERGING) {+ qh_fprintf(qh, qh->ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (!(qh->GOODthreshold || qh->GOODpoint+ || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {+ qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a\n\+good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (qh->GOODvertex > 0 && !qh->MERGING /* matches qh_partitionall */+ && !qh_isvertex(qh->GOODvertexp, vertices)) {+ facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,+ &dist, !qh_ALL, &isoutside, &numpart);+ zadd_(Zdistgood, numpart);+ if (!isoutside) {+ qh_fprintf(qh, qh->ferr, 6153, "qhull input error: point for QV%d is inside initial simplex. It can not be made a vertex.\n",+ qh_pointid(qh, qh->GOODvertexp));+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {+ qh_settempfree(qh, &vertices);+ qh_settempfree(qh, &maxpoints);+ return;+ }+ }+ qh_findgood(qh, qh->facet_list, 0);+ }+ qh_settempfree(qh, &vertices);+ qh_settempfree(qh, &maxpoints);+ trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));+} /* initbuild */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="initialhull">-</a>++ qh_initialhull(qh, vertices )+ constructs the initial hull as a DIM3 simplex of vertices++ design:+ creates a simplex (initializes lists)+ determines orientation of simplex+ sets hyperplanes for facets+ doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)+ checks for flipped facets and qh.NARROWhull+ checks the result+*/+void qh_initialhull(qhT *qh, setT *vertices) {+ facetT *facet, *firstfacet, *neighbor, **neighborp;+ realT dist, angle, minangle= REALmax;+#ifndef qh_NOtrace+ int k;+#endif++ qh_createsimplex(qh, vertices); /* qh->facet_list */+ qh_resetlists(qh, False, qh_RESETvisible);+ qh->facet_next= qh->facet_list; /* advance facet when processed */+ qh->interior_point= qh_getcenter(qh, vertices);+ firstfacet= qh->facet_list;+ qh_setfacetplane(qh, firstfacet);+ zinc_(Znumvisibility); /* needs to be in printsummary */+ qh_distplane(qh, qh->interior_point, firstfacet, &dist);+ if (dist > 0) {+ FORALLfacets+ facet->toporient ^= (unsigned char)True;+ }+ FORALLfacets+ qh_setfacetplane(qh, facet);+ FORALLfacets {+ if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {/* due to axis-parallel facet */+ trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect. Correct all facets\n"));+ facet->flipped= False;+ FORALLfacets {+ facet->toporient ^= (unsigned char)True;+ qh_orientoutside(qh, facet);+ }+ break;+ }+ }+ FORALLfacets {+ if (!qh_checkflipped(qh, facet, NULL, !qh_ALL)) { /* can happen with 'R0.1' */+ if (qh->DELAUNAY && ! qh->ATinfinity) {+ if (qh->UPPERdelaunay)+ qh_fprintf(qh, qh->ferr, 6240, "Qhull precision error: Initial simplex is cocircular or cospherical. Option 'Qs' searches all points. Can not compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");+ else+ qh_fprintf(qh, qh->ferr, 6239, "Qhull precision error: Initial simplex is cocircular or cospherical. Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points. Option 'Qz' adds a point \"at infinity\". Use option 'Qs' to search all points for the initial simplex.\n");+ qh_errexit(qh, qh_ERRinput, NULL, NULL);+ }+ qh_precision(qh, "initial simplex is flat");+ qh_fprintf(qh, qh->ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",+ facet->id);+ qh_errexit(qh, qh_ERRsingular, NULL, NULL); /* calls qh_printhelp_singular */+ }+ FOREACHneighbor_(facet) {+ angle= qh_getangle(qh, facet->normal, neighbor->normal);+ minimize_( minangle, angle);+ }+ }+ if (minangle < qh_MAXnarrow && !qh->NOnarrow) {+ realT diff= 1.0 + minangle;++ qh->NARROWhull= True;+ qh_option(qh, "_narrow-hull", NULL, &diff);+ if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)+ qh_printhelp_narrowhull(qh, qh->ferr, minangle);+ }+ zzval_(Zprocessed)= qh->hull_dim+1;+ qh_checkpolygon(qh, qh->facet_list);+ qh_checkconvex(qh, qh->facet_list, qh_DATAfault);+#ifndef qh_NOtrace+ if (qh->IStracing >= 1) {+ qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed, interior point:");+ for (k=0; k < qh->hull_dim; k++)+ qh_fprintf(qh, qh->ferr, 8106, " %6.4g", qh->interior_point[k]);+ qh_fprintf(qh, qh->ferr, 8107, "\n");+ }+#endif+} /* initialhull */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="initialvertices">-</a>++ qh_initialvertices(qh, dim, maxpoints, points, numpoints )+ determines a non-singular set of initial vertices+ maxpoints may include duplicate points++ returns:+ temporary set of dim+1 vertices in descending order by vertex id+ if qh.RANDOMoutside && !qh.ALLpoints+ picks random points+ if dim >= qh_INITIALmax,+ uses min/max x and max points with non-zero determinants++ notes:+ unless qh.ALLpoints,+ uses maxpoints as long as determinate is non-zero+*/+setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {+ pointT *point, **pointp;+ setT *vertices, *simplex, *tested;+ realT randr;+ int idx, point_i, point_n, k;+ boolT nearzero= False;++ vertices= qh_settemp(qh, dim + 1);+ simplex= qh_settemp(qh, dim+1);+ if (qh->ALLpoints)+ qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);+ else if (qh->RANDOMoutside) {+ while (qh_setsize(qh, simplex) != dim+1) {+ randr= qh_RANDOMint;+ randr= randr/(qh_RANDOMmax+1);+ idx= (int)floor(qh->num_points * randr);+ while (qh_setin(simplex, qh_point(qh, idx))) {+ idx++; /* in case qh_RANDOMint always returns the same value */+ idx= idx < qh->num_points ? idx : 0;+ }+ qh_setappend(qh, &simplex, qh_point(qh, idx));+ }+ }else if (qh->hull_dim >= qh_INITIALmax) {+ tested= qh_settemp(qh, dim+1);+ qh_setappend(qh, &simplex, SETfirst_(maxpoints)); /* max and min X coord */+ qh_setappend(qh, &simplex, SETsecond_(maxpoints));+ qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);+ k= qh_setsize(qh, simplex);+ FOREACHpoint_i_(qh, maxpoints) {+ if (point_i & 0x1) { /* first pick up max. coord. points */+ if (!qh_setin(simplex, point) && !qh_setin(tested, point)){+ qh_detsimplex(qh, point, simplex, k, &nearzero);+ if (nearzero)+ qh_setappend(qh, &tested, point);+ else {+ qh_setappend(qh, &simplex, point);+ if (++k == dim) /* use search for last point */+ break;+ }+ }+ }+ }+ while (k != dim && (point= (pointT*)qh_setdellast(maxpoints))) {+ if (!qh_setin(simplex, point) && !qh_setin(tested, point)){+ qh_detsimplex(qh, point, simplex, k, &nearzero);+ if (nearzero)+ qh_setappend(qh, &tested, point);+ else {+ qh_setappend(qh, &simplex, point);+ k++;+ }+ }+ }+ idx= 0;+ while (k != dim && (point= qh_point(qh, idx++))) {+ if (!qh_setin(simplex, point) && !qh_setin(tested, point)){+ qh_detsimplex(qh, point, simplex, k, &nearzero);+ if (!nearzero){+ qh_setappend(qh, &simplex, point);+ k++;+ }+ }+ }+ qh_settempfree(qh, &tested);+ qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);+ }else+ qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);+ FOREACHpoint_(simplex)+ qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */+ qh_settempfree(qh, &simplex);+ return vertices;+} /* initialvertices */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="isvertex">-</a>++ qh_isvertex( point, vertices )+ returns vertex if point is in vertex set, else returns NULL++ notes:+ for qh.GOODvertex+*/+vertexT *qh_isvertex(pointT *point, setT *vertices) {+ vertexT *vertex, **vertexp;++ FOREACHvertex_(vertices) {+ if (vertex->point == point)+ return vertex;+ }+ return NULL;+} /* isvertex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="makenewfacets">-</a>++ qh_makenewfacets(qh, point )+ make new facets from point and qh.visible_list++ returns:+ qh.newfacet_list= list of new facets with hyperplanes and ->newfacet+ qh.newvertex_list= list of vertices in new facets with ->newlist set++ if (qh.ONLYgood)+ newfacets reference horizon facets, but not vice versa+ ridges reference non-simplicial horizon ridges, but not vice versa+ does not change existing facets+ else+ sets qh.NEWfacets+ new facets attached to horizon facets and ridges+ for visible facets,+ visible->r.replace is corresponding new facet++ see also:+ qh_makenewplanes() -- make hyperplanes for facets+ qh_attachnewfacets() -- attachnewfacets if not done here(qh->ONLYgood)+ qh_matchnewfacets() -- match up neighbors+ qh_updatevertices() -- update vertex neighbors and delvertices+ qh_deletevisible() -- delete visible facets+ qh_checkpolygon() --check the result+ qh_triangulate() -- triangulate a non-simplicial facet++ design:+ for each visible facet+ make new facets to its horizon facets+ update its f.replace+ clear its neighbor set+*/+vertexT *qh_makenewfacets(qhT *qh, pointT *point /*visible_list*/) {+ facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;+ vertexT *apex;+ int numnew=0;++ qh->newfacet_list= qh->facet_tail;+ qh->newvertex_list= qh->vertex_tail;+ apex= qh_newvertex(qh, point);+ qh_appendvertex(qh, apex);+ qh->visit_id++;+ if (!qh->ONLYgood)+ qh->NEWfacets= True;+ FORALLvisible_facets {+ FOREACHneighbor_(visible)+ neighbor->seen= False;+ if (visible->ridges) {+ visible->visitid= qh->visit_id;+ newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);+ }+ if (visible->simplicial)+ newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);+ if (!qh->ONLYgood) {+ if (newfacet2) /* newfacet is null if all ridges defined */+ newfacet= newfacet2;+ if (newfacet)+ visible->f.replace= newfacet;+ else+ zinc_(Zinsidevisible);+ SETfirst_(visible->neighbors)= NULL;+ }+ }+ trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",+ numnew, qh_pointid(qh, point)));+ if (qh->IStracing >= 4)+ qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);+ return apex;+} /* makenewfacets */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="matchduplicates">-</a>++ qh_matchduplicates(qh, atfacet, atskip, hashsize, hashcount )+ match duplicate ridges in qh.hash_table for atfacet/atskip+ duplicates marked with ->dupridge and qh_DUPLICATEridge++ returns:+ picks match with worst merge (min distance apart)+ updates hashcount++ see also:+ qh_matchneighbor++ notes:++ design:+ compute hash value for atfacet and atskip+ repeat twice -- once to make best matches, once to match the rest+ for each possible facet in qh.hash_table+ if it is a matching facet and pass 2+ make match+ unless tricoplanar, mark match for merging (qh_MERGEridge)+ [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]+ if it is a matching facet and pass 1+ test if this is a better match+ if pass 1,+ make best match (it will not be merged)+*/+#ifndef qh_NOmerge+void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {+ boolT same, ismatch;+ int hash, scan;+ facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;+ int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;+ realT maxdist= -REALmax, mindist, dist2, low, high;++ hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,+ SETelem_(atfacet->vertices, atskip));+ trace2((qh, qh->ferr, 2046, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",+ atfacet->id, atskip, hash, *hashcount));+ for (makematch= 0; makematch < 2; makematch++) {+ qh->visit_id++;+ for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {+ zinc_(Zhashlookup);+ nextfacet= NULL;+ newfacet->visitid= qh->visit_id;+ for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));+ scan= (++scan >= hashsize ? 0 : scan)) {+ if (!facet->dupridge || facet->visitid == qh->visit_id)+ continue;+ zinc_(Zhashtests);+ if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {+ ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));+ if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {+ if (!makematch) {+ qh_fprintf(qh, qh->ferr, 6155, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",+ facet->id, skip, newfacet->id, newskip, hash);+ qh_errexit2(qh, qh_ERRqhull, facet, newfacet);+ }+ }else if (ismatch && makematch) {+ if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {+ SETelem_(facet->neighbors, skip)= newfacet;+ if (newfacet->tricoplanar)+ SETelem_(newfacet->neighbors, newskip)= facet;+ else+ SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;+ *hashcount -= 2; /* removed two unmatched facets */+ trace4((qh, qh->ferr, 4059, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",+ facet->id, skip, newfacet->id, newskip));+ }+ }else if (ismatch) {+ mindist= qh_getdistance(qh, facet, newfacet, &low, &high);+ dist2= qh_getdistance(qh, newfacet, facet, &low, &high);+ minimize_(mindist, dist2);+ if (mindist > maxdist) {+ maxdist= mindist;+ maxmatch= facet;+ maxskip= skip;+ maxmatch2= newfacet;+ maxskip2= newskip;+ }+ trace3((qh, qh->ferr, 3018, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",+ facet->id, skip, newfacet->id, newskip, mindist,+ maxmatch->id, maxmatch2->id));+ }else { /* !ismatch */+ nextfacet= facet;+ nextskip= skip;+ }+ }+ if (makematch && !facet+ && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {+ qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",+ newfacet->id, newskip, hash);+ qh_errexit(qh, qh_ERRqhull, newfacet, NULL);+ }+ }+ } /* end of for each new facet at hash */+ if (!makematch) {+ if (!maxmatch) {+ qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",+ atfacet->id, atskip, hash);+ qh_errexit(qh, qh_ERRqhull, atfacet, NULL);+ }+ SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=0 by QH6157 */+ SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;+ *hashcount -= 2; /* removed two unmatched facets */+ zzinc_(Zmultiridge);+ trace0((qh, qh->ferr, 25, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",+ maxmatch->id, maxskip, maxmatch2->id, maxskip2));+ qh_precision(qh, "ridge with multiple neighbors");+ if (qh->IStracing >= 4)+ qh_errprint(qh, "DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);+ }+ }+} /* matchduplicates */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="nearcoplanar">-</a>++ qh_nearcoplanar()+ for all facets, remove near-inside points from facet->coplanarset</li>+ coplanar points defined by innerplane from qh_outerinner()++ returns:+ if qh->KEEPcoplanar && !qh->KEEPinside+ facet->coplanarset only contains coplanar points+ if qh.JOGGLEmax+ drops inner plane by another qh.JOGGLEmax diagonal since a+ vertex could shift out while a coplanar point shifts in++ notes:+ used for qh.PREmerge and qh.JOGGLEmax+ must agree with computation of qh.NEARcoplanar in qh_detroundoff(qh)+ design:+ if not keeping coplanar or inside points+ free all coplanar sets+ else if not keeping both coplanar and inside points+ remove !coplanar or !inside points from coplanar sets+*/+void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {+ facetT *facet;+ pointT *point, **pointp;+ int numpart;+ realT dist, innerplane;++ if (!qh->KEEPcoplanar && !qh->KEEPinside) {+ FORALLfacets {+ if (facet->coplanarset)+ qh_setfree(qh, &facet->coplanarset);+ }+ }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {+ qh_outerinner(qh, NULL, NULL, &innerplane);+ if (qh->JOGGLEmax < REALmax/2)+ innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);+ numpart= 0;+ FORALLfacets {+ if (facet->coplanarset) {+ FOREACHpoint_(facet->coplanarset) {+ numpart++;+ qh_distplane(qh, point, facet, &dist);+ if (dist < innerplane) {+ if (!qh->KEEPinside)+ SETref_(point)= NULL;+ }else if (!qh->KEEPcoplanar)+ SETref_(point)= NULL;+ }+ qh_setcompact(qh, facet->coplanarset);+ }+ }+ zzadd_(Zcheckpart, numpart);+ }+} /* nearcoplanar */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="nearvertex">-</a>++ qh_nearvertex(qh, facet, point, bestdist )+ return nearest vertex in facet to point++ returns:+ vertex and its distance++ notes:+ if qh.DELAUNAY+ distance is measured in the input set+ searches neighboring tricoplanar facets (requires vertexneighbors)+ Slow implementation. Recomputes vertex set for each point.+ The vertex set could be stored in the qh.keepcentrum facet.+*/+vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {+ realT bestdist= REALmax, dist;+ vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;+ coordT *center;+ facetT *neighbor, **neighborp;+ setT *vertices;+ int dim= qh->hull_dim;++ if (qh->DELAUNAY)+ dim--;+ if (facet->tricoplanar) {+ if (!qh->VERTEXneighbors || !facet->center) {+ qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ vertices= qh_settemp(qh, qh->TEMPsize);+ apex= SETfirstt_(facet->vertices, vertexT);+ center= facet->center;+ FOREACHneighbor_(apex) {+ if (neighbor->center == center) {+ FOREACHvertex_(neighbor->vertices)+ qh_setappend(qh, &vertices, vertex);+ }+ }+ }else+ vertices= facet->vertices;+ FOREACHvertex_(vertices) {+ dist= qh_pointdist(vertex->point, point, -dim);+ if (dist < bestdist) {+ bestdist= dist;+ bestvertex= vertex;+ }+ }+ if (facet->tricoplanar)+ qh_settempfree(qh, &vertices);+ *bestdistp= sqrt(bestdist);+ if (!bestvertex) {+ qh_fprintf(qh, qh->ferr, 6261, "qhull internal error (qh_nearvertex): did not find bestvertex for f%d p%d\n", facet->id, qh_pointid(qh, point));+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",+ bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point))); /* bestvertex!=0 by QH2161 */+ return bestvertex;+} /* nearvertex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="newhashtable">-</a>++ qh_newhashtable(qh, newsize )+ returns size of qh.hash_table of at least newsize slots++ notes:+ assumes qh.hash_table is NULL+ qh_HASHfactor determines the number of extra slots+ size is not divisible by 2, 3, or 5+*/+int qh_newhashtable(qhT *qh, int newsize) {+ int size;++ size= ((newsize+1)*qh_HASHfactor) | 0x1; /* odd number */+ while (True) {+ if (newsize<0 || size<0) {+ qh_fprintf(qh, qh->qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d). Did int overflow due to high-D?\n", newsize, size); /* WARN64 */+ qh_errexit(qh, qhmem_ERRmem, NULL, NULL);+ }+ if ((size%3) && (size%5))+ break;+ size += 2;+ /* loop terminates because there is an infinite number of primes */+ }+ qh->hash_table= qh_setnew(qh, size);+ qh_setzero(qh, qh->hash_table, 0, size);+ return size;+} /* newhashtable */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="newvertex">-</a>++ qh_newvertex(qh, point )+ returns a new vertex for point+*/+vertexT *qh_newvertex(qhT *qh, pointT *point) {+ vertexT *vertex;++ zinc_(Ztotvertices);+ vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));+ memset((char *) vertex, (size_t)0, sizeof(vertexT));+ if (qh->vertex_id == UINT_MAX) {+ qh_memfree(qh, vertex, (int)sizeof(vertexT));+ qh_fprintf(qh, qh->ferr, 6159, "qhull error: more than 2^32 vertices. vertexT.id field overflows. Vertices would not be sorted correctly.\n");+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ if (qh->vertex_id == qh->tracevertex_id)+ qh->tracevertex= vertex;+ vertex->id= qh->vertex_id++;+ vertex->point= point;+ trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),+ vertex->id));+ return(vertex);+} /* newvertex */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="nextridge3d">-</a>++ qh_nextridge3d( atridge, facet, vertex )+ return next ridge and vertex for a 3d facet+ returns NULL on error+ [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.++ notes:+ in qh_ORIENTclock order+ this is a O(n^2) implementation to trace all ridges+ be sure to stop on any 2nd visit+ same as QhullRidge::nextRidge3d+ does not use qhT or qh_errexit [QhullFacet.cpp]++ design:+ for each ridge+ exit if it is the ridge after atridge+*/+ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {+ vertexT *atvertex, *vertex, *othervertex;+ ridgeT *ridge, **ridgep;++ if ((atridge->top == facet) ^ qh_ORIENTclock)+ atvertex= SETsecondt_(atridge->vertices, vertexT);+ else+ atvertex= SETfirstt_(atridge->vertices, vertexT);+ FOREACHridge_(facet->ridges) {+ if (ridge == atridge)+ continue;+ if ((ridge->top == facet) ^ qh_ORIENTclock) {+ othervertex= SETsecondt_(ridge->vertices, vertexT);+ vertex= SETfirstt_(ridge->vertices, vertexT);+ }else {+ vertex= SETsecondt_(ridge->vertices, vertexT);+ othervertex= SETfirstt_(ridge->vertices, vertexT);+ }+ if (vertex == atvertex) {+ if (vertexp)+ *vertexp= othervertex;+ return ridge;+ }+ }+ return NULL;+} /* nextridge3d */+#else /* qh_NOmerge */+void qh_matchduplicates(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {+}+ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {++ return NULL;+}+#endif /* qh_NOmerge */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="outcoplanar">-</a>++ qh_outcoplanar()+ move points from all facets' outsidesets to their coplanarsets++ notes:+ for post-processing under qh.NARROWhull++ design:+ for each facet+ for each outside point for facet+ partition point into coplanar set+*/+void qh_outcoplanar(qhT *qh /* facet_list */) {+ pointT *point, **pointp;+ facetT *facet;+ realT dist;++ trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));+ FORALLfacets {+ FOREACHpoint_(facet->outsideset) {+ qh->num_outside--;+ if (qh->KEEPcoplanar || qh->KEEPnearinside) {+ qh_distplane(qh, point, facet, &dist);+ zinc_(Zpartition);+ qh_partitioncoplanar(qh, point, facet, &dist);+ }+ }+ qh_setfree(qh, &facet->outsideset);+ }+} /* outcoplanar */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="point">-</a>++ qh_point(qh, id )+ return point for a point id, or NULL if unknown++ alternative code:+ return((pointT *)((unsigned long)qh.first_point+ + (unsigned long)((id)*qh.normal_size)));+*/+pointT *qh_point(qhT *qh, int id) {++ if (id < 0)+ return NULL;+ if (id < qh->num_points)+ return qh->first_point + id * qh->hull_dim;+ id -= qh->num_points;+ if (id < qh_setsize(qh, qh->other_points))+ return SETelemt_(qh->other_points, id, pointT);+ return NULL;+} /* point */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="point_add">-</a>++ qh_point_add(qh, set, point, elem )+ stores elem at set[point.id]++ returns:+ access function for qh_pointfacet and qh_pointvertex++ notes:+ checks point.id+*/+void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {+ int id, size;++ SETreturnsize_(set, size);+ if ((id= qh_pointid(qh, point)) < 0)+ qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",+ point, id);+ else if (id >= size) {+ qh_fprintf(qh, qh->ferr, 6160, "qhull internal errror(point_add): point p%d is out of bounds(%d)\n",+ id, size);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }else+ SETelem_(set, id)= elem;+} /* point_add */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="pointfacet">-</a>++ qh_pointfacet()+ return temporary set of facet for each point+ the set is indexed by point id++ notes:+ vertices assigned to one of the facets+ coplanarset assigned to the facet+ outside set assigned to the facet+ NULL if no facet for point (inside)+ includes qh.GOODpointp++ access:+ FOREACHfacet_i_(qh, facets) { ... }+ SETelem_(facets, i)++ design:+ for each facet+ add each vertex+ add each coplanar point+ add each outside point+*/+setT *qh_pointfacet(qhT *qh /*qh.facet_list*/) {+ int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);+ setT *facets;+ facetT *facet;+ vertexT *vertex, **vertexp;+ pointT *point, **pointp;++ facets= qh_settemp(qh, numpoints);+ qh_setzero(qh, facets, 0, numpoints);+ qh->vertex_visit++;+ FORALLfacets {+ FOREACHvertex_(facet->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ vertex->visitid= qh->vertex_visit;+ qh_point_add(qh, facets, vertex->point, facet);+ }+ }+ FOREACHpoint_(facet->coplanarset)+ qh_point_add(qh, facets, point, facet);+ FOREACHpoint_(facet->outsideset)+ qh_point_add(qh, facets, point, facet);+ }+ return facets;+} /* pointfacet */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="pointvertex">-</a>++ qh_pointvertex(qh, )+ return temporary set of vertices indexed by point id+ entry is NULL if no vertex for a point+ this will include qh.GOODpointp++ access:+ FOREACHvertex_i_(qh, vertices) { ... }+ SETelem_(vertices, i)+*/+setT *qh_pointvertex(qhT *qh /*qh.facet_list*/) {+ int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);+ setT *vertices;+ vertexT *vertex;++ vertices= qh_settemp(qh, numpoints);+ qh_setzero(qh, vertices, 0, numpoints);+ FORALLvertices+ qh_point_add(qh, vertices, vertex->point, vertex);+ return vertices;+} /* pointvertex */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="prependfacet">-</a>++ qh_prependfacet(qh, facet, facetlist )+ prepend facet to the start of a facetlist++ returns:+ increments qh.numfacets+ updates facetlist, qh.facet_list, facet_next++ notes:+ be careful of prepending since it can lose a pointer.+ e.g., can lose _next by deleting and then prepending before _next+*/+void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {+ facetT *prevfacet, *list;+++ trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",+ facet->id, getid_(*facetlist)));+ if (!*facetlist)+ (*facetlist)= qh->facet_tail;+ list= *facetlist;+ prevfacet= list->previous;+ facet->previous= prevfacet;+ if (prevfacet)+ prevfacet->next= facet;+ list->previous= facet;+ facet->next= *facetlist;+ if (qh->facet_list == list) /* this may change *facetlist */+ qh->facet_list= facet;+ if (qh->facet_next == list)+ qh->facet_next= facet;+ *facetlist= facet;+ qh->num_facets++;+} /* prependfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="printhashtable">-</a>++ qh_printhashtable(qh, fp )+ print hash table to fp++ notes:+ not in I/O to avoid bringing io_r.c in++ design:+ for each hash entry+ if defined+ if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)+ print entry and neighbors+*/+void qh_printhashtable(qhT *qh, FILE *fp) {+ facetT *facet, *neighbor;+ int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;+ vertexT *vertex, **vertexp;++ FOREACHfacet_i_(qh, qh->hash_table) {+ if (facet) {+ FOREACHneighbor_i_(qh, facet) {+ if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)+ break;+ }+ if (neighbor_i == neighbor_n)+ continue;+ qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);+ FOREACHvertex_(facet->vertices)+ qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);+ qh_fprintf(qh, fp, 9285, "\n neighbors:");+ FOREACHneighbor_i_(qh, facet) {+ if (neighbor == qh_MERGEridge)+ id= -3;+ else if (neighbor == qh_DUPLICATEridge)+ id= -2;+ else+ id= getid_(neighbor);+ qh_fprintf(qh, fp, 9286, " %d", id);+ }+ qh_fprintf(qh, fp, 9287, "\n");+ }+ }+} /* printhashtable */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="printlists">-</a>++ qh_printlists(qh, fp )+ print out facet and vertex list for debugging (without 'f/v' tags)+*/+void qh_printlists(qhT *qh) {+ facetT *facet;+ vertexT *vertex;+ int count= 0;++ qh_fprintf(qh, qh->ferr, 8108, "qh_printlists: facets:");+ FORALLfacets {+ if (++count % 100 == 0)+ qh_fprintf(qh, qh->ferr, 8109, "\n ");+ qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);+ }+ qh_fprintf(qh, qh->ferr, 8111, "\n new facets %d visible facets %d next facet for qh_addpoint %d\n vertices(new %d):",+ getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_next),+ getid_(qh->newvertex_list));+ count = 0;+ FORALLvertices {+ if (++count % 100 == 0)+ qh_fprintf(qh, qh->ferr, 8112, "\n ");+ qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);+ }+ qh_fprintf(qh, qh->ferr, 8114, "\n");+} /* printlists */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="resetlists">-</a>++ qh_resetlists(qh, stats, qh_RESETvisible )+ reset newvertex_list, newfacet_list, visible_list+ if stats,+ maintains statistics++ returns:+ visible_list is empty if qh_deletevisible was called+*/+void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /*qh.newvertex_list newfacet_list visible_list*/) {+ vertexT *vertex;+ facetT *newfacet, *visible;+ int totnew=0, totver=0;++ if (stats) {+ FORALLvertex_(qh->newvertex_list)+ totver++;+ FORALLnew_facets+ totnew++;+ zadd_(Zvisvertextot, totver);+ zmax_(Zvisvertexmax, totver);+ zadd_(Znewfacettot, totnew);+ zmax_(Znewfacetmax, totnew);+ }+ FORALLvertex_(qh->newvertex_list)+ vertex->newlist= False;+ qh->newvertex_list= NULL;+ FORALLnew_facets+ newfacet->newfacet= False;+ qh->newfacet_list= NULL;+ if (resetVisible) {+ FORALLvisible_facets {+ visible->f.replace= NULL;+ visible->visible= False;+ }+ qh->num_visible= 0;+ }+ qh->visible_list= NULL; /* may still have visible facets via qh_triangulate */+ qh->NEWfacets= False;+} /* resetlists */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="setvoronoi_all">-</a>++ qh_setvoronoi_all(qh)+ compute Voronoi centers for all facets+ includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')++ returns:+ facet->center is the Voronoi center++ notes:+ this is unused/untested code+ please email bradb@shore.net if this works ok for you++ use:+ FORALLvertices {...} to locate the vertex for a point.+ FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.+*/+void qh_setvoronoi_all(qhT *qh) {+ facetT *facet;++ qh_clearcenters(qh, qh_ASvoronoi);+ qh_vertexneighbors(qh);++ FORALLfacets {+ if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {+ if (!facet->center)+ facet->center= qh_facetcenter(qh, facet->vertices);+ }+ }+} /* setvoronoi_all */++#ifndef qh_NOmerge++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="triangulate">-</a>++ qh_triangulate()+ triangulate non-simplicial facets on qh.facet_list,+ if qh->VORONOI, sets Voronoi centers of non-simplicial facets+ nop if hasTriangulation++ returns:+ all facets simplicial+ each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.++ notes:+ call after qh_check_output since may switch to Voronoi centers+ Output may overwrite ->f.triowner with ->f.area+*/+void qh_triangulate(qhT *qh /*qh.facet_list*/) {+ facetT *facet, *nextfacet, *owner;+ int onlygood= qh->ONLYgood;+ facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;+ facetT *orig_neighbor= NULL, *otherfacet;+ vertexT *new_vertex_list= NULL;+ mergeT *merge;+ mergeType mergetype;+ int neighbor_i, neighbor_n;++ if (qh->hasTriangulation)+ return;+ trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));+ if (qh->hull_dim == 2)+ return;+ if (qh->VORONOI) { /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */+ qh_clearcenters(qh, qh_ASvoronoi);+ qh_vertexneighbors(qh);+ }+ qh->ONLYgood= False; /* for makenew_nonsimplicial */+ qh->visit_id++;+ qh->NEWfacets= True;+ qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);+ qh->newvertex_list= qh->vertex_tail;+ for (facet= qh->facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */+ nextfacet= facet->next;+ if (facet->visible || facet->simplicial)+ continue;+ /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */+ if (!new_facet_list)+ new_facet_list= facet; /* will be moved to end */+ qh_triangulate_facet(qh, facet, &new_vertex_list);+ }+ trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));+ for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */+ nextfacet= facet->next;+ if (facet->visible)+ continue;+ if (facet->ridges) {+ if (qh_setsize(qh, facet->ridges) > 0) {+ qh_fprintf(qh, qh->ferr, 6161, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);+ qh_errexit(qh, qh_ERRqhull, facet, NULL);+ }+ qh_setfree(qh, &facet->ridges);+ }+ if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {+ zinc_(Ztrinull);+ qh_triangulate_null(qh, facet);+ }+ }+ trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh, qh->degen_mergeset)));+ qh->visible_list= qh->facet_tail;+ while ((merge= (mergeT*)qh_setdellast(qh->degen_mergeset))) {+ facet1= merge->facet1;+ facet2= merge->facet2;+ mergetype= merge->type;+ qh_memfree(qh, merge, (int)sizeof(mergeT));+ if (mergetype == MRGmirror) {+ zinc_(Ztrimirror);+ qh_triangulate_mirror(qh, facet1, facet2);+ }+ }+ qh_settempfree(qh, &qh->degen_mergeset);+ trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));+ qh->newvertex_list= new_vertex_list; /* all vertices of new facets */+ qh->visible_list= NULL;+ qh_updatevertices(qh /*qh.newvertex_list, empty newfacet_list and visible_list*/);+ qh_resetlists(qh, False, !qh_RESETvisible /*qh.newvertex_list, empty newfacet_list and visible_list*/);++ trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));+ trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));+ FORALLfacet_(new_facet_list) {+ if (facet->tricoplanar && !facet->visible) {+ FOREACHneighbor_i_(qh, facet) {+ if (neighbor_i == 0) { /* first iteration */+ if (neighbor->tricoplanar)+ orig_neighbor= neighbor->f.triowner;+ else+ orig_neighbor= neighbor;+ }else {+ if (neighbor->tricoplanar)+ otherfacet= neighbor->f.triowner;+ else+ otherfacet= neighbor;+ if (orig_neighbor == otherfacet) {+ zinc_(Ztridegen);+ facet->degenerate= True;+ break;+ }+ }+ }+ }+ }++ trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));+ owner= NULL;+ visible= NULL;+ for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */+ nextfacet= facet->next;+ if (facet->visible) {+ if (facet->tricoplanar) { /* a null or mirrored facet */+ qh_delfacet(qh, facet);+ qh->num_visible--;+ }else { /* a non-simplicial facet followed by its tricoplanars */+ if (visible && !owner) {+ /* RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */+ trace2((qh, qh->ferr, 2053, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",+ visible->id));+ qh_delfacet(qh, visible);+ qh->num_visible--;+ }+ visible= facet;+ owner= NULL;+ }+ }else if (facet->tricoplanar) {+ if (facet->f.triowner != visible || visible==NULL) {+ qh_fprintf(qh, qh->ferr, 6162, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));+ qh_errexit2(qh, qh_ERRqhull, facet, visible);+ }+ if (owner)+ facet->f.triowner= owner;+ else if (!facet->degenerate) {+ owner= facet;+ nextfacet= visible->next; /* rescan tricoplanar facets with owner, visible!=0 by QH6162 */+ facet->keepcentrum= True; /* one facet owns ->normal, etc. */+ facet->coplanarset= visible->coplanarset;+ facet->outsideset= visible->outsideset;+ visible->coplanarset= NULL;+ visible->outsideset= NULL;+ if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */+ visible->center= NULL;+ visible->normal= NULL;+ }+ qh_delfacet(qh, visible);+ qh->num_visible--;+ }+ }+ }+ if (visible && !owner) {+ trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",+ visible->id));+ qh_delfacet(qh, visible);+ qh->num_visible--;+ }+ qh->NEWfacets= False;+ qh->ONLYgood= onlygood; /* restore value */+ if (qh->CHECKfrequently)+ qh_checkpolygon(qh, qh->facet_list);+ qh->hasTriangulation= True;+} /* triangulate */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="triangulate_facet">-</a>++ qh_triangulate_facet(qh, facetA, &firstVertex )+ triangulate a non-simplicial facet+ if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center+ returns:+ qh.newfacet_list == simplicial facets+ facet->tricoplanar set and ->keepcentrum false+ facet->degenerate set if duplicated apex+ facet->f.trivisible set to facetA+ facet->center copied from facetA (created if qh_ASvoronoi)+ qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied+ facet->normal,offset,maxoutside copied from facetA++ notes:+ only called by qh_triangulate+ qh_makenew_nonsimplicial uses neighbor->seen for the same+ if qh.TRInormals, newfacet->normal will need qh_free+ if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free+ keepcentrum is also set on Zwidefacet in qh_mergefacet+ freed by qh_clearcenters++ see also:+ qh_addpoint() -- add a point+ qh_makenewfacets() -- construct a cone of facets for a new vertex++ design:+ if qh_ASvoronoi,+ compute Voronoi center (facet->center)+ select first vertex (highest ID to preserve ID ordering of ->vertices)+ triangulate from vertex to ridges+ copy facet->center, normal, offset+ update vertex neighbors+*/+void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {+ facetT *newfacet;+ facetT *neighbor, **neighborp;+ vertexT *apex;+ int numnew=0;++ trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));++ if (qh->IStracing >= 4)+ qh_printfacet(qh, qh->ferr, facetA);+ FOREACHneighbor_(facetA) {+ neighbor->seen= False;+ neighbor->coplanar= False;+ }+ if (qh->CENTERtype == qh_ASvoronoi && !facetA->center /* matches upperdelaunay in qh_setfacetplane() */+ && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {+ facetA->center= qh_facetcenter(qh, facetA->vertices);+ }+ qh_willdelete(qh, facetA, NULL);+ qh->newfacet_list= qh->facet_tail;+ facetA->visitid= qh->visit_id;+ apex= SETfirstt_(facetA->vertices, vertexT);+ qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);+ SETfirst_(facetA->neighbors)= NULL;+ FORALLnew_facets {+ newfacet->tricoplanar= True;+ newfacet->f.trivisible= facetA;+ newfacet->degenerate= False;+ newfacet->upperdelaunay= facetA->upperdelaunay;+ newfacet->good= facetA->good;+ if (qh->TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */+ newfacet->keepcentrum= True;+ if(facetA->normal){+ newfacet->normal= qh_memalloc(qh, qh->normal_size);+ memcpy((char *)newfacet->normal, facetA->normal, qh->normal_size);+ }+ if (qh->CENTERtype == qh_AScentrum)+ newfacet->center= qh_getcentrum(qh, newfacet);+ else if (qh->CENTERtype == qh_ASvoronoi && facetA->center){+ newfacet->center= qh_memalloc(qh, qh->center_size);+ memcpy((char *)newfacet->center, facetA->center, qh->center_size);+ }+ }else {+ newfacet->keepcentrum= False;+ /* one facet will have keepcentrum=True at end of qh_triangulate */+ newfacet->normal= facetA->normal;+ newfacet->center= facetA->center;+ }+ newfacet->offset= facetA->offset;+#if qh_MAXoutside+ newfacet->maxoutside= facetA->maxoutside;+#endif+ }+ qh_matchnewfacets(qh /*qh.newfacet_list*/);+ zinc_(Ztricoplanar);+ zadd_(Ztricoplanartot, numnew);+ zmax_(Ztricoplanarmax, numnew);+ qh->visible_list= NULL;+ if (!(*first_vertex))+ (*first_vertex)= qh->newvertex_list;+ qh->newvertex_list= NULL;+ qh_updatevertices(qh /*qh.newfacet_list, qh.empty visible_list and qh.newvertex_list*/);+ qh_resetlists(qh, False, !qh_RESETvisible /*qh.newfacet_list, qh.empty visible_list and qh.newvertex_list*/);+} /* triangulate_facet */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="triangulate_link">-</a>++ qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)+ relink facetA to facetB via oldfacets+ returns:+ adds mirror facets to qh->degen_mergeset (4-d and up only)+ design:+ if they are already neighbors, the opposing neighbors become MRGmirror facets+*/+void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {+ int errmirror= False;++ trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n",+ oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));+ if (qh_setin(facetA->neighbors, facetB)) {+ if (!qh_setin(facetB->neighbors, facetA))+ errmirror= True;+ else+ qh_appendmergeset(qh, facetA, facetB, MRGmirror, NULL);+ }else if (qh_setin(facetB->neighbors, facetA))+ errmirror= True;+ if (errmirror) {+ qh_fprintf(qh, qh->ferr, 6163, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",+ facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);+ qh_errexit2(qh, qh_ERRqhull, facetA, facetB);+ }+ qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);+ qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);+} /* triangulate_link */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="triangulate_mirror">-</a>++ qh_triangulate_mirror(qh, facetA, facetB)+ delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror+ a mirrored facet shares the same vertices of a logical ridge+ design:+ since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet+ if they are already neighbors, the opposing neighbors become MRGmirror facets+*/+void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {+ facetT *neighbor, *neighborB;+ int neighbor_i, neighbor_n;++ trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n",+ facetA->id, facetB->id));+ FOREACHneighbor_i_(qh, facetA) {+ neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);+ if (neighbor == neighborB)+ continue; /* occurs twice */+ qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);+ }+ qh_willdelete(qh, facetA, NULL);+ qh_willdelete(qh, facetB, NULL);+} /* triangulate_mirror */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="triangulate_null">-</a>++ qh_triangulate_null(qh, facetA)+ remove null facetA from qh_triangulate_facet()+ a null facet has vertex #1 (apex) == vertex #2+ returns:+ adds facetA to ->visible for deletion after qh_updatevertices+ qh->degen_mergeset contains mirror facets (4-d and up only)+ design:+ since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet+ if they are already neighbors, the opposing neighbors become MRGmirror facets+*/+void qh_triangulate_null(qhT *qh, facetT *facetA) {+ facetT *neighbor, *otherfacet;++ trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));+ neighbor= SETfirstt_(facetA->neighbors, facetT);+ otherfacet= SETsecondt_(facetA->neighbors, facetT);+ qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);+ qh_willdelete(qh, facetA, NULL);+} /* triangulate_null */++#else /* qh_NOmerge */+void qh_triangulate(qhT *qh) {+}+#endif /* qh_NOmerge */++ /*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="vertexintersect">-</a>++ qh_vertexintersect(qh, vertexsetA, vertexsetB )+ intersects two vertex sets (inverse id ordered)+ vertexsetA is a temporary set at the top of qh->qhmem.tempstack++ returns:+ replaces vertexsetA with the intersection++ notes:+ could overwrite vertexsetA if currently too slow+*/+void qh_vertexintersect(qhT *qh, setT **vertexsetA,setT *vertexsetB) {+ setT *intersection;++ intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);+ qh_settempfree(qh, vertexsetA);+ *vertexsetA= intersection;+ qh_settemppush(qh, intersection);+} /* vertexintersect */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="vertexintersect_new">-</a>++ qh_vertexintersect_new(qh, )+ intersects two vertex sets (inverse id ordered)++ returns:+ a new set+*/+setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA,setT *vertexsetB) {+ setT *intersection= qh_setnew(qh, qh->hull_dim - 1);+ vertexT **vertexA= SETaddr_(vertexsetA, vertexT);+ vertexT **vertexB= SETaddr_(vertexsetB, vertexT);++ while (*vertexA && *vertexB) {+ if (*vertexA == *vertexB) {+ qh_setappend(qh, &intersection, *vertexA);+ vertexA++; vertexB++;+ }else {+ if ((*vertexA)->id > (*vertexB)->id)+ vertexA++;+ else+ vertexB++;+ }+ }+ return intersection;+} /* vertexintersect_new */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="vertexneighbors">-</a>++ qh_vertexneighbors(qh)+ for each vertex in qh.facet_list,+ determine its neighboring facets++ returns:+ sets qh.VERTEXneighbors+ nop if qh.VERTEXneighbors already set+ qh_addpoint() will maintain them++ notes:+ assumes all vertex->neighbors are NULL++ design:+ for each facet+ for each vertex+ append facet to vertex->neighbors+*/+void qh_vertexneighbors(qhT *qh /*qh.facet_list*/) {+ facetT *facet;+ vertexT *vertex, **vertexp;++ if (qh->VERTEXneighbors)+ return;+ trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));+ qh->vertex_visit++;+ FORALLfacets {+ if (facet->visible)+ continue;+ FOREACHvertex_(facet->vertices) {+ if (vertex->visitid != qh->vertex_visit) {+ vertex->visitid= qh->vertex_visit;+ vertex->neighbors= qh_setnew(qh, qh->hull_dim);+ }+ qh_setappend(qh, &vertex->neighbors, facet);+ }+ }+ qh->VERTEXneighbors= True;+} /* vertexneighbors */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="vertexsubset">-</a>++ qh_vertexsubset( vertexsetA, vertexsetB )+ returns True if vertexsetA is a subset of vertexsetB+ assumes vertexsets are sorted++ note:+ empty set is a subset of any other set+*/+boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {+ vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);+ vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);++ while (True) {+ if (!*vertexA)+ return True;+ if (!*vertexB)+ return False;+ if ((*vertexA)->id > (*vertexB)->id)+ return False;+ if (*vertexA == *vertexB)+ vertexA++;+ vertexB++;+ }+ return False; /* avoid warnings */+} /* vertexsubset */
+ Cdir/poly_r.c view
@@ -0,0 +1,1205 @@+/*<html><pre> -<a href="qh-poly_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ poly_r.c+ implements polygons and simplices++ see qh-poly_r.htm, poly_r.h and libqhull_r.h++ infrequent code is in poly2_r.c+ (all but top 50 and their callers 12/3/95)++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/poly_r.c#3 $$Change: 2064 $+ $DateTime: 2016/01/18 12:36:08 $$Author: bbarber $+*/++#include "qhull_ra.h"++/*======== functions in alphabetical order ==========*/++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="appendfacet">-</a>++ qh_appendfacet(qh, facet )+ appends facet to end of qh.facet_list,++ returns:+ updates qh.newfacet_list, facet_next, facet_list+ increments qh.numfacets++ notes:+ assumes qh.facet_list/facet_tail is defined (createsimplex)++ see:+ qh_removefacet()++*/+void qh_appendfacet(qhT *qh, facetT *facet) {+ facetT *tail= qh->facet_tail;++ if (tail == qh->newfacet_list)+ qh->newfacet_list= facet;+ if (tail == qh->facet_next)+ qh->facet_next= facet;+ facet->previous= tail->previous;+ facet->next= tail;+ if (tail->previous)+ tail->previous->next= facet;+ else+ qh->facet_list= facet;+ tail->previous= facet;+ qh->num_facets++;+ trace4((qh, qh->ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id));+} /* appendfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="appendvertex">-</a>++ qh_appendvertex(qh, vertex )+ appends vertex to end of qh.vertex_list,++ returns:+ sets vertex->newlist+ updates qh.vertex_list, newvertex_list+ increments qh.num_vertices++ notes:+ assumes qh.vertex_list/vertex_tail is defined (createsimplex)++*/+void qh_appendvertex(qhT *qh, vertexT *vertex) {+ vertexT *tail= qh->vertex_tail;++ if (tail == qh->newvertex_list)+ qh->newvertex_list= vertex;+ vertex->newlist= True;+ vertex->previous= tail->previous;+ vertex->next= tail;+ if (tail->previous)+ tail->previous->next= vertex;+ else+ qh->vertex_list= vertex;+ tail->previous= vertex;+ qh->num_vertices++;+ trace4((qh, qh->ferr, 4045, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));+} /* appendvertex */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="attachnewfacets">-</a>++ qh_attachnewfacets(qh, )+ attach horizon facets to new facets in qh.newfacet_list+ newfacets have neighbor and ridge links to horizon but not vice versa+ only needed for qh.ONLYgood++ returns:+ set qh.NEWfacets+ horizon facets linked to new facets+ ridges changed from visible facets to new facets+ simplicial ridges deleted+ qh.visible_list, no ridges valid+ facet->f.replace is a newfacet (if any)++ design:+ delete interior ridges and neighbor sets by+ for each visible, non-simplicial facet+ for each ridge+ if last visit or if neighbor is simplicial+ if horizon neighbor+ delete ridge for horizon's ridge set+ delete ridge+ erase neighbor set+ attach horizon facets and new facets by+ for all new facets+ if corresponding horizon facet is simplicial+ locate corresponding visible facet {may be more than one}+ link visible facet to new facet+ replace visible facet with new facet in horizon+ else it's non-simplicial+ for all visible neighbors of the horizon facet+ link visible neighbor to new facet+ delete visible neighbor from horizon facet+ append new facet to horizon's neighbors+ the first ridge of the new facet is the horizon ridge+ link the new facet into the horizon ridge+*/+void qh_attachnewfacets(qhT *qh /* qh.visible_list, newfacet_list */) {+ facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;+ ridgeT *ridge, **ridgep;++ qh->NEWfacets= True;+ trace3((qh, qh->ferr, 3012, "qh_attachnewfacets: delete interior ridges\n"));+ qh->visit_id++;+ FORALLvisible_facets {+ visible->visitid= qh->visit_id;+ if (visible->ridges) {+ FOREACHridge_(visible->ridges) {+ neighbor= otherfacet_(ridge, visible);+ if (neighbor->visitid == qh->visit_id+ || (!neighbor->visible && neighbor->simplicial)) {+ if (!neighbor->visible) /* delete ridge for simplicial horizon */+ qh_setdel(neighbor->ridges, ridge);+ qh_setfree(qh, &(ridge->vertices)); /* delete on 2nd visit */+ qh_memfree(qh, ridge, (int)sizeof(ridgeT));+ }+ }+ SETfirst_(visible->ridges)= NULL;+ }+ SETfirst_(visible->neighbors)= NULL;+ }+ trace1((qh, qh->ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n"));+ FORALLnew_facets {+ horizon= SETfirstt_(newfacet->neighbors, facetT);+ if (horizon->simplicial) {+ visible= NULL;+ FOREACHneighbor_(horizon) { /* may have more than one horizon ridge */+ if (neighbor->visible) {+ if (visible) {+ if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices,+ SETindex_(horizon->neighbors, neighbor))) {+ visible= neighbor;+ break;+ }+ }else+ visible= neighbor;+ }+ }+ if (visible) {+ visible->f.replace= newfacet;+ qh_setreplace(qh, horizon->neighbors, visible, newfacet);+ }else {+ qh_fprintf(qh, qh->ferr, 6102, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",+ horizon->id, newfacet->id);+ qh_errexit2(qh, qh_ERRqhull, horizon, newfacet);+ }+ }else { /* non-simplicial, with a ridge for newfacet */+ FOREACHneighbor_(horizon) { /* may hold for many new facets */+ if (neighbor->visible) {+ neighbor->f.replace= newfacet;+ qh_setdelnth(qh, horizon->neighbors,+ SETindex_(horizon->neighbors, neighbor));+ neighborp--; /* repeat */+ }+ }+ qh_setappend(qh, &horizon->neighbors, newfacet);+ ridge= SETfirstt_(newfacet->ridges, ridgeT);+ if (ridge->top == horizon)+ ridge->bottom= newfacet;+ else+ ridge->top= newfacet;+ }+ } /* newfacets */+ if (qh->PRINTstatistics) {+ FORALLvisible_facets {+ if (!visible->f.replace)+ zinc_(Zinsidevisible);+ }+ }+} /* attachnewfacets */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="checkflipped">-</a>++ qh_checkflipped(qh, facet, dist, allerror )+ checks facet orientation to interior point++ if allerror set,+ tests against qh.DISTround+ else+ tests against 0 since tested against DISTround before++ returns:+ False if it flipped orientation (sets facet->flipped)+ distance if non-NULL+*/+boolT qh_checkflipped(qhT *qh, facetT *facet, realT *distp, boolT allerror) {+ realT dist;++ if (facet->flipped && !distp)+ return False;+ zzinc_(Zdistcheck);+ qh_distplane(qh, qh->interior_point, facet, &dist);+ if (distp)+ *distp= dist;+ if ((allerror && dist > -qh->DISTround)|| (!allerror && dist >= 0.0)) {+ facet->flipped= True;+ zzinc_(Zflippedfacets);+ trace0((qh, qh->ferr, 19, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",+ facet->id, dist, qh->furthest_id));+ qh_precision(qh, "flipped facet");+ return False;+ }+ return True;+} /* checkflipped */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="delfacet">-</a>++ qh_delfacet(qh, facet )+ removes facet from facet_list and frees up its memory++ notes:+ assumes vertices and ridges already freed+*/+void qh_delfacet(qhT *qh, facetT *facet) {+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */++ trace4((qh, qh->ferr, 4046, "qh_delfacet: delete f%d\n", facet->id));+ if (facet == qh->tracefacet)+ qh->tracefacet= NULL;+ if (facet == qh->GOODclosest)+ qh->GOODclosest= NULL;+ qh_removefacet(qh, facet);+ if (!facet->tricoplanar || facet->keepcentrum) {+ qh_memfree_(qh, facet->normal, qh->normal_size, freelistp);+ if (qh->CENTERtype == qh_ASvoronoi) { /* braces for macro calls */+ qh_memfree_(qh, facet->center, qh->center_size, freelistp);+ }else /* AScentrum */ {+ qh_memfree_(qh, facet->center, qh->normal_size, freelistp);+ }+ }+ qh_setfree(qh, &(facet->neighbors));+ if (facet->ridges)+ qh_setfree(qh, &(facet->ridges));+ qh_setfree(qh, &(facet->vertices));+ if (facet->outsideset)+ qh_setfree(qh, &(facet->outsideset));+ if (facet->coplanarset)+ qh_setfree(qh, &(facet->coplanarset));+ qh_memfree_(qh, facet, (int)sizeof(facetT), freelistp);+} /* delfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="deletevisible">-</a>++ qh_deletevisible()+ delete visible facets and vertices++ returns:+ deletes each facet and removes from facetlist+ at exit, qh.visible_list empty (== qh.newfacet_list)++ notes:+ ridges already deleted+ horizon facets do not reference facets on qh.visible_list+ new facets in qh.newfacet_list+ uses qh.visit_id;+*/+void qh_deletevisible(qhT *qh /*qh.visible_list*/) {+ facetT *visible, *nextfacet;+ vertexT *vertex, **vertexp;+ int numvisible= 0, numdel= qh_setsize(qh, qh->del_vertices);++ trace1((qh, qh->ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n",+ qh->num_visible, numdel));+ for (visible= qh->visible_list; visible && visible->visible;+ visible= nextfacet) { /* deleting current */+ nextfacet= visible->next;+ numvisible++;+ qh_delfacet(qh, visible);+ }+ if (numvisible != qh->num_visible) {+ qh_fprintf(qh, qh->ferr, 6103, "qhull internal error (qh_deletevisible): qh->num_visible %d is not number of visible facets %d\n",+ qh->num_visible, numvisible);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+ qh->num_visible= 0;+ zadd_(Zvisfacettot, numvisible);+ zmax_(Zvisfacetmax, numvisible);+ zzadd_(Zdelvertextot, numdel);+ zmax_(Zdelvertexmax, numdel);+ FOREACHvertex_(qh->del_vertices)+ qh_delvertex(qh, vertex);+ qh_settruncate(qh, qh->del_vertices, 0);+} /* deletevisible */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="facetintersect">-</a>++ qh_facetintersect(qh, facetA, facetB, skipa, skipB, prepend )+ return vertices for intersection of two simplicial facets+ may include 1 prepended entry (if more, need to settemppush)++ returns:+ returns set of qh.hull_dim-1 + prepend vertices+ returns skipped index for each test and checks for exactly one++ notes:+ does not need settemp since set in quick memory++ see also:+ qh_vertexintersect and qh_vertexintersect_new+ use qh_setnew_delnthsorted to get nth ridge (no skip information)++ design:+ locate skipped vertex by scanning facet A's neighbors+ locate skipped vertex by scanning facet B's neighbors+ intersect the vertex sets+*/+setT *qh_facetintersect(qhT *qh, facetT *facetA, facetT *facetB,+ int *skipA,int *skipB, int prepend) {+ setT *intersect;+ int dim= qh->hull_dim, i, j;+ facetT **neighborsA, **neighborsB;++ neighborsA= SETaddr_(facetA->neighbors, facetT);+ neighborsB= SETaddr_(facetB->neighbors, facetT);+ i= j= 0;+ if (facetB == *neighborsA++)+ *skipA= 0;+ else if (facetB == *neighborsA++)+ *skipA= 1;+ else if (facetB == *neighborsA++)+ *skipA= 2;+ else {+ for (i=3; i < dim; i++) {+ if (facetB == *neighborsA++) {+ *skipA= i;+ break;+ }+ }+ }+ if (facetA == *neighborsB++)+ *skipB= 0;+ else if (facetA == *neighborsB++)+ *skipB= 1;+ else if (facetA == *neighborsB++)+ *skipB= 2;+ else {+ for (j=3; j < dim; j++) {+ if (facetA == *neighborsB++) {+ *skipB= j;+ break;+ }+ }+ }+ if (i >= dim || j >= dim) {+ qh_fprintf(qh, qh->ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",+ facetA->id, facetB->id);+ qh_errexit2(qh, qh_ERRqhull, facetA, facetB);+ }+ intersect= qh_setnew_delnthsorted(qh, facetA->vertices, qh->hull_dim, *skipA, prepend);+ trace4((qh, qh->ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",+ facetA->id, *skipA, facetB->id, *skipB));+ return(intersect);+} /* facetintersect */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="gethash">-</a>++ qh_gethash(qh, hashsize, set, size, firstindex, skipelem )+ return hashvalue for a set with firstindex and skipelem++ notes:+ returned hash is in [0,hashsize)+ assumes at least firstindex+1 elements+ assumes skipelem is NULL, in set, or part of hash++ hashes memory addresses which may change over different runs of the same data+ using sum for hash does badly in high d+*/+int qh_gethash(qhT *qh, int hashsize, setT *set, int size, int firstindex, void *skipelem) {+ void **elemp= SETelemaddr_(set, firstindex, void);+ ptr_intT hash = 0, elem;+ unsigned result;+ int i;+#ifdef _MSC_VER /* Microsoft Visual C++ -- warn about 64-bit issues */+#pragma warning( push) /* WARN64 -- ptr_intT holds a 64-bit pointer */+#pragma warning( disable : 4311) /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */+#endif++ switch (size-firstindex) {+ case 1:+ hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;+ break;+ case 2:+ hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;+ break;+ case 3:+ hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]+ - (ptr_intT) skipelem;+ break;+ case 4:+ hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]+ + (ptr_intT)elemp[3] - (ptr_intT) skipelem;+ break;+ case 5:+ hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]+ + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;+ break;+ case 6:+ hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]+ + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]+ - (ptr_intT) skipelem;+ break;+ default:+ hash= 0;+ i= 3;+ do { /* this is about 10% in 10-d */+ if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {+ hash ^= (elem << i) + (elem >> (32-i));+ i += 3;+ if (i >= 32)+ i -= 32;+ }+ }while (*elemp);+ break;+ }+ if (hashsize<0) {+ qh_fprintf(qh, qh->ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize);+ qh_errexit2(qh, qh_ERRqhull, NULL, NULL);+ }+ result= (unsigned)hash;+ result %= (unsigned)hashsize;+ /* result= 0; for debugging */+ return result;+#ifdef _MSC_VER+#pragma warning( pop)+#endif+} /* gethash */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="makenewfacet">-</a>++ qh_makenewfacet(qh, vertices, toporient, horizon )+ creates a toporient? facet from vertices++ returns:+ returns newfacet+ adds newfacet to qh.facet_list+ newfacet->vertices= vertices+ if horizon+ newfacet->neighbor= horizon, but not vice versa+ newvertex_list updated with vertices+*/+facetT *qh_makenewfacet(qhT *qh, setT *vertices, boolT toporient,facetT *horizon) {+ facetT *newfacet;+ vertexT *vertex, **vertexp;++ FOREACHvertex_(vertices) {+ if (!vertex->newlist) {+ qh_removevertex(qh, vertex);+ qh_appendvertex(qh, vertex);+ }+ }+ newfacet= qh_newfacet(qh);+ newfacet->vertices= vertices;+ newfacet->toporient= (unsigned char)toporient;+ if (horizon)+ qh_setappend(qh, &(newfacet->neighbors), horizon);+ qh_appendfacet(qh, newfacet);+ return(newfacet);+} /* makenewfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="makenewplanes">-</a>++ qh_makenewplanes()+ make new hyperplanes for facets on qh.newfacet_list++ returns:+ all facets have hyperplanes or are marked for merging+ doesn't create hyperplane if horizon is coplanar (will merge)+ updates qh.min_vertex if qh.JOGGLEmax++ notes:+ facet->f.samecycle is defined for facet->mergehorizon facets+*/+void qh_makenewplanes(qhT *qh /* qh.newfacet_list */) {+ facetT *newfacet;++ FORALLnew_facets {+ if (!newfacet->mergehorizon)+ qh_setfacetplane(qh, newfacet);+ }+ if (qh->JOGGLEmax < REALmax/2)+ minimize_(qh->min_vertex, -wwval_(Wnewvertexmax));+} /* makenewplanes */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="makenew_nonsimplicial">-</a>++ qh_makenew_nonsimplicial(qh, visible, apex, numnew )+ make new facets for ridges of a visible facet++ returns:+ first newfacet, bumps numnew as needed+ attaches new facets if !qh.ONLYgood+ marks ridge neighbors for simplicial visible+ if (qh.ONLYgood)+ ridges on newfacet, horizon, and visible+ else+ ridge and neighbors between newfacet and horizon+ visible facet's ridges are deleted++ notes:+ qh.visit_id if visible has already been processed+ sets neighbor->seen for building f.samecycle+ assumes all 'seen' flags initially false++ design:+ for each ridge of visible facet+ get neighbor of visible facet+ if neighbor was already processed+ delete the ridge (will delete all visible facets later)+ if neighbor is a horizon facet+ create a new facet+ if neighbor coplanar+ adds newfacet to f.samecycle for later merging+ else+ updates neighbor's neighbor set+ (checks for non-simplicial facet with multiple ridges to visible facet)+ updates neighbor's ridge set+ (checks for simplicial neighbor to non-simplicial visible facet)+ (deletes ridge if neighbor is simplicial)++*/+#ifndef qh_NOmerge+facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */+ ridgeT *ridge, **ridgep;+ facetT *neighbor, *newfacet= NULL, *samecycle;+ setT *vertices;+ boolT toporient;+ int ridgeid;++ FOREACHridge_(visible->ridges) {+ ridgeid= ridge->id;+ neighbor= otherfacet_(ridge, visible);+ if (neighbor->visible) {+ if (!qh->ONLYgood) {+ if (neighbor->visitid == qh->visit_id) {+ qh_setfree(qh, &(ridge->vertices)); /* delete on 2nd visit */+ qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);+ }+ }+ }else { /* neighbor is an horizon facet */+ toporient= (ridge->top == visible);+ vertices= qh_setnew(qh, qh->hull_dim); /* makes sure this is quick */+ qh_setappend(qh, &vertices, apex);+ qh_setappend_set(qh, &vertices, ridge->vertices);+ newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);+ (*numnew)++;+ if (neighbor->coplanar) {+ newfacet->mergehorizon= True;+ if (!neighbor->seen) {+ newfacet->f.samecycle= newfacet;+ neighbor->f.newcycle= newfacet;+ }else {+ samecycle= neighbor->f.newcycle;+ newfacet->f.samecycle= samecycle->f.samecycle;+ samecycle->f.samecycle= newfacet;+ }+ }+ if (qh->ONLYgood) {+ if (!neighbor->simplicial)+ qh_setappend(qh, &(newfacet->ridges), ridge);+ }else { /* qh_attachnewfacets */+ if (neighbor->seen) {+ if (neighbor->simplicial) {+ qh_fprintf(qh, qh->ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n",+ neighbor->id, visible->id);+ qh_errexit2(qh, qh_ERRqhull, neighbor, visible);+ }+ qh_setappend(qh, &(neighbor->neighbors), newfacet);+ }else+ qh_setreplace(qh, neighbor->neighbors, visible, newfacet);+ if (neighbor->simplicial) {+ qh_setdel(neighbor->ridges, ridge);+ qh_setfree(qh, &(ridge->vertices));+ qh_memfree(qh, ridge, (int)sizeof(ridgeT));+ }else {+ qh_setappend(qh, &(newfacet->ridges), ridge);+ if (toporient)+ ridge->top= newfacet;+ else+ ridge->bottom= newfacet;+ }+ trace4((qh, qh->ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",+ newfacet->id, apex->id, ridgeid, neighbor->id));+ }+ }+ neighbor->seen= True;+ } /* for each ridge */+ if (!qh->ONLYgood)+ SETfirst_(visible->ridges)= NULL;+ return newfacet;+} /* makenew_nonsimplicial */+#else /* qh_NOmerge */+facetT *qh_makenew_nonsimplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {+ return NULL;+}+#endif /* qh_NOmerge */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="makenew_simplicial">-</a>++ qh_makenew_simplicial(qh, visible, apex, numnew )+ make new facets for simplicial visible facet and apex++ returns:+ attaches new facets if (!qh.ONLYgood)+ neighbors between newfacet and horizon++ notes:+ nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial)++ design:+ locate neighboring horizon facet for visible facet+ determine vertices and orientation+ create new facet+ if coplanar,+ add new facet to f.samecycle+ update horizon facet's neighbor list+*/+facetT *qh_makenew_simplicial(qhT *qh, facetT *visible, vertexT *apex, int *numnew) {+ facetT *neighbor, **neighborp, *newfacet= NULL;+ setT *vertices;+ boolT flip, toporient;+ int horizonskip= 0, visibleskip= 0;++ FOREACHneighbor_(visible) {+ if (!neighbor->seen && !neighbor->visible) {+ vertices= qh_facetintersect(qh, neighbor,visible, &horizonskip, &visibleskip, 1);+ SETfirst_(vertices)= apex;+ flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));+ if (neighbor->toporient)+ toporient= horizonskip & 0x1;+ else+ toporient= (horizonskip & 0x1) ^ 0x1;+ newfacet= qh_makenewfacet(qh, vertices, toporient, neighbor);+ (*numnew)++;+ if (neighbor->coplanar && (qh->PREmerge || qh->MERGEexact)) {+#ifndef qh_NOmerge+ newfacet->f.samecycle= newfacet;+ newfacet->mergehorizon= True;+#endif+ }+ if (!qh->ONLYgood)+ SETelem_(neighbor->neighbors, horizonskip)= newfacet;+ trace4((qh, qh->ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",+ newfacet->id, toporient, apex->id, neighbor->id, horizonskip,+ neighbor->toporient, visible->id, visibleskip, flip));+ }+ }+ return newfacet;+} /* makenew_simplicial */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="matchneighbor">-</a>++ qh_matchneighbor(qh, newfacet, newskip, hashsize, hashcount )+ either match subridge of newfacet with neighbor or add to hash_table++ returns:+ duplicate ridges are unmatched and marked by qh_DUPLICATEridge++ notes:+ ridge is newfacet->vertices w/o newskip vertex+ do not allocate memory (need to free hash_table cleanly)+ uses linear hash chains++ see also:+ qh_matchduplicates++ design:+ for each possible matching facet in qh.hash_table+ if vertices match+ set ismatch, if facets have opposite orientation+ if ismatch and matching facet doesn't have a match+ match the facets by updating their neighbor sets+ else+ indicate a duplicate ridge+ set facet hyperplane for later testing+ add facet to hashtable+ unless the other facet was already a duplicate ridge+ mark both facets with a duplicate ridge+ add other facet (if defined) to hash table+*/+void qh_matchneighbor(qhT *qh, facetT *newfacet, int newskip, int hashsize, int *hashcount) {+ boolT newfound= False; /* True, if new facet is already in hash chain */+ boolT same, ismatch;+ int hash, scan;+ facetT *facet, *matchfacet;+ int skip, matchskip;++ hash= qh_gethash(qh, hashsize, newfacet->vertices, qh->hull_dim, 1,+ SETelem_(newfacet->vertices, newskip));+ trace4((qh, qh->ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",+ newfacet->id, newskip, hash, *hashcount));+ zinc_(Zhashlookup);+ for (scan= hash; (facet= SETelemt_(qh->hash_table, scan, facetT));+ scan= (++scan >= hashsize ? 0 : scan)) {+ if (facet == newfacet) {+ newfound= True;+ continue;+ }+ zinc_(Zhashtests);+ if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {+ if (SETelem_(newfacet->vertices, newskip) ==+ SETelem_(facet->vertices, skip)) {+ qh_precision(qh, "two facets with the same vertices");+ qh_fprintf(qh, qh->ferr, 6106, "qhull precision error: Vertex sets are the same for f%d and f%d. Can not force output.\n",+ facet->id, newfacet->id);+ qh_errexit2(qh, qh_ERRprec, facet, newfacet);+ }+ ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient)));+ matchfacet= SETelemt_(facet->neighbors, skip, facetT);+ if (ismatch && !matchfacet) {+ SETelem_(facet->neighbors, skip)= newfacet;+ SETelem_(newfacet->neighbors, newskip)= facet;+ (*hashcount)--;+ trace4((qh, qh->ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",+ facet->id, skip, newfacet->id, newskip));+ return;+ }+ if (!qh->PREmerge && !qh->MERGEexact) {+ qh_precision(qh, "a ridge with more than two neighbors");+ qh_fprintf(qh, qh->ferr, 6107, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors. Can not continue.\n",+ facet->id, newfacet->id, getid_(matchfacet));+ qh_errexit2(qh, qh_ERRprec, facet, newfacet);+ }+ SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;+ newfacet->dupridge= True;+ if (!newfacet->normal)+ qh_setfacetplane(qh, newfacet);+ qh_addhash(newfacet, qh->hash_table, hashsize, hash);+ (*hashcount)++;+ if (!facet->normal)+ qh_setfacetplane(qh, facet);+ if (matchfacet != qh_DUPLICATEridge) {+ SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;+ facet->dupridge= True;+ if (!facet->normal)+ qh_setfacetplane(qh, facet);+ if (matchfacet) {+ matchskip= qh_setindex(matchfacet->neighbors, facet);+ if (matchskip<0) {+ qh_fprintf(qh, qh->ferr, 6260, "qhull internal error (qh_matchneighbor): matchfacet f%d is in f%d neighbors but not vice versa. Can not continue.\n",+ matchfacet->id, facet->id);+ qh_errexit2(qh, qh_ERRqhull, matchfacet, facet);+ }+ SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; /* matchskip>=0 by QH6260 */+ matchfacet->dupridge= True;+ if (!matchfacet->normal)+ qh_setfacetplane(qh, matchfacet);+ qh_addhash(matchfacet, qh->hash_table, hashsize, hash);+ *hashcount += 2;+ }+ }+ trace4((qh, qh->ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",+ newfacet->id, newskip, facet->id, skip,+ (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)),+ ismatch, hash));+ return; /* end of duplicate ridge */+ }+ }+ if (!newfound)+ SETelem_(qh->hash_table, scan)= newfacet; /* same as qh_addhash */+ (*hashcount)++;+ trace4((qh, qh->ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",+ newfacet->id, newskip, hash));+} /* matchneighbor */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="matchnewfacets">-</a>++ qh_matchnewfacets()+ match newfacets in qh.newfacet_list to their newfacet neighbors++ returns:+ qh.newfacet_list with full neighbor sets+ get vertices with nth neighbor by deleting nth vertex+ if qh.PREmerge/MERGEexact or qh.FORCEoutput+ sets facet->flippped if flipped normal (also prevents point partitioning)+ if duplicate ridges and qh.PREmerge/MERGEexact+ sets facet->dupridge+ missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)++ notes:+ newfacets already have neighbor[0] (horizon facet)+ assumes qh.hash_table is NULL+ vertex->neighbors has not been updated yet+ do not allocate memory after qh.hash_table (need to free it cleanly)++ design:+ delete neighbor sets for all new facets+ initialize a hash table+ for all new facets+ match facet with neighbors+ if unmatched facets (due to duplicate ridges)+ for each new facet with a duplicate ridge+ match it with a facet+ check for flipped facets+*/+void qh_matchnewfacets(qhT *qh /* qh.newfacet_list */) {+ int numnew=0, hashcount=0, newskip;+ facetT *newfacet, *neighbor;+ int dim= qh->hull_dim, hashsize, neighbor_i, neighbor_n;+ setT *neighbors;+#ifndef qh_NOtrace+ int facet_i, facet_n, numfree= 0;+ facetT *facet;+#endif++ trace1((qh, qh->ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n"));+ FORALLnew_facets {+ numnew++;+ { /* inline qh_setzero(qh, newfacet->neighbors, 1, qh->hull_dim); */+ neighbors= newfacet->neighbors;+ neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/+ memset((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);+ }+ }++ qh_newhashtable(qh, numnew*(qh->hull_dim-1)); /* twice what is normally needed,+ but every ridge could be DUPLICATEridge */+ hashsize= qh_setsize(qh, qh->hash_table);+ FORALLnew_facets {+ for (newskip=1; newskip<qh->hull_dim; newskip++) /* furthest/horizon already matched */+ /* hashsize>0 because hull_dim>1 and numnew>0 */+ qh_matchneighbor(qh, newfacet, newskip, hashsize, &hashcount);+#if 0 /* use the following to trap hashcount errors */+ {+ int count= 0, k;+ facetT *facet, *neighbor;++ count= 0;+ FORALLfacet_(qh->newfacet_list) { /* newfacet already in use */+ for (k=1; k < qh->hull_dim; k++) {+ neighbor= SETelemt_(facet->neighbors, k, facetT);+ if (!neighbor || neighbor == qh_DUPLICATEridge)+ count++;+ }+ if (facet == newfacet)+ break;+ }+ if (count != hashcount) {+ qh_fprintf(qh, qh->ferr, 8088, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",+ newfacet->id, hashcount, count);+ qh_errexit(qh, qh_ERRqhull, newfacet, NULL);+ }+ }+#endif /* end of trap code */+ }+ if (hashcount) {+ FORALLnew_facets {+ if (newfacet->dupridge) {+ FOREACHneighbor_i_(qh, newfacet) {+ if (neighbor == qh_DUPLICATEridge) {+ qh_matchduplicates(qh, newfacet, neighbor_i, hashsize, &hashcount);+ /* this may report MERGEfacet */+ }+ }+ }+ }+ }+ if (hashcount) {+ qh_fprintf(qh, qh->ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",+ hashcount);+ qh_printhashtable(qh, qh->ferr);+ qh_errexit(qh, qh_ERRqhull, NULL, NULL);+ }+#ifndef qh_NOtrace+ if (qh->IStracing >= 2) {+ FOREACHfacet_i_(qh, qh->hash_table) {+ if (!facet)+ numfree++;+ }+ qh_fprintf(qh, qh->ferr, 8089, "qh_matchnewfacets: %d new facets, %d unused hash entries . hashsize %d\n",+ numnew, numfree, qh_setsize(qh, qh->hash_table));+ }+#endif /* !qh_NOtrace */+ qh_setfree(qh, &qh->hash_table);+ if (qh->PREmerge || qh->MERGEexact) {+ if (qh->IStracing >= 4)+ qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);+ FORALLnew_facets {+ if (newfacet->normal)+ qh_checkflipped(qh, newfacet, NULL, qh_ALL);+ }+ }else if (qh->FORCEoutput)+ qh_checkflipped_all(qh, qh->newfacet_list); /* prints warnings for flipped */+} /* matchnewfacets */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="matchvertices">-</a>++ qh_matchvertices(qh, firstindex, verticesA, skipA, verticesB, skipB, same )+ tests whether vertices match with a single skip+ starts match at firstindex since all new facets have a common vertex++ returns:+ true if matched vertices+ skip index for each set+ sets same iff vertices have the same orientation++ notes:+ assumes skipA is in A and both sets are the same size++ design:+ set up pointers+ scan both sets checking for a match+ test orientation+*/+boolT qh_matchvertices(qhT *qh, int firstindex, setT *verticesA, int skipA,+ setT *verticesB, int *skipB, boolT *same) {+ vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;++ elemAp= SETelemaddr_(verticesA, firstindex, vertexT);+ elemBp= SETelemaddr_(verticesB, firstindex, vertexT);+ skipAp= SETelemaddr_(verticesA, skipA, vertexT);+ do if (elemAp != skipAp) {+ while (*elemAp != *elemBp++) {+ if (skipBp)+ return False;+ skipBp= elemBp; /* one extra like FOREACH */+ }+ }while (*(++elemAp));+ if (!skipBp)+ skipBp= ++elemBp;+ *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB */+ *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */+ trace4((qh, qh->ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n",+ skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));+ return(True);+} /* matchvertices */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="newfacet">-</a>++ qh_newfacet(qh)+ return a new facet++ returns:+ all fields initialized or cleared (NULL)+ preallocates neighbors set+*/+facetT *qh_newfacet(qhT *qh) {+ facetT *facet;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */++ qh_memalloc_(qh, (int)sizeof(facetT), freelistp, facet, facetT);+ memset((char *)facet, (size_t)0, sizeof(facetT));+ if (qh->facet_id == qh->tracefacet_id)+ qh->tracefacet= facet;+ facet->id= qh->facet_id++;+ facet->neighbors= qh_setnew(qh, qh->hull_dim);+#if !qh_COMPUTEfurthest+ facet->furthestdist= 0.0;+#endif+#if qh_MAXoutside+ if (qh->FORCEoutput && qh->APPROXhull)+ facet->maxoutside= qh->MINoutside;+ else+ facet->maxoutside= qh->DISTround;+#endif+ facet->simplicial= True;+ facet->good= True;+ facet->newfacet= True;+ trace4((qh, qh->ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id));+ return(facet);+} /* newfacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="newridge">-</a>++ qh_newridge()+ return a new ridge+*/+ridgeT *qh_newridge(qhT *qh) {+ ridgeT *ridge;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */++ qh_memalloc_(qh, (int)sizeof(ridgeT), freelistp, ridge, ridgeT);+ memset((char *)ridge, (size_t)0, sizeof(ridgeT));+ zinc_(Ztotridges);+ if (qh->ridge_id == UINT_MAX) {+ qh_fprintf(qh, qh->ferr, 7074, "\+qhull warning: more than 2^32 ridges. Qhull results are OK. Since the ridge ID wraps around to 0, two ridges may have the same identifier.\n");+ }+ ridge->id= qh->ridge_id++;+ trace4((qh, qh->ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id));+ return(ridge);+} /* newridge */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="pointid">-</a>++ qh_pointid(qh, point )+ return id for a point,+ returns qh_IDnone(-3) if null, qh_IDinterior(-2) if interior, or qh_IDunknown(-1) if not known++ alternative code if point is in qh.first_point...+ unsigned long id;+ id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;++ notes:+ Valid points are non-negative+ WARN64 -- id truncated to 32-bits, at most 2G points+ NOerrors returned (QhullPoint::id)+ if point not in point array+ the code does a comparison of unrelated pointers.+*/+int qh_pointid(qhT *qh, pointT *point) {+ ptr_intT offset, id;++ if (!point || !qh)+ return qh_IDnone;+ else if (point == qh->interior_point)+ return qh_IDinterior;+ else if (point >= qh->first_point+ && point < qh->first_point + qh->num_points * qh->hull_dim) {+ offset= (ptr_intT)(point - qh->first_point);+ id= offset / qh->hull_dim;+ }else if ((id= qh_setindex(qh->other_points, point)) != -1)+ id += qh->num_points;+ else+ return qh_IDunknown;+ return (int)id;+} /* pointid */++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="removefacet">-</a>++ qh_removefacet(qh, facet )+ unlinks facet from qh.facet_list,++ returns:+ updates qh.facet_list .newfacet_list .facet_next visible_list+ decrements qh.num_facets++ see:+ qh_appendfacet+*/+void qh_removefacet(qhT *qh, facetT *facet) {+ facetT *next= facet->next, *previous= facet->previous;++ if (facet == qh->newfacet_list)+ qh->newfacet_list= next;+ if (facet == qh->facet_next)+ qh->facet_next= next;+ if (facet == qh->visible_list)+ qh->visible_list= next;+ if (previous) {+ previous->next= next;+ next->previous= previous;+ }else { /* 1st facet in qh->facet_list */+ qh->facet_list= next;+ qh->facet_list->previous= NULL;+ }+ qh->num_facets--;+ trace4((qh, qh->ferr, 4057, "qh_removefacet: remove f%d from facet_list\n", facet->id));+} /* removefacet */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="removevertex">-</a>++ qh_removevertex(qh, vertex )+ unlinks vertex from qh.vertex_list,++ returns:+ updates qh.vertex_list .newvertex_list+ decrements qh.num_vertices+*/+void qh_removevertex(qhT *qh, vertexT *vertex) {+ vertexT *next= vertex->next, *previous= vertex->previous;++ if (vertex == qh->newvertex_list)+ qh->newvertex_list= next;+ if (previous) {+ previous->next= next;+ next->previous= previous;+ }else { /* 1st vertex in qh->vertex_list */+ qh->vertex_list= vertex->next;+ qh->vertex_list->previous= NULL;+ }+ qh->num_vertices--;+ trace4((qh, qh->ferr, 4058, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));+} /* removevertex */+++/*-<a href="qh-poly_r.htm#TOC"+ >-------------------------------</a><a name="updatevertices">-</a>++ qh_updatevertices()+ update vertex neighbors and delete interior vertices++ returns:+ if qh.VERTEXneighbors, updates neighbors for each vertex+ if qh.newvertex_list,+ removes visible neighbors from vertex neighbors+ if qh.newfacet_list+ adds new facets to vertex neighbors+ if qh.visible_list+ interior vertices added to qh.del_vertices for later partitioning++ design:+ if qh.VERTEXneighbors+ deletes references to visible facets from vertex neighbors+ appends new facets to the neighbor list for each vertex+ checks all vertices of visible facets+ removes visible facets from neighbor lists+ marks unused vertices for deletion+*/+void qh_updatevertices(qhT *qh /*qh.newvertex_list, newfacet_list, visible_list*/) {+ facetT *newfacet= NULL, *neighbor, **neighborp, *visible;+ vertexT *vertex, **vertexp;++ trace3((qh, qh->ferr, 3013, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));+ if (qh->VERTEXneighbors) {+ FORALLvertex_(qh->newvertex_list) {+ FOREACHneighbor_(vertex) {+ if (neighbor->visible)+ SETref_(neighbor)= NULL;+ }+ qh_setcompact(qh, vertex->neighbors);+ }+ FORALLnew_facets {+ FOREACHvertex_(newfacet->vertices)+ qh_setappend(qh, &vertex->neighbors, newfacet);+ }+ FORALLvisible_facets {+ FOREACHvertex_(visible->vertices) {+ if (!vertex->newlist && !vertex->deleted) {+ FOREACHneighbor_(vertex) { /* this can happen under merging */+ if (!neighbor->visible)+ break;+ }+ if (neighbor)+ qh_setdel(vertex->neighbors, visible);+ else {+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+ trace2((qh, qh->ferr, 2041, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",+ qh_pointid(qh, vertex->point), vertex->id, visible->id));+ }+ }+ }+ }+ }else { /* !VERTEXneighbors */+ FORALLvisible_facets {+ FOREACHvertex_(visible->vertices) {+ if (!vertex->newlist && !vertex->deleted) {+ vertex->deleted= True;+ qh_setappend(qh, &qh->del_vertices, vertex);+ trace2((qh, qh->ferr, 2042, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n",+ qh_pointid(qh, vertex->point), vertex->id, visible->id));+ }+ }+ }+ }+} /* updatevertices */+++
+ Cdir/qset_r.c view
@@ -0,0 +1,1340 @@+/*<html><pre> -<a href="qh-set_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ qset_r.c+ implements set manipulations needed for quickhull++ see qh-set_r.htm and qset_r.h++ Be careful of strict aliasing (two pointers of different types+ that reference the same location). The last slot of a set is+ either the actual size of the set plus 1, or the NULL terminator+ of the set (i.e., setelemT).++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/qset_r.c#3 $$Change: 2062 $+ $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $+*/++#include "libqhull_r.h" /* for qhT and QHULL_CRTDBG */+#include "qset_r.h"+#include "mem_r.h"+#include <stdio.h>+#include <string.h>+/*** uncomment here and qhull_ra.h+ if string.h does not define memcpy()+#include <memory.h>+*/++#ifndef qhDEFlibqhull+typedef struct ridgeT ridgeT;+typedef struct facetT facetT;+void qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);+void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );+# ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */+# pragma warning( disable : 4127) /* conditional expression is constant */+# pragma warning( disable : 4706) /* assignment within conditional function */+# endif+#endif++/*=============== internal macros ===========================*/++/*============ functions in alphabetical order ===================*/++/*-<a href="qh-set_r.htm#TOC"+ >--------------------------------<a name="setaddnth">-</a>++ qh_setaddnth(qh, setp, nth, newelem)+ adds newelem as n'th element of sorted or unsorted *setp++ notes:+ *setp and newelem must be defined+ *setp may be a temp set+ nth=0 is first element+ errors if nth is out of bounds++ design:+ expand *setp if empty or full+ move tail of *setp up one+ insert newelem+*/+void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {+ int oldsize, i;+ setelemT *sizep; /* avoid strict aliasing */+ setelemT *oldp, *newp;++ if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {+ qh_setlarger(qh, setp);+ sizep= SETsizeaddr_(*setp);+ }+ oldsize= sizep->i - 1;+ if (nth < 0 || nth > oldsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);+ qh_setprint(qh, qh->qhmem.ferr, "", *setp);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ sizep->i++;+ oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void); /* NULL */+ newp= oldp+1;+ for (i=oldsize-nth+1; i--; ) /* move at least NULL */+ (newp--)->p= (oldp--)->p; /* may overwrite *sizep */+ newp->p= newelem;+} /* setaddnth */+++/*-<a href="qh-set_r.htm#TOC"+ >--------------------------------<a name="setaddsorted">-</a>++ setaddsorted( setp, newelem )+ adds an newelem into sorted *setp++ notes:+ *setp and newelem must be defined+ *setp may be a temp set+ nop if newelem already in set++ design:+ find newelem's position in *setp+ insert newelem+*/+void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {+ int newindex=0;+ void *elem, **elemp;++ FOREACHelem_(*setp) { /* could use binary search instead */+ if (elem < newelem)+ newindex++;+ else if (elem == newelem)+ return;+ else+ break;+ }+ qh_setaddnth(qh, setp, newindex, newelem);+} /* setaddsorted */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setappend">-</a>++ qh_setappend(qh, setp, newelem)+ append newelem to *setp++ notes:+ *setp may be a temp set+ *setp and newelem may be NULL++ design:+ expand *setp if empty or full+ append newelem to *setp++*/+void qh_setappend(qhT *qh, setT **setp, void *newelem) {+ setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */+ setelemT *endp;+ int count;++ if (!newelem)+ return;+ if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {+ qh_setlarger(qh, setp);+ sizep= SETsizeaddr_(*setp);+ }+ count= (sizep->i)++ - 1;+ endp= (setelemT *)SETelemaddr_(*setp, count, void);+ (endp++)->p= newelem;+ endp->p= NULL;+} /* setappend */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setappend_set">-</a>++ qh_setappend_set(qh, setp, setA)+ appends setA to *setp++ notes:+ *setp can not be a temp set+ *setp and setA may be NULL++ design:+ setup for copy+ expand *setp if it is too small+ append all elements of setA to *setp+*/+void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {+ int sizeA, size;+ setT *oldset;+ setelemT *sizep;++ if (!setA)+ return;+ SETreturnsize_(setA, sizeA);+ if (!*setp)+ *setp= qh_setnew(qh, sizeA);+ sizep= SETsizeaddr_(*setp);+ if (!(size= sizep->i))+ size= (*setp)->maxsize;+ else+ size--;+ if (size + sizeA > (*setp)->maxsize) {+ oldset= *setp;+ *setp= qh_setcopy(qh, oldset, sizeA);+ qh_setfree(qh, &oldset);+ sizep= SETsizeaddr_(*setp);+ }+ if (sizeA > 0) {+ sizep->i= size+sizeA+1; /* memcpy may overwrite */+ memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);+ }+} /* setappend_set */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setappend2ndlast">-</a>++ qh_setappend2ndlast(qh, setp, newelem )+ makes newelem the next to the last element in *setp++ notes:+ *setp must have at least one element+ newelem must be defined+ *setp may be a temp set++ design:+ expand *setp if empty or full+ move last element of *setp up one+ insert newelem+*/+void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {+ setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */+ setelemT *endp, *lastp;+ int count;++ if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {+ qh_setlarger(qh, setp);+ sizep= SETsizeaddr_(*setp);+ }+ count= (sizep->i)++ - 1;+ endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */+ lastp= endp-1;+ *(endp++)= *lastp;+ endp->p= NULL; /* may overwrite *sizep */+ lastp->p= newelem;+} /* setappend2ndlast */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setcheck">-</a>++ qh_setcheck(qh, set, typename, id )+ check set for validity+ report errors with typename and id++ design:+ checks that maxsize, actual size, and NULL terminator agree+*/+void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned id) {+ int maxsize, size;+ int waserr= 0;++ if (!set)+ return;+ SETreturnsize_(set, size);+ maxsize= set->maxsize;+ if (size > maxsize || !maxsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",+ size, tname, id, maxsize);+ waserr= 1;+ }else if (set->e[size].p) {+ qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",+ tname, id, size-1, maxsize);+ waserr= 1;+ }+ if (waserr) {+ qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+} /* setcheck */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setcompact">-</a>++ qh_setcompact(qh, set )+ remove internal NULLs from an unsorted set++ returns:+ updated set++ notes:+ set may be NULL+ it would be faster to swap tail of set into holes, like qh_setdel++ design:+ setup pointers into set+ skip NULLs while copying elements to start of set+ update the actual size+*/+void qh_setcompact(qhT *qh, setT *set) {+ int size;+ void **destp, **elemp, **endp, **firstp;++ if (!set)+ return;+ SETreturnsize_(set, size);+ destp= elemp= firstp= SETaddr_(set, void);+ endp= destp + size;+ while (1) {+ if (!(*destp++ = *elemp++)) {+ destp--;+ if (elemp > endp)+ break;+ }+ }+ qh_settruncate(qh, set, (int)(destp-firstp)); /* WARN64 */+} /* setcompact */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setcopy">-</a>++ qh_setcopy(qh, set, extra )+ make a copy of a sorted or unsorted set with extra slots++ returns:+ new set++ design:+ create a newset with extra slots+ copy the elements to the newset++*/+setT *qh_setcopy(qhT *qh, setT *set, int extra) {+ setT *newset;+ int size;++ if (extra < 0)+ extra= 0;+ SETreturnsize_(set, size);+ newset= qh_setnew(qh, size+extra);+ SETsizeaddr_(newset)->i= size+1; /* memcpy may overwrite */+ memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);+ return(newset);+} /* setcopy */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setdel">-</a>++ qh_setdel(set, oldelem )+ delete oldelem from an unsorted set++ returns:+ returns oldelem if found+ returns NULL otherwise++ notes:+ set may be NULL+ oldelem must not be NULL;+ only deletes one copy of oldelem in set++ design:+ locate oldelem+ update actual size if it was full+ move the last element to the oldelem's location+*/+void *qh_setdel(setT *set, void *oldelem) {+ setelemT *sizep;+ setelemT *elemp;+ setelemT *lastp;++ if (!set)+ return NULL;+ elemp= (setelemT *)SETaddr_(set, void);+ while (elemp->p != oldelem && elemp->p)+ elemp++;+ if (elemp->p) {+ sizep= SETsizeaddr_(set);+ if (!(sizep->i)--) /* if was a full set */+ sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */+ lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);+ elemp->p= lastp->p; /* may overwrite itself */+ lastp->p= NULL;+ return oldelem;+ }+ return NULL;+} /* setdel */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setdellast">-</a>++ qh_setdellast(set)+ return last element of set or NULL++ notes:+ deletes element from set+ set may be NULL++ design:+ return NULL if empty+ if full set+ delete last element and set actual size+ else+ delete last element and update actual size+*/+void *qh_setdellast(setT *set) {+ int setsize; /* actually, actual_size + 1 */+ int maxsize;+ setelemT *sizep;+ void *returnvalue;++ if (!set || !(set->e[0].p))+ return NULL;+ sizep= SETsizeaddr_(set);+ if ((setsize= sizep->i)) {+ returnvalue= set->e[setsize - 2].p;+ set->e[setsize - 2].p= NULL;+ sizep->i--;+ }else {+ maxsize= set->maxsize;+ returnvalue= set->e[maxsize - 1].p;+ set->e[maxsize - 1].p= NULL;+ sizep->i= maxsize;+ }+ return returnvalue;+} /* setdellast */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setdelnth">-</a>++ qh_setdelnth(qh, set, nth )+ deletes nth element from unsorted set+ 0 is first element++ returns:+ returns the element (needs type conversion)++ notes:+ errors if nth invalid++ design:+ setup points and check nth+ delete nth element and overwrite with last element+*/+void *qh_setdelnth(qhT *qh, setT *set, int nth) {+ void *elem;+ setelemT *sizep;+ setelemT *elemp, *lastp;++ sizep= SETsizeaddr_(set);+ if ((sizep->i--)==0) /* if was a full set */+ sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */+ if (nth < 0 || nth >= sizep->i) {+ qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */+ lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);+ elem= elemp->p;+ elemp->p= lastp->p; /* may overwrite itself */+ lastp->p= NULL;+ return elem;+} /* setdelnth */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setdelnthsorted">-</a>++ qh_setdelnthsorted(qh, set, nth )+ deletes nth element from sorted set++ returns:+ returns the element (use type conversion)++ notes:+ errors if nth invalid++ see also:+ setnew_delnthsorted++ design:+ setup points and check nth+ copy remaining elements down one+ update actual size+*/+void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {+ void *elem;+ setelemT *sizep;+ setelemT *newp, *oldp;++ sizep= SETsizeaddr_(set);+ if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ newp= (setelemT *)SETelemaddr_(set, nth, void);+ elem= newp->p;+ oldp= newp+1;+ while (((newp++)->p= (oldp++)->p))+ ; /* copy remaining elements and NULL */+ if ((sizep->i--)==0) /* if was a full set */+ sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */+ return elem;+} /* setdelnthsorted */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setdelsorted">-</a>++ qh_setdelsorted(set, oldelem )+ deletes oldelem from sorted set++ returns:+ returns oldelem if it was deleted++ notes:+ set may be NULL++ design:+ locate oldelem in set+ copy remaining elements down one+ update actual size+*/+void *qh_setdelsorted(setT *set, void *oldelem) {+ setelemT *sizep;+ setelemT *newp, *oldp;++ if (!set)+ return NULL;+ newp= (setelemT *)SETaddr_(set, void);+ while(newp->p != oldelem && newp->p)+ newp++;+ if (newp->p) {+ oldp= newp+1;+ while (((newp++)->p= (oldp++)->p))+ ; /* copy remaining elements */+ sizep= SETsizeaddr_(set);+ if ((sizep->i--)==0) /* if was a full set */+ sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */+ return oldelem;+ }+ return NULL;+} /* setdelsorted */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setduplicate">-</a>++ qh_setduplicate(qh, set, elemsize )+ duplicate a set of elemsize elements++ notes:+ use setcopy if retaining old elements++ design:+ create a new set+ for each elem of the old set+ create a newelem+ append newelem to newset+*/+setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {+ void *elem, **elemp, *newElem;+ setT *newSet;+ int size;++ if (!(size= qh_setsize(qh, set)))+ return NULL;+ newSet= qh_setnew(qh, size);+ FOREACHelem_(set) {+ newElem= qh_memalloc(qh, elemsize);+ memcpy(newElem, elem, (size_t)elemsize);+ qh_setappend(qh, &newSet, newElem);+ }+ return newSet;+} /* setduplicate */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setendpointer">-</a>++ qh_setendpointer( set )+ Returns pointer to NULL terminator of a set's elements+ set can not be NULL++*/+void **qh_setendpointer(setT *set) {++ setelemT *sizep= SETsizeaddr_(set);+ int n= sizep->i;+ return (n ? &set->e[n-1].p : &sizep->p);+} /* qh_setendpointer */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setequal">-</a>++ qh_setequal( setA, setB )+ returns 1 if two sorted sets are equal, otherwise returns 0++ notes:+ either set may be NULL++ design:+ check size of each set+ setup pointers+ compare elements of each set+*/+int qh_setequal(setT *setA, setT *setB) {+ void **elemAp, **elemBp;+ int sizeA= 0, sizeB= 0;++ if (setA) {+ SETreturnsize_(setA, sizeA);+ }+ if (setB) {+ SETreturnsize_(setB, sizeB);+ }+ if (sizeA != sizeB)+ return 0;+ if (!sizeA)+ return 1;+ elemAp= SETaddr_(setA, void);+ elemBp= SETaddr_(setB, void);+ if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))+ return 1;+ return 0;+} /* setequal */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setequal_except">-</a>++ qh_setequal_except( setA, skipelemA, setB, skipelemB )+ returns 1 if sorted setA and setB are equal except for skipelemA & B++ returns:+ false if either skipelemA or skipelemB are missing++ notes:+ neither set may be NULL++ if skipelemB is NULL,+ can skip any one element of setB++ design:+ setup pointers+ search for skipelemA, skipelemB, and mismatches+ check results+*/+int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {+ void **elemA, **elemB;+ int skip=0;++ elemA= SETaddr_(setA, void);+ elemB= SETaddr_(setB, void);+ while (1) {+ if (*elemA == skipelemA) {+ skip++;+ elemA++;+ }+ if (skipelemB) {+ if (*elemB == skipelemB) {+ skip++;+ elemB++;+ }+ }else if (*elemA != *elemB) {+ skip++;+ if (!(skipelemB= *elemB++))+ return 0;+ }+ if (!*elemA)+ break;+ if (*elemA++ != *elemB++)+ return 0;+ }+ if (skip != 2 || *elemB)+ return 0;+ return 1;+} /* setequal_except */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setequal_skip">-</a>++ qh_setequal_skip( setA, skipA, setB, skipB )+ returns 1 if sorted setA and setB are equal except for elements skipA & B++ returns:+ false if different size++ notes:+ neither set may be NULL++ design:+ setup pointers+ search for mismatches while skipping skipA and skipB+*/+int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {+ void **elemA, **elemB, **skipAp, **skipBp;++ elemA= SETaddr_(setA, void);+ elemB= SETaddr_(setB, void);+ skipAp= SETelemaddr_(setA, skipA, void);+ skipBp= SETelemaddr_(setB, skipB, void);+ while (1) {+ if (elemA == skipAp)+ elemA++;+ if (elemB == skipBp)+ elemB++;+ if (!*elemA)+ break;+ if (*elemA++ != *elemB++)+ return 0;+ }+ if (*elemB)+ return 0;+ return 1;+} /* setequal_skip */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setfree">-</a>++ qh_setfree(qh, setp )+ frees the space occupied by a sorted or unsorted set++ returns:+ sets setp to NULL++ notes:+ set may be NULL++ design:+ free array+ free set+*/+void qh_setfree(qhT *qh, setT **setp) {+ int size;+ void **freelistp; /* used if !qh_NOmem by qh_memfree_() */++ if (*setp) {+ size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;+ if (size <= qh->qhmem.LASTsize) {+ qh_memfree_(qh, *setp, size, freelistp);+ }else+ qh_memfree(qh, *setp, size);+ *setp= NULL;+ }+} /* setfree */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setfree2">-</a>++ qh_setfree2(qh, setp, elemsize )+ frees the space occupied by a set and its elements++ notes:+ set may be NULL++ design:+ free each element+ free set+*/+void qh_setfree2(qhT *qh, setT **setp, int elemsize) {+ void *elem, **elemp;++ FOREACHelem_(*setp)+ qh_memfree(qh, elem, elemsize);+ qh_setfree(qh, setp);+} /* setfree2 */++++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setfreelong">-</a>++ qh_setfreelong(qh, setp )+ frees a set only if it's in long memory++ returns:+ sets setp to NULL if it is freed++ notes:+ set may be NULL++ design:+ if set is large+ free it+*/+void qh_setfreelong(qhT *qh, setT **setp) {+ int size;++ if (*setp) {+ size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;+ if (size > qh->qhmem.LASTsize) {+ qh_memfree(qh, *setp, size);+ *setp= NULL;+ }+ }+} /* setfreelong */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setin">-</a>++ qh_setin(set, setelem )+ returns 1 if setelem is in a set, 0 otherwise++ notes:+ set may be NULL or unsorted++ design:+ scans set for setelem+*/+int qh_setin(setT *set, void *setelem) {+ void *elem, **elemp;++ FOREACHelem_(set) {+ if (elem == setelem)+ return 1;+ }+ return 0;+} /* setin */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setindex">-</a>++ qh_setindex(set, atelem )+ returns the index of atelem in set.+ returns -1, if not in set or maxsize wrong++ notes:+ set may be NULL and may contain nulls.+ NOerrors returned (qh_pointid, QhullPoint::id)++ design:+ checks maxsize+ scans set for atelem+*/+int qh_setindex(setT *set, void *atelem) {+ void **elem;+ int size, i;++ if (!set)+ return -1;+ SETreturnsize_(set, size);+ if (size > set->maxsize)+ return -1;+ elem= SETaddr_(set, void);+ for (i=0; i < size; i++) {+ if (*elem++ == atelem)+ return i;+ }+ return -1;+} /* setindex */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setlarger">-</a>++ qh_setlarger(qh, oldsetp )+ returns a larger set that contains all elements of *oldsetp++ notes:+ the set is at least twice as large+ if temp set, updates qh->qhmem.tempstack++ design:+ creates a new set+ copies the old set to the new set+ updates pointers in tempstack+ deletes the old set+*/+void qh_setlarger(qhT *qh, setT **oldsetp) {+ int size= 1;+ setT *newset, *set, **setp, *oldset;+ setelemT *sizep;+ setelemT *newp, *oldp;++ if (*oldsetp) {+ oldset= *oldsetp;+ SETreturnsize_(oldset, size);+ qh->qhmem.cntlarger++;+ qh->qhmem.totlarger += size+1;+ newset= qh_setnew(qh, 2 * size);+ oldp= (setelemT *)SETaddr_(oldset, void);+ newp= (setelemT *)SETaddr_(newset, void);+ memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);+ sizep= SETsizeaddr_(newset);+ sizep->i= size+1;+ FOREACHset_((setT *)qh->qhmem.tempstack) {+ if (set == oldset)+ *(setp-1)= newset;+ }+ qh_setfree(qh, oldsetp);+ }else+ newset= qh_setnew(qh, 3);+ *oldsetp= newset;+} /* setlarger */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setlast">-</a>++ qh_setlast( set )+ return last element of set or NULL (use type conversion)++ notes:+ set may be NULL++ design:+ return last element+*/+void *qh_setlast(setT *set) {+ int size;++ if (set) {+ size= SETsizeaddr_(set)->i;+ if (!size)+ return SETelem_(set, set->maxsize - 1);+ else if (size > 1)+ return SETelem_(set, size - 2);+ }+ return NULL;+} /* setlast */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setnew">-</a>++ qh_setnew(qh, setsize )+ creates and allocates space for a set++ notes:+ setsize means the number of elements (!including the NULL terminator)+ use qh_settemp/qh_setfreetemp if set is temporary++ design:+ allocate memory for set+ roundup memory if small set+ initialize as empty set+*/+setT *qh_setnew(qhT *qh, int setsize) {+ setT *set;+ int sizereceived; /* used if !qh_NOmem */+ int size;+ void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */++ if (!setsize)+ setsize++;+ size= sizeof(setT) + setsize * SETelemsize;+ if (size>0 && size <= qh->qhmem.LASTsize) {+ qh_memalloc_(qh, size, freelistp, set, setT);+#ifndef qh_NOmem+ sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];+ if (sizereceived > size)+ setsize += (sizereceived - size)/SETelemsize;+#endif+ }else+ set= (setT*)qh_memalloc(qh, size);+ set->maxsize= setsize;+ set->e[setsize].i= 1;+ set->e[0].p= NULL;+ return(set);+} /* setnew */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setnew_delnthsorted">-</a>++ qh_setnew_delnthsorted(qh, set, size, nth, prepend )+ creates a sorted set not containing nth element+ if prepend, the first prepend elements are undefined++ notes:+ set must be defined+ checks nth+ see also: setdelnthsorted++ design:+ create new set+ setup pointers and allocate room for prepend'ed entries+ append head of old set to new set+ append tail of old set to new set+*/+setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {+ setT *newset;+ void **oldp, **newp;+ int tailsize= size - nth -1, newsize;++ if (tailsize < 0) {+ qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ newsize= size-1 + prepend;+ newset= qh_setnew(qh, newsize);+ newset->e[newset->maxsize].i= newsize+1; /* may be overwritten */+ oldp= SETaddr_(set, void);+ newp= SETaddr_(newset, void) + prepend;+ switch (nth) {+ case 0:+ break;+ case 1:+ *(newp++)= *oldp++;+ break;+ case 2:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ case 3:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ case 4:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ default:+ memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);+ newp += nth;+ oldp += nth;+ break;+ }+ oldp++;+ switch (tailsize) {+ case 0:+ break;+ case 1:+ *(newp++)= *oldp++;+ break;+ case 2:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ case 3:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ case 4:+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ *(newp++)= *oldp++;+ break;+ default:+ memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);+ newp += tailsize;+ }+ *newp= NULL;+ return(newset);+} /* setnew_delnthsorted */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setprint">-</a>++ qh_setprint(qh, fp, string, set )+ print set elements to fp with identifying string++ notes:+ never errors+*/+void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {+ int size, k;++ if (!set)+ qh_fprintf(qh, fp, 9346, "%s set is null\n", string);+ else {+ SETreturnsize_(set, size);+ qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",+ string, set, set->maxsize, size);+ if (size > set->maxsize)+ size= set->maxsize+1;+ for (k=0; k < size; k++)+ qh_fprintf(qh, fp, 9348, " %p", set->e[k].p);+ qh_fprintf(qh, fp, 9349, "\n");+ }+} /* setprint */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setreplace">-</a>++ qh_setreplace(qh, set, oldelem, newelem )+ replaces oldelem in set with newelem++ notes:+ errors if oldelem not in the set+ newelem may be NULL, but it turns the set into an indexed set (no FOREACH)++ design:+ find oldelem+ replace with newelem+*/+void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {+ void **elemp;++ elemp= SETaddr_(set, void);+ while (*elemp != oldelem && *elemp)+ elemp++;+ if (*elemp)+ *elemp= newelem;+ else {+ qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",+ oldelem);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+} /* setreplace */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setsize">-</a>++ qh_setsize(qh, set )+ returns the size of a set++ notes:+ errors if set's maxsize is incorrect+ same as SETreturnsize_(set)+ same code for qh_setsize [qset_r.c] and QhullSetBase::count++ design:+ determine actual size of set from maxsize+*/+int qh_setsize(qhT *qh, setT *set) {+ int size;+ setelemT *sizep;++ if (!set)+ return(0);+ sizep= SETsizeaddr_(set);+ if ((size= sizep->i)) {+ size--;+ if (size > set->maxsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",+ size, set->maxsize);+ qh_setprint(qh, qh->qhmem.ferr, "set: ", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ }else+ size= set->maxsize;+ return size;+} /* setsize */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settemp">-</a>++ qh_settemp(qh, setsize )+ return a stacked, temporary set of upto setsize elements++ notes:+ use settempfree or settempfree_all to release from qh->qhmem.tempstack+ see also qh_setnew++ design:+ allocate set+ append to qh->qhmem.tempstack++*/+setT *qh_settemp(qhT *qh, int setsize) {+ setT *newset;++ newset= qh_setnew(qh, setsize);+ qh_setappend(qh, &qh->qhmem.tempstack, newset);+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",+ newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));+ return newset;+} /* settemp */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settempfree">-</a>++ qh_settempfree(qh, set )+ free temporary set at top of qh->qhmem.tempstack++ notes:+ nop if set is NULL+ errors if set not from previous qh_settemp++ to locate errors:+ use 'T2' to find source and then find mis-matching qh_settemp++ design:+ check top of qh->qhmem.tempstack+ free it+*/+void qh_settempfree(qhT *qh, setT **set) {+ setT *stackedset;++ if (!*set)+ return;+ stackedset= qh_settemppop(qh);+ if (stackedset != *set) {+ qh_settemppush(qh, stackedset);+ qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",+ *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,+ stackedset, qh_setsize(qh, stackedset));+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ qh_setfree(qh, set);+} /* settempfree */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settempfree_all">-</a>++ qh_settempfree_all(qh)+ free all temporary sets in qh->qhmem.tempstack++ design:+ for each set in tempstack+ free set+ free qh->qhmem.tempstack+*/+void qh_settempfree_all(qhT *qh) {+ setT *set, **setp;++ FOREACHset_(qh->qhmem.tempstack)+ qh_setfree(qh, &set);+ qh_setfree(qh, &qh->qhmem.tempstack);+} /* settempfree_all */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settemppop">-</a>++ qh_settemppop(qh)+ pop and return temporary set from qh->qhmem.tempstack++ notes:+ the returned set is permanent++ design:+ pop and check top of qh->qhmem.tempstack+*/+setT *qh_settemppop(qhT *qh) {+ setT *stackedset;++ stackedset= (setT*)qh_setdellast(qh->qhmem.tempstack);+ if (!stackedset) {+ qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",+ qh_setsize(qh, qh->qhmem.tempstack)+1, stackedset, qh_setsize(qh, stackedset));+ return stackedset;+} /* settemppop */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settemppush">-</a>++ qh_settemppush(qh, set )+ push temporary set unto qh->qhmem.tempstack (makes it temporary)++ notes:+ duplicates settemp() for tracing++ design:+ append set to tempstack+*/+void qh_settemppush(qhT *qh, setT *set) {+ if (!set) {+ qh_fprintf(qh, qh->qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ qh_setappend(qh, &qh->qhmem.tempstack, set);+ if (qh->qhmem.IStracing >= 5)+ qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",+ qh_setsize(qh, qh->qhmem.tempstack), set, qh_setsize(qh, set));+} /* settemppush */+++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="settruncate">-</a>++ qh_settruncate(qh, set, size )+ truncate set to size elements++ notes:+ set must be defined++ see:+ SETtruncate_++ design:+ check size+ update actual size of set+*/+void qh_settruncate(qhT *qh, setT *set, int size) {++ if (size < 0 || size > set->maxsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ set->e[set->maxsize].i= size+1; /* maybe overwritten */+ set->e[size].p= NULL;+} /* settruncate */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setunique">-</a>++ qh_setunique(qh, set, elem )+ add elem to unsorted set unless it is already in set++ notes:+ returns 1 if it is appended++ design:+ if elem not in set+ append elem to set+*/+int qh_setunique(qhT *qh, setT **set, void *elem) {++ if (!qh_setin(*set, elem)) {+ qh_setappend(qh, set, elem);+ return 1;+ }+ return 0;+} /* setunique */++/*-<a href="qh-set_r.htm#TOC"+ >-------------------------------<a name="setzero">-</a>++ qh_setzero(qh, set, index, size )+ zero elements from index on+ set actual size of set to size++ notes:+ set must be defined+ the set becomes an indexed set (can not use FOREACH...)++ see also:+ qh_settruncate++ design:+ check index and size+ update actual size+ zero elements starting at e[index]+*/+void qh_setzero(qhT *qh, setT *set, int idx, int size) {+ int count;++ if (idx < 0 || idx >= size || size > set->maxsize) {+ qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);+ qh_setprint(qh, qh->qhmem.ferr, "", set);+ qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);+ }+ set->e[set->maxsize].i= size+1; /* may be overwritten */+ count= size - idx + 1; /* +1 for NULL terminator */+ memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);+} /* setzero */++
+ Cdir/random_r.c view
@@ -0,0 +1,247 @@+/*<html><pre> -<a href="index_r.htm#TOC"+ >-------------------------------</a><a name="TOP">-</a>++ random_r.c and utilities+ Park & Miller's minimimal standard random number generator+ argc/argv conversion++ Used by rbox. Do not use 'qh' +*/++#include "libqhull_r.h"+#include "random_r.h"++#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */+#pragma warning( disable : 4706) /* assignment within conditional function */+#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */+#endif++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="argv_to_command">-</a>++ qh_argv_to_command(argc, argv, command, max_size )++ build command from argc/argv+ max_size is at least++ returns:+ a space-delimited string of options (just as typed)+ returns false if max_size is too short++ notes:+ silently removes+ makes option string easy to input and output+ matches qh_argv_to_command_size()++ argc may be 0+*/+int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {+ int i, remaining;+ char *s;+ *command= '\0'; /* max_size > 0 */++ if (argc) {+ if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */+ || (s= strrchr( argv[0], '/')))+ s++;+ else+ s= argv[0];+ if ((int)strlen(s) < max_size) /* WARN64 */+ strcpy(command, s);+ else+ goto error_argv;+ if ((s= strstr(command, ".EXE"))+ || (s= strstr(command, ".exe")))+ *s= '\0';+ }+ for (i=1; i < argc; i++) {+ s= argv[i];+ remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2; /* WARN64 */+ if (!*s || strchr(s, ' ')) {+ char *t= command + strlen(command);+ remaining -= 2;+ if (remaining < 0) {+ goto error_argv;+ }+ *t++= ' ';+ *t++= '"';+ while (*s) {+ if (*s == '"') {+ if (--remaining < 0)+ goto error_argv;+ *t++= '\\';+ }+ *t++= *s++;+ }+ *t++= '"';+ *t= '\0';+ }else if (remaining < 0) {+ goto error_argv;+ }else+ strcat(command, " ");+ strcat(command, s);+ }+ return 1;++error_argv:+ return 0;+} /* argv_to_command */++/*-<a href="qh-globa_r.htm#TOC"+>-------------------------------</a><a name="argv_to_command_size">-</a>++qh_argv_to_command_size(argc, argv )++ return size to allocate for qh_argv_to_command()++notes:+ argc may be 0+ actual size is usually shorter+*/+int qh_argv_to_command_size(int argc, char *argv[]) {+ unsigned int count= 1; /* null-terminator if argc==0 */+ int i;+ char *s;++ for (i=0; i<argc; i++){+ count += (int)strlen(argv[i]) + 1; /* WARN64 */+ if (i>0 && strchr(argv[i], ' ')) {+ count += 2; /* quote delimiters */+ for (s=argv[i]; *s; s++) {+ if (*s == '"') {+ count++;+ }+ }+ }+ }+ return count;+} /* argv_to_command_size */++/*-<a href="qh-geom_r.htm#TOC"+ >-------------------------------</a><a name="rand">-</a>++ qh_rand()+ qh_srand(qh, seed )+ generate pseudo-random number between 1 and 2^31 -2++ notes:+ For qhull and rbox, called from qh_RANDOMint(),etc. [user.h]++ From Park & Miller's minimal standard random number generator+ Communications of the ACM, 31:1192-1201, 1988.+ Does not use 0 or 2^31 -1+ this is silently enforced by qh_srand()+ Can make 'Rn' much faster by moving qh_rand to qh_distplane+*/++/* Global variables and constants */++#define qh_rand_a 16807+#define qh_rand_m 2147483647+#define qh_rand_q 127773 /* m div a */+#define qh_rand_r 2836 /* m mod a */++int qh_rand(qhT *qh) {+ int lo, hi, test;+ int seed = qh->last_random;++ hi = seed / qh_rand_q; /* seed div q */+ lo = seed % qh_rand_q; /* seed mod q */+ test = qh_rand_a * lo - qh_rand_r * hi;+ if (test > 0)+ seed= test;+ else+ seed= test + qh_rand_m;+ qh->last_random= seed;+ /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */+ /* seed = qh_RANDOMmax; for testing */+ return seed;+} /* rand */++void qh_srand(qhT *qh, int seed) {+ if (seed < 1)+ qh->last_random= 1;+ else if (seed >= qh_rand_m)+ qh->last_random= qh_rand_m - 1;+ else+ qh->last_random= seed;+} /* qh_srand */++/*-<a href="qh-geom_r.htm#TOC"+>-------------------------------</a><a name="randomfactor">-</a>++qh_randomfactor(qh, scale, offset )+ return a random factor r * scale + offset++notes:+ qh.RANDOMa/b are defined in global_r.c+ qh_RANDOMint requires 'qh'+*/+realT qh_randomfactor(qhT *qh, realT scale, realT offset) {+ realT randr;++ randr= qh_RANDOMint;+ return randr * scale + offset;+} /* randomfactor */++/*-<a href="qh-geom_r.htm#TOC"+>-------------------------------</a><a name="randommatrix">-</a>++qh_randommatrix(qh, buffer, dim, rows )+ generate a random dim X dim matrix in range [-1,1]+ assumes buffer is [dim+1, dim]++ returns:+ sets buffer to random numbers+ sets rows to rows of buffer+ sets row[dim] as scratch row++ notes:+ qh_RANDOMint requires 'qh'+*/+void qh_randommatrix(qhT *qh, realT *buffer, int dim, realT **rows) {+ int i, k;+ realT **rowi, *coord, realr;++ coord= buffer;+ rowi= rows;+ for (i=0; i < dim; i++) {+ *(rowi++)= coord;+ for (k=0; k < dim; k++) {+ realr= qh_RANDOMint;+ *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;+ }+ }+ *rowi= coord;+} /* randommatrix */++/*-<a href="qh-globa_r.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); /* WARN64 */+ if (s< (*endp) && (*endp)[-1] == ' ')+ (*endp)--;+ return result;+} /* strtol */
+ Cdir/stat_r.c view
@@ -0,0 +1,682 @@+/*<html><pre> -<a href="qh-stat_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ stat_r.c+ contains all statistics that are collected for qhull++ see qh-stat_r.htm and stat_r.h++ Copyright (c) 1993-2015 The Geometry Center.+ $Id: //main/2015/qhull/src/libqhull_r/stat_r.c#5 $$Change: 2062 $+ $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $+*/++#include "qhull_ra.h"++/*========== functions in alphabetic order ================*/++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="allstatA">-</a>++ qh_allstatA()+ define statistics in groups of 20++ notes:+ (otherwise, 'gcc -O2' uses too much memory)+ uses qhstat.next+*/+void qh_allstatA(qhT *qh) {++ /* zdef_(type,name,doc,average) */+ zzdef_(zdoc, Zdoc2, "precision statistics", -1);+ zdef_(zinc, Znewvertex, NULL, -1);+ zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex);+ zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);+ zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);+ zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);+ zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);++ qh->qhstat.precision= qh->qhstat.next; /* call qh_precision for each of these */+ zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);+ zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);+ zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);+ zzdef_(zinc, Zflippedfacets, "flipped facets", -1);+ zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);+ zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);+ zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);+ zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);+ zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);+ zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);+ zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);+}+void qh_allstatB(qhT *qh) {+ zzdef_(zdoc, Zdoc1, "summary information", -1);+ zdef_(zinc, Zvertices, "number of vertices in output", -1);+ zdef_(zinc, Znumfacets, "number of facets in output", -1);+ zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);+ zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);+ zdef_(zinc, Znumridges, "number of ridges in output", -1);+ zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);+ zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);+ zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);+ zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);+ zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);+ zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);+ zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);+ zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);+ zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);+ zdef_(zinc, Ztotvertices, "vertices created altogether", -1);+ zzdef_(zinc, Zsetplane, "facets created altogether", -1);+ zdef_(zinc, Ztotridges, "ridges created altogether", -1);+ zdef_(zinc, Zpostfacets, "facets before post merge", -1);+ zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets);+ zdef_(zmax, Znummergemax, " maximum merges for a facet(at most 511)", -1);+ zdef_(zinc, Zangle, NULL, -1);+ zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle);+ zdef_(wmax, Wanglemax, " maximum angle(cosine) of facet normals across a ridge", -1);+ zdef_(wmin, Wanglemin, " minimum angle(cosine) of facet normals across a ridge", -1);+ zdef_(wadd, Wareatot, "total area of facets", -1);+ zdef_(wmax, Wareamax, " maximum facet area", -1);+ zdef_(wmin, Wareamin, " minimum facet area", -1);+}+void qh_allstatC(qhT *qh) {+ zdef_(zdoc, Zdoc9, "build hull statistics", -1);+ zzdef_(zinc, Zprocessed, "points processed", -1);+ zzdef_(zinc, Zretry, "retries due to precision problems", -1);+ zdef_(wmax, Wretrymax, " max. random joggle", -1);+ zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);+ zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);+ zdef_(zinc, Zinsidevisible, " ave. visible facets without an horizon neighbor", Zprocessed);+ zdef_(zadd, Zvisfacettot, " ave. facets deleted per iteration", Zprocessed);+ zdef_(zmax, Zvisfacetmax, " maximum", -1);+ zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);+ zdef_(zmax, Zvisvertexmax, " maximum", -1);+ zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);+ zdef_(zadd, Znewfacettot, "ave. new or merged facets per iteration", Zprocessed);+ zdef_(zmax, Znewfacetmax, " maximum(includes initial simplex)", -1);+ zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);+ zdef_(wadd, Wnewbalance2, " standard deviation", -1);+ zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);+ zdef_(wadd, Wpbalance2, " standard deviation", -1);+ zdef_(zinc, Zpbalance, " number of trials", -1);+ zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);+ zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1);+ zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);+ zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1);+ zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1);+ zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1);+ zdef_(zinc, Zgoodfacet, "good facets found", -1);+ zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);+ zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);+ zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);+ zzdef_(zinc, Zcheckpart, " ave. distance tests per check", Ztotcheck);+}+void qh_allstatD(qhT *qh) {+ zdef_(zinc, Zvisit, "resets of visit_id", -1);+ zdef_(zinc, Zvvisit, " resets of vertex_visit", -1);+ zdef_(zmax, Zvisit2max, " max visit_id/2", -1);+ zdef_(zmax, Zvvisit2max, " max vertex_visit/2", -1);++ zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1);+ zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);+ zdef_(zmax, Zdelvertexmax, " maximum vertices deleted per iteration", -1);+ zdef_(zinc, Zfindbest, "calls to findbest", -1);+ zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);+ zdef_(zmax, Zfindbestmax, " max. facets tested", -1);+ zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);+ zdef_(zinc, Zfindnew, "calls to findbestnew", -1);+ zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);+ zdef_(zmax, Zfindnewmax, " max. facets tested", -1);+ zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);+ zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);+ zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);+ zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);+ zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);+ zdef_(zinc, Zfindjump, " ave. clearly better", Zfindhorizon);+ zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);+ zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);+ zdef_(zinc, Zpartflip, " repartitioned coplanar points for flipped orientation", -1);+}+void qh_allstatE(qhT *qh) {+ zdef_(zinc, Zpartinside, "inside points", -1);+ zdef_(zinc, Zpartnear, " inside points kept with a facet", -1);+ zdef_(zinc, Zcoplanarinside, " inside points that were coplanar with a facet", -1);+ zdef_(zinc, Zbestlower, "calls to findbestlower", -1);+ zdef_(zinc, Zbestlowerv, " with search of vertex neighbors", -1);+ zdef_(zinc, Zbestlowerall, " with rare search of all facets", -1);+ zdef_(zmax, Zbestloweralln, " facets per search of all facets", -1);+ zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);+ zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);+ zdef_(zinc, Ztotpartition, "partitions of a point", -1);+ zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);+ zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);+ zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);+ zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);+ zdef_(zinc, Zdistio, "distance tests for output", -1);+ zdef_(zinc, Zdiststat, "distance tests for statistics", -1);+ zdef_(zinc, Zdistplane, "total number of distance tests", -1);+ zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);+ zzdef_(zinc, Zpartcoplanar, " distance tests for these partitions", -1);+ zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);+}+void qh_allstatE2(qhT *qh) {+ zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);+ zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);+ zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);+ zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1);+ zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);+ zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);+ zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);++ zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);+ zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);+ zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);+ zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);+ zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);+ zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);+ zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);+ zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);+ zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);+}+void qh_allstatF(qhT *qh) {+ zdef_(zdoc, Zdoc7, "statistics for merging", -1);+ zdef_(zinc, Zpremergetot, "merge iterations", -1);+ zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);+ zdef_(zadd, Zmergeinitmax, " maximum", -1);+ zdef_(zadd, Zmergesettot, " ave. additional non-convex ridges per iteration", Zpremergetot);+ zdef_(zadd, Zmergesetmax, " maximum additional in one pass", -1);+ zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);+ zdef_(zadd, Zmergesettot2, " additional non-convex ridges", -1);+ zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1);+ zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1);+ zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);+ zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);+ zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);+ zdef_(zinc, Zmergesimplex, "merged a simplex", -1);+ zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);+ zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);+ zzdef_(zadd, Zcyclefacettot, " ave. facets per cycle", Zcyclehorizon);+ zdef_(zmax, Zcyclefacetmax, " max. facets", -1);+ zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);+ zdef_(zinc, Zmergenew, "new facets merged", -1);+ zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);+ zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);+ zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);+ zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);+ zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);+ zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);+ zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);+}+void qh_allstatG(qhT *qh) {+ zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);+ zdef_(wadd, Wacoplanartot, " average merge distance", Zacoplanar);+ zdef_(wmax, Wacoplanarmax, " maximum merge distance", -1);+ zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);+ zdef_(wadd, Wcoplanartot, " average merge distance", Zcoplanar);+ zdef_(wmax, Wcoplanarmax, " maximum merge distance", -1);+ zdef_(zinc, Zconcave, "merges due to concave facets", -1);+ zdef_(wadd, Wconcavetot, " average merge distance", Zconcave);+ zdef_(wmax, Wconcavemax, " maximum merge distance", -1);+ zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);+ zdef_(wadd, Wavoidoldtot, " average merge distance", Zavoidold);+ zdef_(wmax, Wavoidoldmax, " maximum merge distance", -1);+ zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);+ zdef_(wadd, Wdegentot, " average merge distance", Zdegen);+ zdef_(wmax, Wdegenmax, " maximum merge distance", -1);+ zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);+ zdef_(wadd, Wflippedtot, " average merge distance", Zflipped);+ zdef_(wmax, Wflippedmax, " maximum merge distance", -1);+ zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);+ zdef_(wadd, Wduplicatetot, " average merge distance", Zduplicate);+ zdef_(wmax, Wduplicatemax, " maximum merge distance", -1);+}+void qh_allstatH(qhT *qh) {+ zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);+ zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);+ zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);+ zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);+ zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);+ zdef_(zinc, Zdupridge, " duplicate ridges detected", -1);+ zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);+ zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);+ zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);+ zdef_(zinc, Zdelfacetdup, " facets deleted because of no neighbors", -1);+ zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);+ zdef_(zinc, Zremvertexdel, " deleted", -1);+ zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);+ zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);+ zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);+ zdef_(zadd, Zintersecttot, " ave. number found per vertex", Zintersect);+ zdef_(zmax, Zintersectmax, " max. found for a vertex", -1);+ zdef_(zinc, Zvertexridge, NULL, -1);+ zdef_(zadd, Zvertexridgetot, " ave. number of ridges per tested vertex", Zvertexridge);+ zdef_(zmax, Zvertexridgemax, " max. number of ridges per tested vertex", -1);++ zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1);+ zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);+ zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);+ zdef_(zadd, Zmempoints, "for input points, outside and coplanar sets, and qhT",-1);+ zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);+} /* allstat */++void qh_allstatI(qhT *qh) {+ qh->qhstat.vridges= qh->qhstat.next;+ zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);+ zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);+ zzdef_(wadd, Wridge, " ave. distance to ridge", Zridge);+ zzdef_(wmax, Wridgemax, " max. distance to ridge", -1);+ zzdef_(zinc, Zridgemid, "bounded ridges", -1);+ zzdef_(wadd, Wridgemid, " ave. distance of midpoint to ridge", Zridgemid);+ zzdef_(wmax, Wridgemidmax, " max. distance of midpoint to ridge", -1);+ zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);+ zzdef_(wadd, Wridgeok, " ave. angle to ridge", Zridgeok);+ zzdef_(wmax, Wridgeokmax, " max. angle to ridge", -1);+ zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);+ zzdef_(wadd, Wridge0, " ave. angle to ridge", Zridge0);+ zzdef_(wmax, Wridge0max, " max. angle to ridge", -1);++ zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1);+ zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);+ zdef_(zadd, Ztricoplanartot, " ave. new facets created(may be deleted)", Ztricoplanar);+ zdef_(zmax, Ztricoplanarmax, " max. new facets created", -1);+ zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1);+ zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1);+ zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1);+} /* allstat */++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="allstatistics">-</a>++ qh_allstatistics()+ reset printed flag for all statistics+*/+void qh_allstatistics(qhT *qh) {+ int i;++ for(i=ZEND; i--; )+ qh->qhstat.printed[i]= False;+} /* allstatistics */++#if qh_KEEPstatistics+/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="collectstatistics">-</a>++ qh_collectstatistics()+ collect statistics for qh.facet_list++*/+void qh_collectstatistics(qhT *qh) {+ facetT *facet, *neighbor, **neighborp;+ vertexT *vertex, **vertexp;+ realT dotproduct, dist;+ int sizneighbors, sizridges, sizvertices, i;++ qh->old_randomdist= qh->RANDOMdist;+ qh->RANDOMdist= False;+ zval_(Zmempoints)= qh->num_points * qh->normal_size + sizeof(qhT);+ zval_(Zmemfacets)= 0;+ zval_(Zmemridges)= 0;+ zval_(Zmemvertices)= 0;+ zval_(Zangle)= 0;+ wval_(Wangle)= 0.0;+ zval_(Znumridges)= 0;+ zval_(Znumfacets)= 0;+ zval_(Znumneighbors)= 0;+ zval_(Znumvertices)= 0;+ zval_(Znumvneighbors)= 0;+ zval_(Znummergetot)= 0;+ zval_(Znummergemax)= 0;+ zval_(Zvertices)= qh->num_vertices - qh_setsize(qh, qh->del_vertices);+ if (qh->MERGING || qh->APPROXhull || qh->JOGGLEmax < REALmax/2)+ wmax_(Wmaxoutside, qh->max_outside);+ if (qh->MERGING)+ wmin_(Wminvertex, qh->min_vertex);+ FORALLfacets+ facet->seen= False;+ if (qh->DELAUNAY) {+ FORALLfacets {+ if (facet->upperdelaunay != qh->UPPERdelaunay)+ facet->seen= True; /* remove from angle statistics */+ }+ }+ FORALLfacets {+ if (facet->visible && qh->NEWfacets)+ continue;+ sizvertices= qh_setsize(qh, facet->vertices);+ sizneighbors= qh_setsize(qh, facet->neighbors);+ sizridges= qh_setsize(qh, facet->ridges);+ zinc_(Znumfacets);+ zadd_(Znumvertices, sizvertices);+ zmax_(Zmaxvertices, sizvertices);+ zadd_(Znumneighbors, sizneighbors);+ zmax_(Zmaxneighbors, sizneighbors);+ zadd_(Znummergetot, facet->nummerge);+ i= facet->nummerge; /* avoid warnings */+ zmax_(Znummergemax, i);+ if (!facet->simplicial) {+ if (sizvertices == qh->hull_dim) {+ zinc_(Znowsimplicial);+ }else {+ zinc_(Znonsimplicial);+ }+ }+ if (sizridges) {+ zadd_(Znumridges, sizridges);+ zmax_(Zmaxridges, sizridges);+ }+ zadd_(Zmemfacets, sizeof(facetT) + qh->normal_size + 2*sizeof(setT)+ + SETelemsize * (sizneighbors + sizvertices));+ if (facet->ridges) {+ zadd_(Zmemridges,+ sizeof(setT) + SETelemsize * sizridges + sizridges *+ (sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh->hull_dim-1))/2);+ }+ if (facet->outsideset)+ zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->outsideset));+ if (facet->coplanarset)+ zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(qh, facet->coplanarset));+ if (facet->seen) /* Delaunay upper envelope */+ continue;+ facet->seen= True;+ FOREACHneighbor_(facet) {+ if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge+ || neighbor->seen || !facet->normal || !neighbor->normal)+ continue;+ dotproduct= qh_getangle(qh, facet->normal, neighbor->normal);+ zinc_(Zangle);+ wadd_(Wangle, dotproduct);+ wmax_(Wanglemax, dotproduct)+ wmin_(Wanglemin, dotproduct)+ }+ if (facet->normal) {+ FOREACHvertex_(facet->vertices) {+ zinc_(Zdiststat);+ qh_distplane(qh, vertex->point, facet, &dist);+ wmax_(Wvertexmax, dist);+ wmin_(Wvertexmin, dist);+ }+ }+ }+ FORALLvertices {+ if (vertex->deleted)+ continue;+ zadd_(Zmemvertices, sizeof(vertexT));+ if (vertex->neighbors) {+ sizneighbors= qh_setsize(qh, vertex->neighbors);+ zadd_(Znumvneighbors, sizneighbors);+ zmax_(Zmaxvneighbors, sizneighbors);+ zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors);+ }+ }+ qh->RANDOMdist= qh->old_randomdist;+} /* collectstatistics */+#endif /* qh_KEEPstatistics */++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="initstatistics">-</a>++ qh_initstatistics(qh)+ initialize statistics++ notes:+ NOerrors -- qh_initstatistics can not use qh_errexit(), qh_fprintf, or qh.ferr+ On first call, only qhmem.ferr is defined. qh_memalloc is not setup.+ Also invoked by QhullQh().+*/+void qh_initstatistics(qhT *qh) {+ int i;+ realT realx;+ int intx;++ qh->qhstat.next= 0;+ qh_allstatA(qh);+ qh_allstatB(qh);+ qh_allstatC(qh);+ qh_allstatD(qh);+ qh_allstatE(qh);+ qh_allstatE2(qh);+ qh_allstatF(qh);+ qh_allstatG(qh);+ qh_allstatH(qh);+ qh_allstatI(qh);+ if (qh->qhstat.next > (int)sizeof(qh->qhstat.id)) {+ qh_fprintf(qh, qh->qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\+ qhstat.next %d should be <= sizeof(qh->qhstat.id) %d\n", qh->qhstat.next, (int)sizeof(qh->qhstat.id));+#if 0 /* for locating error, Znumridges should be duplicated */+ for(i=0; i < ZEND; i++) {+ int j;+ for(j=i+1; j < ZEND; j++) {+ if (qh->qhstat.id[i] == qh->qhstat.id[j]) {+ qh_fprintf(qh, qh->qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",+ qh->qhstat.id[i], i, j);+ }+ }+ }+#endif+ qh_exit(qh_ERRqhull); /* can not use qh_errexit() */+ }+ qh->qhstat.init[zinc].i= 0;+ qh->qhstat.init[zadd].i= 0;+ qh->qhstat.init[zmin].i= INT_MAX;+ qh->qhstat.init[zmax].i= INT_MIN;+ qh->qhstat.init[wadd].r= 0;+ qh->qhstat.init[wmin].r= REALmax;+ qh->qhstat.init[wmax].r= -REALmax;+ for(i=0; i < ZEND; i++) {+ if (qh->qhstat.type[i] > ZTYPEreal) {+ realx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r;+ qh->qhstat.stats[i].r= realx;+ }else if (qh->qhstat.type[i] != zdoc) {+ intx= qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i;+ qh->qhstat.stats[i].i= intx;+ }+ }+} /* initstatistics */++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="newstats">-</a>++ qh_newstats(qh, )+ returns True if statistics for zdoc++ returns:+ next zdoc+*/+boolT qh_newstats(qhT *qh, int idx, int *nextindex) {+ boolT isnew= False;+ int start, i;++ if (qh->qhstat.type[qh->qhstat.id[idx]] == zdoc)+ start= idx+1;+ else+ start= idx;+ for(i= start; i < qh->qhstat.next && qh->qhstat.type[qh->qhstat.id[i]] != zdoc; i++) {+ if (!qh_nostatistic(qh, qh->qhstat.id[i]) && !qh->qhstat.printed[qh->qhstat.id[i]])+ isnew= True;+ }+ *nextindex= i;+ return isnew;+} /* newstats */++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="nostatistic">-</a>++ qh_nostatistic(qh, index )+ true if no statistic to print+*/+boolT qh_nostatistic(qhT *qh, int i) {++ if ((qh->qhstat.type[i] > ZTYPEreal+ &&qh->qhstat.stats[i].r == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].r)+ || (qh->qhstat.type[i] < ZTYPEreal+ &&qh->qhstat.stats[i].i == qh->qhstat.init[(unsigned char)(qh->qhstat.type[i])].i))+ return True;+ return False;+} /* nostatistic */++#if qh_KEEPstatistics+/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="printallstatistics">-</a>++ qh_printallstatistics(qh, fp, string )+ print all statistics with header 'string'+*/+void qh_printallstatistics(qhT *qh, FILE *fp, const char *string) {++ qh_allstatistics(qh);+ qh_collectstatistics(qh);+ qh_printstatistics(qh, fp, string);+ qh_memstatistics(qh, fp);+}+++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="printstatistics">-</a>++ qh_printstatistics(qh, fp, string )+ print statistics to a file with header 'string'+ skips statistics with qhstat.printed[] (reset with qh_allstatistics)++ see:+ qh_printallstatistics()+*/+void qh_printstatistics(qhT *qh, FILE *fp, const char *string) {+ int i, k;+ realT ave;++ if (qh->num_points != qh->num_vertices) {+ wval_(Wpbalance)= 0;+ wval_(Wpbalance2)= 0;+ }else+ wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),+ wval_(Wpbalance2), &ave);+ wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),+ wval_(Wnewbalance2), &ave);+ qh_fprintf(qh, fp, 9350, "\n\+%s\n\+ qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh->rbox_command,+ qh->qhull_command, qh_version, qh->qhull_options);+ qh_fprintf(qh, fp, 9351, "\nprecision constants:\n\+ %6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\+ %6.2g max. roundoff error for distance computation('En')\n\+ %6.2g max. roundoff error for angle computations\n\+ %6.2g min. distance for outside points ('Wn')\n\+ %6.2g min. distance for visible facets ('Vn')\n\+ %6.2g max. distance for coplanar facets ('Un')\n\+ %6.2g max. facet width for recomputing centrum and area\n\+",+ qh->MAXabs_coord, qh->DISTround, qh->ANGLEround, qh->MINoutside,+ qh->MINvisible, qh->MAXcoplanar, qh->WIDEfacet);+ if (qh->KEEPnearinside)+ qh_fprintf(qh, fp, 9352, "\+ %6.2g max. distance for near-inside points\n", qh->NEARinside);+ if (qh->premerge_cos < REALmax/2) qh_fprintf(qh, fp, 9353, "\+ %6.2g max. cosine for pre-merge angle\n", qh->premerge_cos);+ if (qh->PREmerge) qh_fprintf(qh, fp, 9354, "\+ %6.2g radius of pre-merge centrum\n", qh->premerge_centrum);+ if (qh->postmerge_cos < REALmax/2) qh_fprintf(qh, fp, 9355, "\+ %6.2g max. cosine for post-merge angle\n", qh->postmerge_cos);+ if (qh->POSTmerge) qh_fprintf(qh, fp, 9356, "\+ %6.2g radius of post-merge centrum\n", qh->postmerge_centrum);+ qh_fprintf(qh, fp, 9357, "\+ %6.2g max. distance for merging two simplicial facets\n\+ %6.2g max. roundoff error for arithmetic operations\n\+ %6.2g min. denominator for divisions\n\+ zero diagonal for Gauss: ", qh->ONEmerge, REALepsilon, qh->MINdenom);+ for(k=0; k < qh->hull_dim; k++)+ qh_fprintf(qh, fp, 9358, "%6.2e ", qh->NEARzero[k]);+ qh_fprintf(qh, fp, 9359, "\n\n");+ for(i=0 ; i < qh->qhstat.next; )+ qh_printstats(qh, fp, i, &i);+} /* printstatistics */+#endif /* qh_KEEPstatistics */++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="printstatlevel">-</a>++ qh_printstatlevel(qh, fp, id )+ print level information for a statistic++ notes:+ nop if id >= ZEND, printed, or same as initial value+*/+void qh_printstatlevel(qhT *qh, FILE *fp, int id) {+#define NULLfield " "++ if (id >= ZEND || qh->qhstat.printed[id])+ return;+ if (qh->qhstat.type[id] == zdoc) {+ qh_fprintf(qh, fp, 9360, "%s\n", qh->qhstat.doc[id]);+ return;+ }+ if (qh_nostatistic(qh, id) || !qh->qhstat.doc[id])+ return;+ qh->qhstat.printed[id]= True;+ if (qh->qhstat.count[id] != -1+ && qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i == 0)+ qh_fprintf(qh, fp, 9361, " *0 cnt*");+ else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] == -1)+ qh_fprintf(qh, fp, 9362, "%7.2g", qh->qhstat.stats[id].r);+ else if (qh->qhstat.type[id] >= ZTYPEreal && qh->qhstat.count[id] != -1)+ qh_fprintf(qh, fp, 9363, "%7.2g", qh->qhstat.stats[id].r/ qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);+ else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] == -1)+ qh_fprintf(qh, fp, 9364, "%7d", qh->qhstat.stats[id].i);+ else if (qh->qhstat.type[id] < ZTYPEreal && qh->qhstat.count[id] != -1)+ qh_fprintf(qh, fp, 9365, "%7.3g", (realT) qh->qhstat.stats[id].i / qh->qhstat.stats[(unsigned char)(qh->qhstat.count[id])].i);+ qh_fprintf(qh, fp, 9366, " %s\n", qh->qhstat.doc[id]);+} /* printstatlevel */+++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="printstats">-</a>++ qh_printstats(qh, fp, index, nextindex )+ print statistics for a zdoc group++ returns:+ next zdoc if non-null+*/+void qh_printstats(qhT *qh, FILE *fp, int idx, int *nextindex) {+ int j, nexti;++ if (qh_newstats(qh, idx, &nexti)) {+ qh_fprintf(qh, fp, 9367, "\n");+ for (j=idx; j<nexti; j++)+ qh_printstatlevel(qh, fp, qh->qhstat.id[j]);+ }+ if (nextindex)+ *nextindex= nexti;+} /* printstats */++#if qh_KEEPstatistics++/*-<a href="qh-stat_r.htm#TOC"+ >-------------------------------</a><a name="stddev">-</a>++ qh_stddev(num, tot, tot2, ave )+ compute the standard deviation and average from statistics++ tot2 is the sum of the squares+ notes:+ computes r.m.s.:+ (x-ave)^2+ == x^2 - 2x tot/num + (tot/num)^2+ == tot2 - 2 tot tot/num + tot tot/num+ == tot2 - tot ave+*/+realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {+ realT stddev;++ *ave= tot/num;+ stddev= sqrt(tot2/num - *ave * *ave);+ return stddev;+} /* stddev */++#endif /* qh_KEEPstatistics */++#if !qh_KEEPstatistics+void qh_collectstatistics(qhT *qh) {}+void qh_printallstatistics(qhT *qh, FILE *fp, char *string) {};+void qh_printstatistics(qhT *qh, FILE *fp, char *string) {}+#endif+
+ Cdir/user_r.c view
@@ -0,0 +1,527 @@+/*<html><pre> -<a href="qh-user_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ user.c+ user redefinable functions++ see user2_r.c for qh_fprintf, qh_malloc, qh_free++ see README.txt see COPYING.txt for copyright information.++ see libqhull_r.h for data structures, macros, and user-callable functions.++ see user_eg.c, user_eg2.c, and unix.c for examples.++ see user.h for user-definable constants++ use qh_NOmem in mem_r.h to turn off memory management+ use qh_NOmerge in user.h to turn off facet merging+ set qh_KEEPstatistics in user.h to 0 to turn off statistics++ This is unsupported software. You're welcome to make changes,+ but you're on your own if something goes wrong. Use 'Tc' to+ check frequently. Usually qhull will report an error if+ a data structure becomes inconsistent. If so, it also reports+ the last point added to the hull, e.g., 102. You can then trace+ the execution of qhull with "T4P102".++ Please report any errors that you fix to qhull@qhull.org++ Qhull-template is a template for calling qhull from within your application++ if you recompile and load this module, then user.o will not be loaded+ from qhull.a++ you can add additional quick allocation sizes in qh_user_memsizes++ if the other functions here are redefined to not use qh_print...,+ then io.o will not be loaded from qhull.a. See user_eg_r.c for an+ example. We recommend keeping io.o for the extra debugging+ information it supplies.+*/++#include "qhull_ra.h"++#include <stdarg.h>++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="qhull_template">-</a>++ Qhull-template+ Template for calling qhull from inside your program++ returns:+ exit code(see qh_ERR... in libqhull_r.h)+ all memory freed++ notes:+ This can be called any number of times.++*/+#if 0+{+ int dim; /* dimension of points */+ int numpoints; /* number of points */+ coordT *points; /* array of coordinates for each point */+ boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */+ char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */+ FILE *outfile= stdout; /* output from qh_produce_output(qh)+ use NULL to skip qh_produce_output(qh) */+ FILE *errfile= stderr; /* error messages from qhull code */+ int exitcode; /* 0 if no error from qhull */+ facetT *facet; /* set by FORALLfacets */+ int curlong, totlong; /* memory remaining after qh_memfreeshort */++ qhT qh_qh; /* Qhull's data structure. First argument of most calls */+ qhT *qh= &qh_qh; /* Alternatively -- qhT *qh= (qhT*)malloc(sizeof(qhT)) */++ QHULL_LIB_CHECK /* Check for compatible library */++ qh_zero(qh, errfile);++ /* initialize dim, numpoints, points[], ismalloc here */+ exitcode= qh_new_qhull(qh, dim, numpoints, points, ismalloc,+ flags, outfile, errfile);+ if (!exitcode) { /* if no error */+ /* 'qh->facet_list' contains the convex hull */+ FORALLfacets {+ /* ... your code ... */+ }+ }+ qh_freeqhull(qh, !qh_ALL);+ qh_memfreeshort(qh, &curlong, &totlong);+ if (curlong || totlong)+ qh_fprintf(qh, errfile, 7068, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);+}+#endif++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="new_qhull">-</a>++ qh_new_qhull(qh, dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )+ Run qhull and return results in qh.+ Returns exitcode (0 if no errors).+ Before first call, either call qh_zero(qh, errfile), or set qh to all zero.++ notes:+ do not modify points until finished with results.+ The qhull data structure contains pointers into the points array.+ do not call qhull functions before qh_new_qhull().+ The qhull data structure is not initialized until qh_new_qhull().+ do not call qh_init_A (global_r.c)++ Default errfile is stderr, outfile may be null+ qhull_cmd must start with "qhull "+ projects points to a new point array for Delaunay triangulations ('d' and 'v')+ transforms points into a new point array for halfspace intersection ('H')++ see:+ Qhull-template at the beginning of this file.+ An example of using qh_new_qhull is user_eg_r.c+*/+int qh_new_qhull(qhT *qh, int dim, int numpoints, coordT *points, boolT ismalloc,+ char *qhull_cmd, FILE *outfile, FILE *errfile) {+ /* gcc may issue a "might be clobbered" warning for dim, points, and ismalloc [-Wclobbered].+ These parameters are not referenced after a longjmp() and hence not clobbered.+ See http://stackoverflow.com/questions/7721854/what-sense-do-these-clobbered-variable-warnings-make */+ int exitcode, hulldim;+ boolT new_ismalloc;+ coordT *new_points;++ if(!errfile){+ errfile= stderr;+ }+ if (!qh->qhmem.ferr) {+ qh_meminit(qh, errfile);+ } else {+ qh_memcheck(qh);+ }+ if (strncmp(qhull_cmd, "qhull ", (size_t)6)) {+ qh_fprintf(qh, errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \"\n");+ return qh_ERRinput;+ }+ qh_initqhull_start(qh, NULL, outfile, errfile);+ trace1((qh, qh->ferr, 1044, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));+ exitcode = setjmp(qh->errexit);+ if (!exitcode)+ {+ qh->NOerrexit = False;+ qh_initflags(qh, qhull_cmd);+ if (qh->DELAUNAY)+ qh->PROJECTdelaunay= True;+ if (qh->HALFspace) {+ /* points is an array of halfspaces,+ the last coordinate of each halfspace is its offset */+ hulldim= dim-1;+ qh_setfeasible(qh, hulldim);+ new_points= qh_sethalfspace_all(qh, dim, numpoints, points, qh->feasible_point);+ new_ismalloc= True;+ if (ismalloc)+ qh_free(points);+ }else {+ hulldim= dim;+ new_points= points;+ new_ismalloc= ismalloc;+ }+ qh_init_B(qh, new_points, numpoints, hulldim, new_ismalloc);+ qh_qhull(qh);+ qh_check_output(qh);+ if (outfile) {+ qh_produce_output(qh);+ }else {+ qh_prepare_output(qh);+ }+ if (qh->VERIFYoutput && !qh->STOPpoint && !qh->STOPcone)+ qh_check_points(qh);+ }+ qh->NOerrexit = True;+ return exitcode;+} /* new_qhull */++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="errexit">-</a>++ qh_errexit(qh, exitcode, facet, ridge )+ report and exit from an error+ report facet and ridge if non-NULL+ reports useful information such as last point processed+ set qh.FORCEoutput to print neighborhood of facet++ see:+ qh_errexit2() in libqhull_r.c for printing 2 facets++ design:+ check for error within error processing+ compute qh.hulltime+ print facet and ridge (if any)+ report commandString, options, qh.furthest_id+ print summary and statistics (including precision statistics)+ if qh_ERRsingular+ print help text for singular data set+ exit program via long jump (if defined) or exit()+*/+void qh_errexit(qhT *qh, int exitcode, facetT *facet, ridgeT *ridge) {++ if (qh->ERREXITcalled) {+ qh_fprintf(qh, qh->ferr, 8126, "\nqhull error while processing previous error. Exit program\n");+ qh_exit(qh_ERRqhull);+ }+ qh->ERREXITcalled= True;+ if (!qh->QHULLfinished)+ qh->hulltime= qh_CPUclock - qh->hulltime;+ qh_errprint(qh, "ERRONEOUS", facet, NULL, ridge, NULL);+ qh_fprintf(qh, qh->ferr, 8127, "\nWhile executing: %s | %s\n", qh->rbox_command, qh->qhull_command);+ qh_fprintf(qh, qh->ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);+ if (qh->furthest_id >= 0) {+ qh_fprintf(qh, qh->ferr, 8129, "Last point added to hull was p%d.", qh->furthest_id);+ if (zzval_(Ztotmerge))+ qh_fprintf(qh, qh->ferr, 8130, " Last merge was #%d.", zzval_(Ztotmerge));+ if (qh->QHULLfinished)+ qh_fprintf(qh, qh->ferr, 8131, "\nQhull has finished constructing the hull.");+ else if (qh->POSTmerging)+ qh_fprintf(qh, qh->ferr, 8132, "\nQhull has started post-merging.");+ qh_fprintf(qh, qh->ferr, 8133, "\n");+ }+ if (qh->FORCEoutput && (qh->QHULLfinished || (!facet && !ridge)))+ qh_produce_output(qh);+ else if (exitcode != qh_ERRinput) {+ if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh->hull_dim+1) {+ qh_fprintf(qh, qh->ferr, 8134, "\nAt error exit:\n");+ qh_printsummary(qh, qh->ferr);+ if (qh->PRINTstatistics) {+ qh_collectstatistics(qh);+ qh_printstatistics(qh, qh->ferr, "at error exit");+ qh_memstatistics(qh, qh->ferr);+ }+ }+ if (qh->PRINTprecision)+ qh_printstats(qh, qh->ferr, qh->qhstat.precision, NULL);+ }+ if (!exitcode)+ exitcode= qh_ERRqhull;+ else if (exitcode == qh_ERRsingular)+ qh_printhelp_singular(qh, qh->ferr);+ else if (exitcode == qh_ERRprec && !qh->PREmerge)+ qh_printhelp_degenerate(qh, qh->ferr);+ if (qh->NOerrexit) {+ qh_fprintf(qh, qh->ferr, 6187, "qhull error while ending program, or qh->NOerrexit not cleared after setjmp(). Exit program with error.\n");+ qh_exit(qh_ERRqhull);+ }+ qh->ERREXITcalled= False;+ qh->NOerrexit= True;+ qh->ALLOWrestart= False; /* longjmp will undo qh_build_withrestart */+ longjmp(qh->errexit, exitcode);+} /* errexit */+++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="errprint">-</a>++ qh_errprint(qh, fp, string, atfacet, otherfacet, atridge, atvertex )+ prints out the information of facets and ridges to fp+ also prints neighbors and geomview output++ notes:+ except for string, any parameter may be NULL+*/+void qh_errprint(qhT *qh, const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {+ int i;++ if (atfacet) {+ qh_fprintf(qh, qh->ferr, 8135, "%s FACET:\n", string);+ qh_printfacet(qh, qh->ferr, atfacet);+ }+ if (otherfacet) {+ qh_fprintf(qh, qh->ferr, 8136, "%s OTHER FACET:\n", string);+ qh_printfacet(qh, qh->ferr, otherfacet);+ }+ if (atridge) {+ qh_fprintf(qh, qh->ferr, 8137, "%s RIDGE:\n", string);+ qh_printridge(qh, qh->ferr, atridge);+ if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)+ qh_printfacet(qh, qh->ferr, atridge->top);+ if (atridge->bottom+ && atridge->bottom != atfacet && atridge->bottom != otherfacet)+ qh_printfacet(qh, qh->ferr, atridge->bottom);+ if (!atfacet)+ atfacet= atridge->top;+ if (!otherfacet)+ otherfacet= otherfacet_(atridge, atfacet);+ }+ if (atvertex) {+ qh_fprintf(qh, qh->ferr, 8138, "%s VERTEX:\n", string);+ qh_printvertex(qh, qh->ferr, atvertex);+ }+ if (qh->fout && qh->FORCEoutput && atfacet && !qh->QHULLfinished && !qh->IStracing) {+ qh_fprintf(qh, qh->ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n");+ for (i=0; i < qh_PRINTEND; i++) /* use fout for geomview output */+ qh_printneighborhood(qh, qh->fout, qh->PRINTout[i], atfacet, otherfacet,+ !qh_ALL);+ }+} /* errprint */+++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="printfacetlist">-</a>++ qh_printfacetlist(qh, fp, facetlist, facets, printall )+ print all fields for a facet list and/or set of facets to fp+ if !printall,+ only prints good facets++ notes:+ also prints all vertices+*/+void qh_printfacetlist(qhT *qh, facetT *facetlist, setT *facets, boolT printall) {+ facetT *facet, **facetp;++ qh_printbegin(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);+ FORALLfacet_(facetlist)+ qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);+ FOREACHfacet_(facets)+ qh_printafacet(qh, qh->ferr, qh_PRINTfacets, facet, printall);+ qh_printend(qh, qh->ferr, qh_PRINTfacets, facetlist, facets, printall);+} /* printfacetlist */+++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printhelp_degenerate">-</a>++ qh_printhelp_degenerate(qh, fp )+ prints descriptive message for precision error++ notes:+ no message if qh_QUICKhelp+*/+void qh_printhelp_degenerate(qhT *qh, FILE *fp) {++ if (qh->MERGEexact || qh->PREmerge || qh->JOGGLEmax < REALmax/2)+ qh_fprintf(qh, fp, 9368, "\n\+A Qhull error has occurred. Qhull should have corrected the above\n\+precision error. Please send the input and all of the output to\n\+qhull_bug@qhull.org\n");+ else if (!qh_QUICKhelp) {+ qh_fprintf(qh, fp, 9369, "\n\+Precision problems were detected during construction of the convex hull.\n\+This occurs because convex hull algorithms assume that calculations are\n\+exact, but floating-point arithmetic has roundoff errors.\n\+\n\+To correct for precision problems, do not use 'Q0'. By default, Qhull\n\+selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\+Qhull joggles the input to prevent precision problems. See \"Imprecision\n\+in Qhull\" (qh-impre.htm).\n\+\n\+If you use 'Q0', the output may include\n\+coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\+Qhull may produce a ridge with four neighbors or two facets with the same \n\+vertices. Qhull reports these events when they occur. It stops when a\n\+concave ridge, flipped facet, or duplicate facet occurs.\n");+#if REALfloat+ qh_fprintf(qh, fp, 9370, "\+\n\+Qhull is currently using single precision arithmetic. The following\n\+will probably remove the precision problems:\n\+ - recompile qhull for realT precision(#define REALfloat 0 in user.h).\n");+#endif+ if (qh->DELAUNAY && !qh->SCALElast && qh->MAXabs_coord > 1e4)+ qh_fprintf(qh, fp, 9371, "\+\n\+When computing the Delaunay triangulation of coordinates > 1.0,\n\+ - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");+ if (qh->DELAUNAY && !qh->ATinfinity)+ qh_fprintf(qh, fp, 9372, "\+When computing the Delaunay triangulation:\n\+ - use 'Qz' to add a point at-infinity. This reduces precision problems.\n");++ qh_fprintf(qh, fp, 9373, "\+\n\+If you need triangular output:\n\+ - use option 'Qt' to triangulate the output\n\+ - use option 'QJ' to joggle the input points and remove precision errors\n\+ - use option 'Ft'. It triangulates non-simplicial facets with added points.\n\+\n\+If you must use 'Q0',\n\+try one or more of the following options. They can not guarantee an output.\n\+ - use 'QbB' to scale the input to a cube.\n\+ - use 'Po' to produce output and prevent partitioning for flipped facets\n\+ - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\+ - use 'En' to specify a maximum roundoff error less than %2.2g.\n\+ - options 'Qf', 'Qbb', and 'QR0' may also help\n",+ qh->DISTround);+ qh_fprintf(qh, fp, 9374, "\+\n\+To guarantee simplicial output:\n\+ - use option 'Qt' to triangulate the output\n\+ - use option 'QJ' to joggle the input points and remove precision errors\n\+ - use option 'Ft' to triangulate the output by adding points\n\+ - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\+");+ }+} /* printhelp_degenerate */+++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="printhelp_narrowhull">-</a>++ qh_printhelp_narrowhull(qh, minangle )+ Warn about a narrow hull++ notes:+ Alternatively, reduce qh_WARNnarrow in user.h++*/+void qh_printhelp_narrowhull(qhT *qh, FILE *fp, realT minangle) {++ qh_fprintf(qh, fp, 9375, "qhull precision warning: \n\+The initial hull is narrow (cosine of min. angle is %.16f).\n\+Is the input lower dimensional (e.g., on a plane in 3-d)? Qhull may\n\+produce a wide facet. Options 'QbB' (scale to unit box) or 'Qbb' (scale\n\+last coordinate) may remove this warning. Use 'Pp' to skip this warning.\n\+See 'Limitations' in qh-impre.htm.\n",+ -minangle); /* convert from angle between normals to angle between facets */+} /* printhelp_narrowhull */++/*-<a href="qh-io_r.htm#TOC"+ >-------------------------------</a><a name="printhelp_singular">-</a>++ qh_printhelp_singular(qh, fp )+ prints descriptive message for singular input+*/+void qh_printhelp_singular(qhT *qh, FILE *fp) {+ facetT *facet;+ vertexT *vertex, **vertexp;+ realT min, max, *coord, dist;+ int i,k;++ qh_fprintf(qh, fp, 9376, "\n\+The input to qhull appears to be less than %d dimensional, or a\n\+computation has overflowed.\n\n\+Qhull could not construct a clearly convex simplex from points:\n",+ qh->hull_dim);+ qh_printvertexlist(qh, fp, "", qh->facet_list, NULL, qh_ALL);+ if (!qh_QUICKhelp)+ qh_fprintf(qh, fp, 9377, "\n\+The center point is coplanar with a facet, or a vertex is coplanar\n\+with a neighboring facet. The maximum round off error for\n\+computing distances is %2.2g. The center point, facets and distances\n\+to the center point are as follows:\n\n", qh->DISTround);+ qh_printpointid(qh, fp, "center point", qh->hull_dim, qh->interior_point, qh_IDunknown);+ qh_fprintf(qh, fp, 9378, "\n");+ FORALLfacets {+ qh_fprintf(qh, fp, 9379, "facet");+ FOREACHvertex_(facet->vertices)+ qh_fprintf(qh, fp, 9380, " p%d", qh_pointid(qh, vertex->point));+ zinc_(Zdistio);+ qh_distplane(qh, qh->interior_point, facet, &dist);+ qh_fprintf(qh, fp, 9381, " distance= %4.2g\n", dist);+ }+ if (!qh_QUICKhelp) {+ if (qh->HALFspace)+ qh_fprintf(qh, fp, 9382, "\n\+These points are the dual of the given halfspaces. They indicate that\n\+the intersection is degenerate.\n");+ qh_fprintf(qh, fp, 9383,"\n\+These points either have a maximum or minimum x-coordinate, or\n\+they maximize the determinant for k coordinates. Trial points\n\+are first selected from points that maximize a coordinate.\n");+ if (qh->hull_dim >= qh_INITIALmax)+ qh_fprintf(qh, fp, 9384, "\n\+Because of the high dimension, the min x-coordinate and max-coordinate\n\+points are used if the determinant is non-zero. Option 'Qs' will\n\+do a better, though much slower, job. Instead of 'Qs', you can change\n\+the points by randomly rotating the input with 'QR0'.\n");+ }+ qh_fprintf(qh, fp, 9385, "\nThe min and max coordinates for each dimension are:\n");+ for (k=0; k < qh->hull_dim; k++) {+ min= REALmax;+ max= -REALmin;+ for (i=qh->num_points, coord= qh->first_point+k; i--; coord += qh->hull_dim) {+ maximize_(max, *coord);+ minimize_(min, *coord);+ }+ qh_fprintf(qh, fp, 9386, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);+ }+ if (!qh_QUICKhelp) {+ qh_fprintf(qh, fp, 9387, "\n\+If the input should be full dimensional, you have several options that\n\+may determine an initial simplex:\n\+ - use 'QJ' to joggle the input and make it full dimensional\n\+ - use 'QbB' to scale the points to the unit cube\n\+ - use 'QR0' to randomly rotate the input for different maximum points\n\+ - use 'Qs' to search all points for the initial simplex\n\+ - use 'En' to specify a maximum roundoff error less than %2.2g.\n\+ - trace execution with 'T3' to see the determinant for each point.\n",+ qh->DISTround);+#if REALfloat+ qh_fprintf(qh, fp, 9388, "\+ - recompile qhull for realT precision(#define REALfloat 0 in libqhull_r.h).\n");+#endif+ qh_fprintf(qh, fp, 9389, "\n\+If the input is lower dimensional:\n\+ - use 'QJ' to joggle the input and make it full dimensional\n\+ - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\+ pick the coordinate with the least range. The hull will have the\n\+ correct topology.\n\+ - determine the flat containing the points, rotate the points\n\+ into a coordinate plane, and delete the other coordinates.\n\+ - add one or more points to make the input full dimensional.\n\+");+ }+} /* printhelp_singular */++/*-<a href="qh-globa_r.htm#TOC"+ >-------------------------------</a><a name="user_memsizes">-</a>++ qh_user_memsizes(qh)+ allocate up to 10 additional, quick allocation sizes++ notes:+ increase maximum number of allocations in qh_initqhull_mem()+*/+void qh_user_memsizes(qhT *qh) {++ QHULL_UNUSED(qh)+ /* qh_memsize(qh, size); */+} /* user_memsizes */++
+ Cdir/usermem_r.c view
@@ -0,0 +1,94 @@+/*<html><pre> -<a href="qh-user_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ usermem_r.c+ qh_exit(), qh_free(), and qh_malloc()++ See README.txt.++ If you redefine one of these functions you must redefine all of them.+ If you recompile and load this file, then usermem.o will not be loaded+ from qhull.a or qhull.lib++ See libqhull_r.h for data structures, macros, and user-callable functions.+ See user_r.c for qhull-related, redefinable functions+ see user_r.h for user-definable constants+ See userprintf_r.c for qh_fprintf and userprintf_rbox_r.c for qh_fprintf_rbox++ Please report any errors that you fix to qhull@qhull.org+*/++#include "libqhull_r.h"++#include <stdarg.h>+#include <stdlib.h>++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="qh_exit">-</a>++ qh_exit( exitcode )+ exit program++ notes:+ qh_exit() is called when qh_errexit() and longjmp() are not available.++ This is the only use of exit() in Qhull+ To replace qh_exit with 'throw', see libqhullcpp/usermem_r-cpp.cpp+*/+void qh_exit(int exitcode) {+ exit(exitcode);+} /* exit */++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="qh_fprintf_stderr">-</a>++ qh_fprintf_stderr( msgcode, format, list of args )+ fprintf to stderr with msgcode (non-zero)++ notes:+ qh_fprintf_stderr() is called when qh->ferr is not defined, usually due to an initialization error+ + It is typically followed by qh_errexit().++ Redefine this function to avoid using stderr++ Use qh_fprintf [userprintf_r.c] for normal printing+*/+void qh_fprintf_stderr(int msgcode, const char *fmt, ... ) {+ va_list args;++ va_start(args, fmt);+ if(msgcode)+ fprintf(stderr, "QH%.4d ", msgcode);+ vfprintf(stderr, fmt, args);+ va_end(args);+} /* fprintf_stderr */++/*-<a href="qh-user_r.htm#TOC"+>-------------------------------</a><a name="qh_free">-</a>++ qh_free(qhT *qh, mem )+ free memory++ notes:+ same as free()+ No calls to qh_errexit() +*/+void qh_free(void *mem) {+ free(mem);+} /* free */++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="qh_malloc">-</a>++ qh_malloc( mem )+ allocate memory++ notes:+ same as malloc()+*/+void *qh_malloc(size_t size) {+ return malloc(size);+} /* malloc */++
+ Cdir/userprintf_r.c view
@@ -0,0 +1,65 @@+/*<html><pre> -<a href="qh-user_r.htm"+ >-------------------------------</a><a name="TOP">-</a>++ userprintf_r.c+ qh_fprintf()++ see README.txt see COPYING.txt for copyright information.++ If you recompile and load this file, then userprintf_r.o will not be loaded+ from qhull.a or qhull.lib++ See libqhull_r.h for data structures, macros, and user-callable functions.+ See user_r.c for qhull-related, redefinable functions+ see user_r.h for user-definable constants+ See usermem_r.c for qh_exit(), qh_free(), and qh_malloc()+ see Qhull.cpp and RboxPoints.cpp for examples.++ Please report any errors that you fix to qhull@qhull.org+*/++#include "libqhull_r.h"++#include <stdarg.h>+#include <stdio.h>+#include <stdlib.h>++/*-<a href="qh-user_r.htm#TOC"+ >-------------------------------</a><a name="qh_fprintf">-</a>++ qh_fprintf(qh, fp, msgcode, format, list of args )+ print arguments to *fp according to format+ Use qh_fprintf_rbox() for rboxlib_r.c++ notes:+ same as fprintf()+ fgets() is not trapped like fprintf()+ exit qh_fprintf via qh_errexit()+ may be called for errors in qh_initstatistics and qh_meminit+*/++void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... ) {+ va_list args;++ if (!fp) {+ if(!qh){+ qh_fprintf_stderr(6241, "userprintf_r.c: fp and qh not defined for qh_fprintf '%s'", fmt);+ qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */+ }+ /* could use qh->qhmem.ferr, but probably better to be cautious */+ qh_fprintf_stderr(6232, "Qhull internal error (userprintf_r.c): fp is 0. Wrong qh_fprintf called.\n");+ qh_errexit(qh, 6232, NULL, NULL);+ }+ va_start(args, fmt);+ if (qh && qh->ANNOTATEoutput) {+ fprintf(fp, "[QH%.4d]", msgcode);+ }else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {+ fprintf(fp, "QH%.4d ", msgcode);+ }+ vfprintf(fp, fmt, args);+ va_end(args);++ /* Place debugging traps here. Use with option 'Tn' */++} /* qh_fprintf */+
+ Cdir/utils.c view
@@ -0,0 +1,91 @@+#include <stdlib.h> // to use realloc+#include <math.h> // to use NAN+#include <stdio.h> // to use printf++double* getpoint(double* points, unsigned dim, unsigned id){+ double* out = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ out[i] = points[id*dim+i];+ }+ return out;+}++/* dot product of two vectors */+double dotproduct(double* p1, double* p2, unsigned dim){+ double out = 0;+ for(unsigned i=0; i < dim; i++){+ out += p1[i] * p2[i];+ }+ return out;+}++/* middle of segment [p1,p2] */+double* middle(double* p1, double* p2, unsigned dim){+ double* out = malloc(dim * sizeof(double));+ for(unsigned i=0; i<dim; i++){+ out[i] = (p1[i] + p2[i])/2;+ }+ return out;+}++/* vector of NANs */+double* nanvector(int dim){+ double* out = malloc(dim * sizeof(double));+ for(unsigned i=0; i < dim; i++){+ out[i] = NAN;+ }+ return out;+}++// to use the qsort function+int cmpfunc (const void * a, const void * b) {+ return ( *(int*)a - *(int*)b );+}+int cmpfuncdbl (const void * a, const void * b) {+ return ( *(double*)a - *(double*)b > 0 ? 1 : -1);+}+void qsortu(unsigned* vector, unsigned length){+ qsort(vector, length, sizeof(unsigned), cmpfunc);+}+++double square(double x){+ return x*x;+}++/* append to a vector of unsigned */+void appendu(unsigned x, unsigned** array, unsigned length, unsigned* flag){+ *flag = 1;+ for(unsigned i=0; i<length; i++){+ if(x==*(*array + i)){+ *flag = 0;+ break;+ }+ }+ if(*flag==1){+ *array = realloc(*array, (length+1)*sizeof(unsigned));+ if(*array == NULL){+ printf("realloc failure - exiting");+ exit(1);+ }+ *(*array + length) = x;+ }+}++/* make a vector of zeros */+unsigned* uzeros(unsigned length){+ unsigned* out = malloc(length * sizeof(unsigned));+ for(unsigned i=0; i < length; i++){+ out[i] = 0;+ }+ return out;+}++/* squared distance between two points */+double squaredDistance(double* p1, double* p2, unsigned dim){+ double out = 0;+ for(unsigned i=0; i < dim; i++){+ out += square(p1[i] - p2[i]);+ }+ return out;+}
+ ChangeLog.md view
@@ -0,0 +1,15 @@+ +0.1.0.1+ pushed on hackage 2022-07-25+0.1.0.2 + trial for a split version - no examples + probably not worthwile, + `toysolver` remains necessary, which forces base <4.15+ which does not allow to go to ghc 9.+0.1.0.3 maintenance +- issue with not finding include + trying <> instead of ""+ change both include-dir and C-dir to ./Cdir+ there was a hint on stackoverflow that single char dirs do not work well in cabal+ works with stack once, after stack install uniform-geometry can use it.+- cannot go to hpack, trying stack init - not working either
qhull.cabal view
@@ -1,5 +1,5 @@ name: qhull-version: 0.1.0.1+version: 0.1.0.3 synopsis: Delaunay triangulation, Voronoi diagrams and convex hulls. description: Based on the qhull C library. @@ -12,9 +12,13 @@ copyright: 2018 Stéphane Laurent category: Math build-type: Simple-extra-source-files: README.md+extra-source-files: README.md ChangeLog.md cabal-version: >=1.10 +source-repository head+ type: git+ location: https://github.com/stla/qhull+ flag exe description: Build the executables.@@ -87,26 +91,28 @@ other-extensions: ForeignFunctionInterface , TypeFamilies default-language: Haskell2010- include-dirs: C- C-sources: ./C/libqhull_r.c- , ./C/geom_r.c- , ./C/geom2_r.c- , ./C/global_r.c- , ./C/io_r.c- , ./C/mem_r.c- , ./C/merge_r.c- , ./C/poly_r.c- , ./C/poly2_r.c- , ./C/qset_r.c- , ./C/random_r.c- , ./C/usermem_r.c- , ./C/userprintf_r.c- , ./C/user_r.c- , ./C/stat_r.c- , ./C/delaunay.c- , ./C/convexhull.c- , ./C/utils.c- , ./C/halfspaces.c++ include-dirs: ./Cdir+ C-sources: ./Cdir/libqhull_r.c+ , ./Cdir/geom_r.c+ , ./Cdir/geom2_r.c+ , ./Cdir/global_r.c+ , ./Cdir/io_r.c+ , ./Cdir/mem_r.c+ , ./Cdir/merge_r.c+ , ./Cdir/poly_r.c+ , ./Cdir/poly2_r.c+ , ./Cdir/qset_r.c+ , ./Cdir/random_r.c+ , ./Cdir/usermem_r.c+ , ./Cdir/userprintf_r.c+ , ./Cdir/user_r.c+ , ./Cdir/stat_r.c+ , ./Cdir/delaunay.c+ , ./Cdir/convexhull.c+ , ./Cdir/utils.c+ , ./Cdir/halfspaces.c+ ghc-options: -O0 -Wall executable test_delaunay@@ -185,6 +191,4 @@ , containers ghc-options: -main-is Adjacency.AdjacencyMatrix -source-repository head- type: git- location: https://github.com/stla/qhull+