packages feed

qhull 0.1.0.1 → 0.1.0.3

raw patch · 40 files changed

+23960/−23941 lines, 40 files

Files

− 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:", &center, 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, &centers, neighbor);-      }else if (firstinf) {-        firstinf= False;-        qh_setappend(qh, &centers, 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, &centers, facet);-      }else if (firstinf) {-        firstinf= False;-        qh_setappend(qh, &centers, 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, &centers);-            }-          }-        }-      }-    }-  }-  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:", &center, 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, &centers, neighbor);+      }else if (firstinf) {+        firstinf= False;+        qh_setappend(qh, &centers, 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, &centers, facet);+      }else if (firstinf) {+        firstinf= False;+        qh_setappend(qh, &centers, 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, &centers);+            }+          }+        }+      }+    }+  }+  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+