LCOV - code coverage report
Current view: top level - alg/internal_libqhull - poly2_r.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 713 1982 36.0 %
Date: 2024-05-02 00:41:30 Functions: 31 59 52.5 %

          Line data    Source code
       1             : /*<html><pre>  -<a                             href="qh-poly_r.htm"
       2             :   >-------------------------------</a><a name="TOP">-</a>
       3             : 
       4             :    poly2_r.c
       5             :    implements polygons and simplicies
       6             : 
       7             :    see qh-poly_r.htm, poly_r.h and libqhull_r.h
       8             : 
       9             :    frequently used code is in poly_r.c
      10             : 
      11             :    Copyright (c) 1993-2020 The Geometry Center.
      12             :    $Id: //main/2019/qhull/src/libqhull_r/poly2_r.c#20 $$Change: 2953 $
      13             :    $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
      14             : */
      15             : 
      16             : #include "qhull_ra.h"
      17             : 
      18             : /*======== functions in alphabetical order ==========*/
      19             : 
      20             : /*-<a                             href="qh-poly_r.htm#TOC"
      21             :   >-------------------------------</a><a name="addfacetvertex">-</a>
      22             : 
      23             :   qh_addfacetvertex(qh, facet, newvertex )
      24             :     add newvertex to facet.vertices if not already there
      25             :     vertices are inverse sorted by vertex->id
      26             : 
      27             :   returns:
      28             :     True if new vertex for facet
      29             : 
      30             :   notes:
      31             :     see qh_replacefacetvertex
      32             : */
      33           1 : boolT qh_addfacetvertex(qhT *qh, facetT *facet, vertexT *newvertex) {
      34             :   vertexT *vertex;
      35           1 :   int vertex_i= 0, vertex_n;
      36           1 :   boolT isnew= True;
      37             : 
      38           4 :   FOREACHvertex_i_(qh, facet->vertices) {
      39           3 :     if (vertex->id < newvertex->id) {
      40           0 :       break;
      41           3 :     }else if (vertex->id == newvertex->id) {
      42           0 :       isnew= False;
      43           0 :       break;
      44             :     }
      45             :   }
      46           1 :   if (isnew)
      47           1 :     qh_setaddnth(qh, &facet->vertices, vertex_i, newvertex);
      48           1 :   return isnew;
      49             : } /* addfacetvertex */
      50             : 
      51             : /*-<a                             href="qh-poly_r.htm#TOC"
      52             :   >-------------------------------</a><a name="addhash">-</a>
      53             : 
      54             :   qh_addhash( newelem, hashtable, hashsize, hash )
      55             :     add newelem to linear hash table at hash if not already there
      56             : */
      57           0 : void qh_addhash(void *newelem, setT *hashtable, int hashsize, int hash) {
      58             :   int scan;
      59             :   void *elem;
      60             : 
      61           0 :   for (scan= (int)hash; (elem= SETelem_(hashtable, scan));
      62           0 :        scan= (++scan >= hashsize ? 0 : scan)) {
      63           0 :     if (elem == newelem)
      64           0 :       break;
      65             :   }
      66             :   /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
      67           0 :   if (!elem)
      68           0 :     SETelem_(hashtable, scan)= newelem;
      69           0 : } /* addhash */
      70             : 
      71             : /*-<a                             href="qh-poly_r.htm#TOC"
      72             :   >-------------------------------</a><a name="check_bestdist">-</a>
      73             : 
      74             :   qh_check_bestdist(qh)
      75             :     check that all points are within max_outside of the nearest facet
      76             :     if qh.ONLYgood,
      77             :       ignores !good facets
      78             : 
      79             :   see:
      80             :     qh_check_maxout(), qh_outerinner()
      81             : 
      82             :   notes:
      83             :     only called from qh_check_points()
      84             :       seldom used since qh.MERGING is almost always set
      85             :     if notverified>0 at end of routine
      86             :       some points were well inside the hull.  If the hull contains
      87             :       a lens-shaped component, these points were not verified.  Use
      88             :       options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
      89             : 
      90             :   design:
      91             :     determine facet for each point (if any)
      92             :     for each point
      93             :       start with the assigned facet or with the first facet
      94             :       find the best facet for the point and check all coplanar facets
      95             :       error if point is outside of facet
      96             : */
      97           0 : void qh_check_bestdist(qhT *qh) {
      98           0 :   boolT waserror= False, unassigned;
      99           0 :   facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
     100             :   facetT *facetlist;
     101           0 :   realT dist, maxoutside, maxdist= -REALmax;
     102             :   pointT *point;
     103           0 :   int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
     104             :   setT *facets;
     105             : 
     106           0 :   trace1((qh, qh->ferr, 1020, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
     107             :       qh->facet_list->id));
     108           0 :   maxoutside= qh_maxouter(qh);
     109           0 :   maxoutside += qh->DISTround;
     110             :   /* one more qh.DISTround for check computation */
     111           0 :   trace1((qh, qh->ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
     112           0 :   facets= qh_pointfacet(qh /* qh.facet_list */);
     113           0 :   if (!qh_QUICKhelp && qh->PRINTprecision)
     114           0 :     qh_fprintf(qh, qh->ferr, 8091, "\n\
     115             : qhull output completed.  Verifying that %d points are\n\
     116             : below %2.2g of the nearest %sfacet.\n",
     117           0 :              qh_setsize(qh, facets), maxoutside, (qh->ONLYgood ?  "good " : ""));
     118           0 :   FOREACHfacet_i_(qh, facets) {  /* for each point with facet assignment */
     119           0 :     if (facet)
     120           0 :       unassigned= False;
     121             :     else {
     122           0 :       unassigned= True;
     123           0 :       facet= qh->facet_list;
     124             :     }
     125           0 :     point= qh_point(qh, facet_i);
     126           0 :     if (point == qh->GOODpointp)
     127           0 :       continue;
     128           0 :     qh_distplane(qh, point, facet, &dist);
     129           0 :     numpart++;
     130           0 :     bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
     131             :     /* occurs after statistics reported */
     132           0 :     maximize_(maxdist, dist);
     133           0 :     if (dist > maxoutside) {
     134           0 :       if (qh->ONLYgood && !bestfacet->good
     135           0 :       && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
     136           0 :       && dist > maxoutside))
     137           0 :         notgood++;
     138             :       else {
     139           0 :         waserror= True;
     140           0 :         qh_fprintf(qh, qh->ferr, 6109, "qhull precision error (qh_check_bestdist): point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n",
     141             :                 facet_i, bestfacet->id, dist, maxoutside);
     142           0 :         if (errfacet1 != bestfacet) {
     143           0 :           errfacet2= errfacet1;
     144           0 :           errfacet1= bestfacet;
     145             :         }
     146             :       }
     147           0 :     }else if (unassigned && dist < -qh->MAXcoplanar)
     148           0 :       notverified++;
     149             :   }
     150           0 :   qh_settempfree(qh, &facets);
     151           0 :   if (notverified && !qh->DELAUNAY && !qh_QUICKhelp && qh->PRINTprecision)
     152           0 :     qh_fprintf(qh, qh->ferr, 8092, "\n%d points were well inside the hull.  If the hull contains\n\
     153             : a lens-shaped component, these points were not verified.  Use\n\
     154             : options 'Qci Tv' to verify all points.\n", notverified);
     155           0 :   if (maxdist > qh->outside_err) {
     156           0 :     qh_fprintf(qh, qh->ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value is qh.outside_err (%6.2g)\n",
     157             :               maxdist, qh->outside_err);
     158           0 :     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
     159           0 :   }else if (waserror && qh->outside_err > REALmax/2)
     160           0 :     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
     161             :   /* else if waserror, the error was logged to qh.ferr but does not effect the output */
     162           0 :   trace0((qh, qh->ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
     163           0 : } /* check_bestdist */
     164             : 
     165             : #ifndef qh_NOmerge
     166             : /*-<a                             href="qh-poly_r.htm#TOC"
     167             :   >-------------------------------</a><a name="check_maxout">-</a>
     168             : 
     169             :   qh_check_maxout(qh)
     170             :     updates qh.max_outside by checking all points against bestfacet
     171             :     if qh.ONLYgood, ignores !good facets
     172             : 
     173             :   returns:
     174             :     updates facet->maxoutside via qh_findbesthorizon()
     175             :     sets qh.maxoutdone
     176             :     if printing qh.min_vertex (qh_outerinner),
     177             :       it is updated to the current vertices
     178             :     removes inside/coplanar points from coplanarset as needed
     179             : 
     180             :   notes:
     181             :     defines coplanar as qh.min_vertex instead of qh.MAXcoplanar
     182             :     may not need to check near-inside points because of qh.MAXcoplanar
     183             :       and qh.KEEPnearinside (before it was -qh.DISTround)
     184             : 
     185             :   see also:
     186             :     qh_check_bestdist()
     187             : 
     188             :   design:
     189             :     if qh.min_vertex is needed
     190             :       for all neighbors of all vertices
     191             :         test distance from vertex to neighbor
     192             :     determine facet for each point (if any)
     193             :     for each point with an assigned facet
     194             :       find the best facet for the point and check all coplanar facets
     195             :         (updates outer planes)
     196             :     remove near-inside points from coplanar sets
     197             : */
     198           3 : void qh_check_maxout(qhT *qh) {
     199           3 :   facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist, *maxbestfacet= NULL, *minfacet, *maxfacet, *maxpointfacet;
     200             :   realT dist, maxoutside, mindist, nearest;
     201             :   realT maxoutside_base, minvertex_base;
     202           3 :   pointT *point, *maxpoint= NULL;
     203           3 :   int numpart= 0, facet_i, facet_n, notgood= 0;
     204             :   setT *facets, *vertices;
     205             :   vertexT *vertex, *minvertex;
     206             : 
     207           3 :   trace1((qh, qh->ferr, 1022, "qh_check_maxout: check and update qh.min_vertex %2.2g and qh.max_outside %2.2g\n", qh->min_vertex, qh->max_outside));
     208           3 :   minvertex_base= fmin_(qh->min_vertex, -(qh->ONEmerge+qh->DISTround));
     209           3 :   maxoutside= mindist= 0.0;
     210           3 :   minvertex= qh->vertex_list;
     211           3 :   maxfacet= minfacet= maxpointfacet= qh->facet_list;
     212           3 :   if (qh->VERTEXneighbors
     213           3 :   && (qh->PRINTsummary || qh->KEEPinside || qh->KEEPcoplanar
     214           0 :         || qh->TRACElevel || qh->PRINTstatistics || qh->VERIFYoutput || qh->CHECKfrequently
     215           0 :         || qh->PRINTout[0] == qh_PRINTsummary || qh->PRINTout[0] == qh_PRINTnone)) {
     216           3 :     trace1((qh, qh->ferr, 1023, "qh_check_maxout: determine actual minvertex\n"));
     217           3 :     vertices= qh_pointvertex(qh /* qh.facet_list */);
     218       14675 :     FORALLvertices {
     219       72922 :       FOREACHneighbor_(vertex) {
     220       58250 :         zinc_(Zdistvertex);  /* distance also computed by main loop below */
     221       58250 :         qh_distplane(qh, vertex->point, neighbor, &dist);
     222       58250 :         if (dist < mindist) {
     223          15 :           if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
     224           0 :             nearest= qh_vertex_bestdist(qh, neighbor->vertices);
     225             :             /* should be caught in qh_mergefacet */
     226           0 :             qh_fprintf(qh, qh->ferr, 7083, "Qhull precision warning: in post-processing (qh_check_maxout) p%d(v%d) is %2.2g below f%d nearest vertices %2.2g\n",
     227             :               qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
     228             :           }
     229          15 :           mindist= dist;
     230          15 :           minvertex= vertex;
     231          15 :           minfacet= neighbor;
     232             :         }
     233             : #ifndef qh_NOtrace
     234       58250 :         if (-dist > qh->TRACEdist || dist > qh->TRACEdist
     235       58250 :         || neighbor == qh->tracefacet || vertex == qh->tracevertex) {
     236           0 :           nearest= qh_vertex_bestdist(qh, neighbor->vertices);
     237           0 :           qh_fprintf(qh, qh->ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d nearest vertices %2.2g\n",
     238             :                     qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, nearest);
     239             :         }
     240             : #endif
     241             :       }
     242             :     }
     243           3 :     if (qh->MERGING) {
     244           3 :       wmin_(Wminvertex, qh->min_vertex);
     245             :     }
     246           3 :     qh->min_vertex= mindist;
     247           3 :     qh_settempfree(qh, &vertices);
     248             :   }
     249           3 :   trace1((qh, qh->ferr, 1055, "qh_check_maxout: determine actual maxoutside\n"));
     250           3 :   maxoutside_base= fmax_(qh->max_outside, qh->ONEmerge+qh->DISTround);
     251             :   /* maxoutside_base is same as qh.MAXoutside without qh.MINoutside (qh_detmaxoutside) */
     252           3 :   facets= qh_pointfacet(qh /* qh.facet_list */);
     253       14676 :   FOREACHfacet_i_(qh, facets) {     /* for each point with facet assignment */
     254       14673 :     if (facet) {
     255       14673 :       point= qh_point(qh, facet_i);
     256       14673 :       if (point == qh->GOODpointp)
     257           0 :         continue;
     258       14673 :       zzinc_(Ztotcheck);
     259       14673 :       qh_distplane(qh, point, facet, &dist);
     260       14673 :       numpart++;
     261       14673 :       bestfacet= qh_findbesthorizon(qh, qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
     262       14673 :       if (bestfacet && dist >= maxoutside) {
     263          23 :         if (qh->ONLYgood && !bestfacet->good
     264           0 :         && !((bestfacet= qh_findgooddist(qh, point, bestfacet, &dist, &facetlist))
     265           0 :         && dist > maxoutside)) {
     266           0 :           notgood++;
     267          23 :         }else if (dist/maxoutside_base > qh_WIDEmaxoutside && (qh->PRINTprecision || !qh->ALLOWwide)) {
     268           0 :           nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
     269           0 :           if (nearest < fmax_(qh->ONEmerge, qh->max_outside) * qh_RATIOcoplanaroutside * 2) {
     270           0 :             qh_fprintf(qh, qh->ferr, 7087, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above twisted facet f%d nearest vertices %2.2g\n",
     271             :               qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
     272             :           }else {
     273           0 :             qh_fprintf(qh, qh->ferr, 7088, "Qhull precision warning: in post-processing (qh_check_maxout) p%d for f%d is %2.2g above hidden facet f%d nearest vertices %2.2g\n",
     274             :               qh_pointid(qh, point), facet->id, dist, bestfacet->id, nearest);
     275             :           }
     276           0 :           maxbestfacet= bestfacet;
     277             :         }
     278          23 :         maxoutside= dist;
     279          23 :         maxfacet= bestfacet;
     280          23 :         maxpoint= point;
     281          23 :         maxpointfacet= facet;
     282             :       }
     283       14673 :       if (dist > qh->TRACEdist || (bestfacet && bestfacet == qh->tracefacet))
     284           0 :         qh_fprintf(qh, qh->ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n",
     285             :               qh_pointid(qh, point), dist, (bestfacet ? bestfacet->id : UINT_MAX));
     286             :     }
     287             :   }
     288           3 :   zzadd_(Zcheckpart, numpart);
     289           3 :   qh_settempfree(qh, &facets);
     290           3 :   wval_(Wmaxout)= maxoutside - qh->max_outside;
     291           3 :   wmax_(Wmaxoutside, qh->max_outside);
     292           3 :   if (!qh->APPROXhull && maxoutside > qh->DISTround) { /* initial value for f.maxoutside */
     293           0 :     FORALLfacets {
     294           0 :       if (maxoutside < facet->maxoutside) {
     295           0 :         if (!qh->KEEPcoplanar) {
     296           0 :           maxoutside= facet->maxoutside;
     297           0 :         }else if (maxoutside + qh->DISTround < facet->maxoutside) { /* maxoutside is computed distance, e.g., rbox 100 s D3 t1547136913 | qhull R1e-3 Tcv Qc */
     298           0 :           qh_fprintf(qh, qh->ferr, 7082, "Qhull precision warning (qh_check_maxout): f%d.maxoutside (%4.4g) is greater than computed qh.max_outside (%2.2g) + qh.DISTround (%2.2g).  It should be less than or equal\n",
     299             :             facet->id, facet->maxoutside, maxoutside, qh->DISTround);
     300             :         }
     301             :       }
     302             :     }
     303             :   }
     304           3 :   qh->max_outside= maxoutside;
     305           3 :   qh_nearcoplanar(qh /* qh.facet_list */);
     306           3 :   qh->maxoutdone= True;
     307           3 :   trace1((qh, qh->ferr, 1024, "qh_check_maxout:  p%d(v%d) is qh.min_vertex %2.2g below facet f%d.  Point p%d for f%d is qh.max_outside %2.2g above f%d.  %d points are outside of not-good facets\n",
     308             :     qh_pointid(qh, minvertex->point), minvertex->id, qh->min_vertex, minfacet->id, qh_pointid(qh, maxpoint), maxpointfacet->id, qh->max_outside, maxfacet ? maxfacet->id : -1, notgood));
     309           3 :   if(!qh->ALLOWwide) {
     310           3 :     if (maxoutside/maxoutside_base > qh_WIDEmaxoutside) {
     311           0 :       qh_fprintf(qh, qh->ferr, 6297, "Qhull precision error (qh_check_maxout): large increase in qh.max_outside during post-processing dist %2.2g (%.1fx).  See warning QH0032/QH0033.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
     312             :         maxoutside, maxoutside/maxoutside_base);
     313           0 :       qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
     314           3 :     }else if (!qh->APPROXhull && maxoutside_base > (qh->ONEmerge * qh_WIDEmaxoutside2)) {
     315           0 :       if (maxoutside > (qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
     316           0 :         qh_fprintf(qh, qh->ferr, 6298, "Qhull precision error (qh_check_maxout): a facet merge, vertex merge, vertex, or coplanar point produced a wide facet %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.   Allow with 'Q12' (allow-wide)\n",
     317           0 :           maxoutside_base, maxoutside_base/(qh->ONEmerge + qh->DISTround));
     318           0 :         qh_errexit(qh, qh_ERRwide, maxbestfacet, NULL);
     319             :       }
     320           3 :     }else if (qh->min_vertex/minvertex_base > qh_WIDEmaxoutside) {
     321           0 :       qh_fprintf(qh, qh->ferr, 6354, "Qhull precision error (qh_check_maxout): large increase in qh.min_vertex during post-processing dist %2.2g (%.1fx).  See warning QH7083.  Allow with 'Q12' (allow-wide) and 'Pp'\n",
     322           0 :         qh->min_vertex, qh->min_vertex/minvertex_base);
     323           0 :       qh_errexit(qh, qh_ERRwide, minfacet, NULL);
     324           3 :     }else if (minvertex_base < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {
     325           0 :       if (qh->min_vertex < -(qh->ONEmerge * qh_WIDEmaxoutside2)) {  /* wide facets may have been deleted */
     326           0 :         qh_fprintf(qh, qh->ferr, 6380, "Qhull precision error (qh_check_maxout): a facet or vertex merge produced a wide facet: v%d below f%d distance %2.2g (%.1fx). Trace with option 'TWn' to identify the merge.  Allow with 'Q12' (allow-wide)\n",
     327           0 :           minvertex->id, minfacet->id, mindist, -qh->min_vertex/(qh->ONEmerge + qh->DISTround));
     328           0 :         qh_errexit(qh, qh_ERRwide, minfacet, NULL);
     329             :       }
     330             :     }
     331             :   }
     332           3 : } /* check_maxout */
     333             : #else /* qh_NOmerge */
     334             : void qh_check_maxout(qhT *qh) {
     335             :   QHULL_UNUSED(qh)
     336             : }
     337             : #endif
     338             : 
     339             : /*-<a                             href="qh-poly_r.htm#TOC"
     340             :   >-------------------------------</a><a name="check_output">-</a>
     341             : 
     342             :   qh_check_output(qh)
     343             :     performs the checks at the end of qhull algorithm
     344             :     Maybe called after Voronoi output.  If so, it recomputes centrums since they are Voronoi centers instead.
     345             : */
     346           3 : void qh_check_output(qhT *qh) {
     347             :   int i;
     348             : 
     349           3 :   if (qh->STOPcone)
     350           0 :     return;
     351           3 :   if (qh->VERIFYoutput || qh->IStracing || qh->CHECKfrequently) {
     352           0 :     qh_checkpolygon(qh, qh->facet_list);
     353           0 :     qh_checkflipped_all(qh, qh->facet_list);
     354           0 :     qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
     355           3 :   }else if (!qh->MERGING && qh_newstats(qh, qh->qhstat.precision, &i)) {
     356           0 :     qh_checkflipped_all(qh, qh->facet_list);
     357           0 :     qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
     358             :   }
     359             : } /* check_output */
     360             : 
     361             : 
     362             : 
     363             : /*-<a                             href="qh-poly_r.htm#TOC"
     364             :   >-------------------------------</a><a name="check_point">-</a>
     365             : 
     366             :   qh_check_point(qh, point, facet, maxoutside, maxdist, errfacet1, errfacet2, errcount )
     367             :     check that point is less than maxoutside from facet
     368             : 
     369             :   notes:
     370             :     only called from qh_checkpoints
     371             :     reports up to qh_MAXcheckpoint-1 errors per facet
     372             : */
     373           0 : void qh_check_point(qhT *qh, pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2, int *errcount) {
     374             :   realT dist, nearest;
     375             : 
     376             :   /* occurs after statistics reported */
     377           0 :   qh_distplane(qh, point, facet, &dist);
     378           0 :   maximize_(*maxdist, dist);
     379           0 :   if (dist > *maxoutside) {
     380           0 :     (*errcount)++;
     381           0 :     if (*errfacet1 != facet) {
     382           0 :       *errfacet2= *errfacet1;
     383           0 :       *errfacet1= facet;
     384             :     }
     385           0 :     if (*errcount < qh_MAXcheckpoint) {
     386           0 :       nearest= qh_vertex_bestdist(qh, facet->vertices);
     387           0 :       qh_fprintf(qh, qh->ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g nearest vertices %2.2g\n",
     388             :                 qh_pointid(qh, point), facet->id, dist, *maxoutside, nearest);
     389             :     }
     390             :   }
     391           0 : } /* qh_check_point */
     392             : 
     393             : 
     394             : /*-<a                             href="qh-poly_r.htm#TOC"
     395             :   >-------------------------------</a><a name="check_points">-</a>
     396             : 
     397             :   qh_check_points(qh)
     398             :     checks that all points are inside all facets
     399             : 
     400             :   notes:
     401             :     if many points and qh_check_maxout not called (i.e., !qh.MERGING),
     402             :        calls qh_findbesthorizon via qh_check_bestdist (seldom done).
     403             :     ignores flipped facets
     404             :     maxoutside includes 2 qh.DISTrounds
     405             :       one qh.DISTround for the computed distances in qh_check_points
     406             :     qh_printafacet and qh_printsummary needs only one qh.DISTround
     407             :     the computation for qh.VERIFYdirect does not account for qh.other_points
     408             : 
     409             :   design:
     410             :     if many points
     411             :       use qh_check_bestdist()
     412             :     else
     413             :       for all facets
     414             :         for all points
     415             :           check that point is inside facet
     416             : */
     417           0 : void qh_check_points(qhT *qh) {
     418           0 :   facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
     419           0 :   realT total, maxoutside, maxdist= -REALmax;
     420             :   pointT *point, **pointp, *pointtemp;
     421             :   int errcount;
     422             :   boolT testouter;
     423             : 
     424           0 :   maxoutside= qh_maxouter(qh);
     425           0 :   maxoutside += qh->DISTround;
     426             :   /* one more qh.DISTround for check computation */
     427           0 :   trace1((qh, qh->ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n",
     428             :           maxoutside));
     429           0 :   if (qh->num_good)   /* miss counts other_points and !good facets */
     430           0 :      total= (float)qh->num_good * (float)qh->num_points;
     431             :   else
     432           0 :      total= (float)qh->num_facets * (float)qh->num_points;
     433           0 :   if (total >= qh_VERIFYdirect && !qh->maxoutdone) {
     434           0 :     if (!qh_QUICKhelp && qh->SKIPcheckmax && qh->MERGING)
     435           0 :       qh_fprintf(qh, qh->ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').  Verify may report that a point is outside of a facet.\n");
     436           0 :     qh_check_bestdist(qh);
     437             :   }else {
     438           0 :     if (qh_MAXoutside && qh->maxoutdone)
     439           0 :       testouter= True;
     440             :     else
     441           0 :       testouter= False;
     442             :     if (!qh_QUICKhelp) {
     443           0 :       if (qh->MERGEexact)
     444           0 :         qh_fprintf(qh, qh->ferr, 7076, "qhull input warning: exact merge ('Qx').  Verify may report that a point is outside of a facet.  See qh-optq.htm#Qx\n");
     445           0 :       else if (qh->SKIPcheckmax || qh->NOnearinside)
     446           0 :         qh_fprintf(qh, qh->ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of near-inside points ('Q8').  Verify may report that a point is outside of a facet.\n");
     447             :     }
     448           0 :     if (qh->PRINTprecision) {
     449           0 :       if (testouter)
     450           0 :         qh_fprintf(qh, qh->ferr, 8098, "\n\
     451             : Output completed.  Verifying that all points are below outer planes of\n\
     452             : all %sfacets.  Will make %2.0f distance computations.\n",
     453           0 :               (qh->ONLYgood ?  "good " : ""), total);
     454             :       else
     455           0 :         qh_fprintf(qh, qh->ferr, 8099, "\n\
     456             : Output completed.  Verifying that all points are below %2.2g of\n\
     457             : all %sfacets.  Will make %2.0f distance computations.\n",
     458           0 :               maxoutside, (qh->ONLYgood ?  "good " : ""), total);
     459             :     }
     460           0 :     FORALLfacets {
     461           0 :       if (!facet->good && qh->ONLYgood)
     462           0 :         continue;
     463           0 :       if (facet->flipped)
     464           0 :         continue;
     465           0 :       if (!facet->normal) {
     466           0 :         qh_fprintf(qh, qh->ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
     467           0 :         if (!errfacet1)
     468           0 :           errfacet1= facet;
     469           0 :         continue;
     470             :       }
     471           0 :       if (testouter) {
     472             : #if qh_MAXoutside
     473           0 :         maxoutside= facet->maxoutside + 2 * qh->DISTround;
     474             :         /* one DISTround to actual point and another to computed point */
     475             : #endif
     476             :       }
     477           0 :       errcount= 0;
     478           0 :       FORALLpoints {
     479           0 :         if (point != qh->GOODpointp)
     480           0 :           qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
     481             :       }
     482           0 :       FOREACHpoint_(qh->other_points) {
     483           0 :         if (point != qh->GOODpointp)
     484           0 :           qh_check_point(qh, point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2, &errcount);
     485             :       }
     486           0 :       if (errcount >= qh_MAXcheckpoint) {
     487           0 :         qh_fprintf(qh, qh->ferr, 6422, "qhull precision error (qh_check_points): %d additional points outside facet f%d, maxdist= %6.8g\n",
     488             :              errcount-qh_MAXcheckpoint+1, facet->id, maxdist);
     489             :       }
     490             :     }
     491           0 :     if (maxdist > qh->outside_err) {
     492           0 :       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",
     493             :                 maxdist, qh->outside_err );
     494           0 :       qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
     495           0 :     }else if (errfacet1 && qh->outside_err > REALmax/2)
     496           0 :         qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2 );
     497             :     /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */
     498           0 :     trace0((qh, qh->ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist));
     499             :   }
     500           0 : } /* check_points */
     501             : 
     502             : 
     503             : /*-<a                             href="qh-poly_r.htm#TOC"
     504             :   >-------------------------------</a><a name="checkconvex">-</a>
     505             : 
     506             :   qh_checkconvex(qh, facetlist, fault )
     507             :     check that each ridge in facetlist is convex
     508             :     fault = qh_DATAfault if reporting errors from qh_initialhull with qh.ZEROcentrum
     509             :           = qh_ALGORITHMfault otherwise
     510             : 
     511             :   returns:
     512             :     counts Zconcaveridges and Zcoplanarridges
     513             :     errors if !qh.FORCEoutput ('Fo') and concaveridge or if merging a coplanar ridge
     514             :     overwrites Voronoi centers if set by qh_setvoronoi_all/qh_ASvoronoi
     515             : 
     516             :   notes:
     517             :     called by qh_initial_hull, qh_check_output, qh_all_merges ('Tc'), qh_build_withrestart ('QJ')
     518             :     does not test f.tricoplanar facets (qh_triangulate)
     519             :     must be no stronger than qh_test_appendmerge
     520             :     if not merging,
     521             :       tests vertices for neighboring simplicial facets < -qh.DISTround
     522             :     else if ZEROcentrum and simplicial facet,
     523             :       tests vertices for neighboring simplicial facets < 0.0
     524             :       tests centrums of neighboring nonsimplicial facets < 0.0
     525             :     else if ZEROcentrum
     526             :       tests centrums of neighboring facets < 0.0
     527             :     else
     528             :       tests centrums of neighboring facets < -qh.DISTround ('En' 'Rn')
     529             :     Does not test against -qh.centrum_radius since repeated computations may have different round-off errors (e.g., 'Rn')
     530             : 
     531             :   design:
     532             :     for all facets
     533             :       report flipped facets
     534             :       if ZEROcentrum and simplicial neighbors
     535             :         test vertices against neighbor
     536             :       else
     537             :         test centrum against neighbor
     538             : */
     539           3 : void qh_checkconvex(qhT *qh, facetT *facetlist, int fault) {
     540           3 :   facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
     541             :   vertexT *vertex;
     542             :   realT dist;
     543             :   pointT *centrum;
     544           3 :   boolT waserror= False, centrum_warning= False, tempcentrum= False, first_nonsimplicial= False, tested_simplicial, allsimplicial;
     545             :   int neighbor_i, neighbor_n;
     546             : 
     547           3 :   if (qh->ZEROcentrum) {
     548           3 :     trace1((qh, qh->ferr, 1064, "qh_checkconvex: check that facets are not-flipped and for qh.ZEROcentrum that simplicial vertices are below their neighbor (dist<0.0)\n"));
     549           3 :     first_nonsimplicial= True;
     550           0 :   }else if (!qh->MERGING) {
     551           0 :     trace1((qh, qh->ferr, 1026, "qh_checkconvex: check that facets are not-flipped and that simplicial vertices are convex by qh.DISTround ('En', 'Rn')\n"));
     552           0 :     first_nonsimplicial= True;
     553             :   }else
     554           0 :     trace1((qh, qh->ferr, 1062, "qh_checkconvex: check that facets are not-flipped and that their centrums are convex by qh.DISTround ('En', 'Rn') \n"));
     555           3 :   if (!qh->RERUN) {
     556           3 :     zzval_(Zconcaveridges)= 0;
     557           3 :     zzval_(Zcoplanarridges)= 0;
     558             :   }
     559          15 :   FORALLfacet_(facetlist) {
     560          12 :     if (facet->flipped) {
     561           0 :       qh_joggle_restart(qh, "flipped facet"); /* also tested by qh_checkflipped */
     562           0 :       qh_fprintf(qh, qh->ferr, 6113, "qhull precision error: f%d is flipped (interior point is outside)\n",
     563             :                facet->id);
     564           0 :       errfacet1= facet;
     565           0 :       waserror= True;
     566           0 :       continue;
     567             :     }
     568          12 :     if (facet->tricoplanar)
     569           0 :       continue;
     570          12 :     if (qh->MERGING && (!qh->ZEROcentrum || !facet->simplicial)) {
     571           0 :       allsimplicial= False;
     572           0 :       tested_simplicial= False;
     573             :     }else {
     574          12 :       allsimplicial= True;
     575          12 :       tested_simplicial= True;
     576          48 :       FOREACHneighbor_i_(qh, facet) {
     577          36 :         if (neighbor->tricoplanar)
     578           0 :           continue;
     579          36 :         if (!neighbor->simplicial) {
     580           0 :           allsimplicial= False;
     581           0 :           continue;
     582             :         }
     583          36 :         vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
     584          36 :         qh_distplane(qh, vertex->point, neighbor, &dist);
     585          36 :         if (dist >= -qh->DISTround) {
     586           0 :           if (fault == qh_DATAfault) {
     587           0 :             qh_joggle_restart(qh, "non-convex initial simplex");
     588           0 :             if (dist > qh->DISTround)
     589           0 :               qh_fprintf(qh, qh->ferr, 6114, "qhull precision error: initial simplex is not convex, since p%d(v%d) is %6.4g above opposite f%d\n",
     590             :                   qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
     591             :             else
     592           0 :               qh_fprintf(qh, qh->ferr, 6379, "qhull precision error: initial simplex is not convex, since p%d(v%d) is within roundoff of opposite facet f%d (dist %6.4g)\n",
     593             :                   qh_pointid(qh, vertex->point), vertex->id, neighbor->id, dist);
     594           0 :             qh_errexit(qh, qh_ERRsingular, neighbor, NULL);
     595             :           }
     596           0 :           if (dist > qh->DISTround) {
     597           0 :             zzinc_(Zconcaveridges);
     598           0 :             qh_joggle_restart(qh, "concave ridge");
     599           0 :             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 f%d\n",
     600             :               facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
     601           0 :             errfacet1= facet;
     602           0 :             errfacet2= neighbor;
     603           0 :             waserror= True;
     604           0 :           }else if (qh->ZEROcentrum) {
     605           0 :             if (dist > 0.0) {     /* qh_checkzero checked convex (dist < (- 2*qh->DISTround)), computation may differ e.g. 'Rn' */
     606           0 :               zzinc_(Zcoplanarridges);
     607           0 :               qh_joggle_restart(qh, "coplanar ridge");
     608           0 :               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 or coplanar with f%d with qh.ZEROcentrum\n",
     609             :                 facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id);
     610           0 :               errfacet1= facet;
     611           0 :               errfacet2= neighbor;
     612           0 :               waserror= True;
     613             :             }
     614             :           }else {
     615           0 :             zzinc_(Zcoplanarridges);
     616           0 :             qh_joggle_restart(qh, "coplanar ridge");
     617           0 :             trace0((qh, qh->ferr, 22, "qhull precision error: f%d is coplanar to f%d, since p%d(v%d) is within %6.4g of f%d, during p%d\n",
     618             :               facet->id, neighbor->id, qh_pointid(qh, vertex->point), vertex->id, dist, neighbor->id, qh->furthest_id));
     619             :           }
     620             :         }
     621             :       }
     622             :     }
     623          12 :     if (!allsimplicial) {
     624           0 :       if (first_nonsimplicial) {
     625           0 :         trace1((qh, qh->ferr, 1063, "qh_checkconvex: starting with f%d, also check that centrums of non-simplicial ridges are below their neighbors (dist<0.0)\n",
     626             :              facet->id));
     627           0 :         first_nonsimplicial= False;
     628             :       }
     629           0 :       if (qh->CENTERtype == qh_AScentrum) {
     630           0 :         if (!facet->center)
     631           0 :           facet->center= qh_getcentrum(qh, facet);
     632           0 :         centrum= facet->center;
     633             :       }else {
     634           0 :         if (!centrum_warning && !facet->simplicial) {  /* recomputed centrum correct for simplicial facets */
     635           0 :            centrum_warning= True;
     636           0 :            qh_fprintf(qh, qh->ferr, 7062, "qhull warning: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
     637             :         }
     638           0 :         centrum= qh_getcentrum(qh, facet);
     639           0 :         tempcentrum= True;
     640             :       }
     641           0 :       FOREACHneighbor_(facet) {
     642           0 :         if (neighbor->simplicial && tested_simplicial) /* tested above since f.simplicial */
     643           0 :           continue;
     644           0 :         if (neighbor->tricoplanar)
     645           0 :           continue;
     646           0 :         zzinc_(Zdistconvex);
     647           0 :         qh_distplane(qh, centrum, neighbor, &dist);
     648           0 :         if (dist > qh->DISTround) {
     649           0 :           zzinc_(Zconcaveridges);
     650           0 :           qh_joggle_restart(qh, "concave ridge");
     651           0 :           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",
     652             :             facet->id, neighbor->id, facet->id, dist, neighbor->id);
     653           0 :           errfacet1= facet;
     654           0 :           errfacet2= neighbor;
     655           0 :           waserror= True;
     656           0 :         }else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
     657             :                                      can test against centrum radius instead */
     658           0 :           zzinc_(Zcoplanarridges);
     659           0 :           qh_joggle_restart(qh, "coplanar ridge");
     660           0 :           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",
     661             :             facet->id, neighbor->id, facet->id, dist, neighbor->id);
     662           0 :           errfacet1= facet;
     663           0 :           errfacet2= neighbor;
     664           0 :           waserror= True;
     665             :         }
     666             :       }
     667           0 :       if (tempcentrum)
     668           0 :         qh_memfree(qh, centrum, qh->normal_size);
     669             :     }
     670             :   }
     671           3 :   if (waserror && !qh->FORCEoutput)
     672           0 :     qh_errexit2(qh, qh_ERRprec, errfacet1, errfacet2);
     673           3 : } /* checkconvex */
     674             : 
     675             : 
     676             : /*-<a                             href="qh-poly_r.htm#TOC"
     677             :   >-------------------------------</a><a name="checkfacet">-</a>
     678             : 
     679             :   qh_checkfacet(qh, facet, newmerge, waserror )
     680             :     checks for consistency errors in facet
     681             :     newmerge set if from merge_r.c
     682             : 
     683             :   returns:
     684             :     sets waserror if any error occurs
     685             : 
     686             :   checks:
     687             :     vertex ids are inverse sorted
     688             :     unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
     689             :     if non-simplicial, at least as many ridges as neighbors
     690             :     neighbors are not duplicated
     691             :     ridges are not duplicated
     692             :     in 3-d, ridges=verticies
     693             :     (qh.hull_dim-1) ridge vertices
     694             :     neighbors are reciprocated
     695             :     ridge neighbors are facet neighbors and a ridge for every neighbor
     696             :     simplicial neighbors match facetintersect
     697             :     vertex intersection matches vertices of common ridges
     698             :     vertex neighbors and facet vertices agree
     699             :     all ridges have distinct vertex sets
     700             : 
     701             :   notes:
     702             :     called by qh_tracemerge and qh_checkpolygon
     703             :     uses neighbor->seen
     704             : 
     705             :   design:
     706             :     check sets
     707             :     check vertices
     708             :     check sizes of neighbors and vertices
     709             :     check for qh_MERGEridge and qh_DUPLICATEridge flags
     710             :     check neighbor set
     711             :     check ridge set
     712             :     check ridges, neighbors, and vertices
     713             : */
     714          12 : void qh_checkfacet(qhT *qh, facetT *facet, boolT newmerge, boolT *waserrorp) {
     715          12 :   facetT *neighbor, **neighborp, *errother=NULL;
     716          12 :   ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
     717             :   vertexT *vertex, **vertexp;
     718          12 :   unsigned int previousid= INT_MAX;
     719          12 :   int numneighbors, numvertices, numridges=0, numRvertices=0;
     720          12 :   boolT waserror= False;
     721          12 :   int skipA, skipB, ridge_i, ridge_n, i, last_v= qh->hull_dim-2;
     722             :   setT *intersection;
     723             : 
     724          12 :   trace4((qh, qh->ferr, 4088, "qh_checkfacet: check f%d newmerge? %d\n", facet->id, newmerge));
     725          12 :   if (facet->id >= qh->facet_id) {
     726           0 :     qh_fprintf(qh, qh->ferr, 6414, "qhull internal error (qh_checkfacet): unknown facet id f%d >= qh.facet_id (%d)\n", facet->id, qh->facet_id);
     727           0 :     waserror= True;
     728             :   }
     729          12 :   if (facet->visitid > qh->visit_id) {
     730           0 :     qh_fprintf(qh, qh->ferr, 6415, "qhull internal error (qh_checkfacet): expecting f%d.visitid <= qh.visit_id (%d).  Got visitid %d\n", facet->id, qh->visit_id, facet->visitid);
     731           0 :     waserror= True;
     732             :   }
     733          12 :   if (facet->visible && !qh->NEWtentative) {
     734           0 :     qh_fprintf(qh, qh->ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on qh.visible_list\n",
     735             :       facet->id);
     736           0 :     qh_errexit(qh, qh_ERRqhull, facet, NULL);
     737             :   }
     738          12 :   if (facet->redundant && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) {
     739           0 :     qh_fprintf(qh, qh->ferr, 6399, "qhull internal error (qh_checkfacet): redundant facet f%d not on qh.visible_list\n",
     740             :       facet->id);
     741           0 :     waserror= True;
     742             :   }
     743          12 :   if (facet->degenerate && !facet->visible && qh_setsize(qh, qh->degen_mergeset)==0) {
     744           0 :     qh_fprintf(qh, qh->ferr, 6400, "qhull internal error (qh_checkfacet): degenerate facet f%d is not on qh.visible_list and qh.degen_mergeset is empty\n",
     745             :       facet->id);
     746           0 :     waserror= True;
     747             :   }
     748          12 :   if (!facet->normal) {
     749           0 :     qh_fprintf(qh, qh->ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n",
     750             :       facet->id);
     751           0 :     waserror= True;
     752             :   }
     753          12 :   if (!facet->newfacet) {
     754          12 :     if (facet->dupridge) {
     755           0 :       qh_fprintf(qh, qh->ferr, 6349, "qhull internal error (qh_checkfacet): f%d is 'dupridge' but it is not a newfacet on qh.newfacet_list f%d\n",
     756           0 :         facet->id, getid_(qh->newfacet_list));
     757           0 :       waserror= True;
     758             :     }
     759          12 :     if (facet->newmerge) {
     760           0 :       qh_fprintf(qh, qh->ferr, 6383, "qhull internal error (qh_checkfacet): f%d is 'newmerge' but it is not a newfacet on qh.newfacet_list f%d.  Missing call to qh_reducevertices\n",
     761           0 :         facet->id, getid_(qh->newfacet_list));
     762           0 :       waserror= True;
     763             :     }
     764             :   }
     765          12 :   qh_setcheck(qh, facet->vertices, "vertices for f", facet->id);
     766          12 :   qh_setcheck(qh, facet->ridges, "ridges for f", facet->id);
     767          12 :   qh_setcheck(qh, facet->outsideset, "outsideset for f", facet->id);
     768          12 :   qh_setcheck(qh, facet->coplanarset, "coplanarset for f", facet->id);
     769          12 :   qh_setcheck(qh, facet->neighbors, "neighbors for f", facet->id);
     770          48 :   FOREACHvertex_(facet->vertices) {
     771          36 :     if (vertex->deleted) {
     772           0 :       qh_fprintf(qh, qh->ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
     773           0 :       qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
     774           0 :       waserror= True;
     775             :     }
     776          36 :     if (vertex->id >= previousid) {
     777           0 :       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);
     778           0 :       waserror= True;
     779           0 :       break;
     780             :     }
     781          36 :     previousid= vertex->id;
     782             :   }
     783          12 :   numneighbors= qh_setsize(qh, facet->neighbors);
     784          12 :   numvertices= qh_setsize(qh, facet->vertices);
     785          12 :   numridges= qh_setsize(qh, facet->ridges);
     786          12 :   if (facet->simplicial) {
     787          12 :     if (numvertices+numneighbors != 2*qh->hull_dim
     788           0 :     && !facet->degenerate && !facet->redundant) {
     789           0 :       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",
     790             :                 facet->id, numvertices, numneighbors);
     791           0 :       qh_setprint(qh, qh->ferr, "", facet->neighbors);
     792           0 :       waserror= True;
     793             :     }
     794             :   }else { /* non-simplicial */
     795           0 :     if (!newmerge
     796           0 :     &&(numvertices < qh->hull_dim || numneighbors < qh->hull_dim)
     797           0 :     && !facet->degenerate && !facet->redundant) {
     798           0 :       qh_fprintf(qh, qh->ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh->hull_dim\n",
     799             :          facet->id, numvertices, numneighbors);
     800           0 :        waserror= True;
     801             :     }
     802             :     /* 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 */
     803           0 :     if (numridges < numneighbors
     804           0 :     ||(qh->hull_dim == 3 && numvertices > numridges && !qh->NEWfacets)
     805           0 :     ||(qh->hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
     806           0 :       if (!facet->degenerate && !facet->redundant) {
     807           0 :         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",
     808             :             facet->id, numridges, numneighbors, numvertices);
     809           0 :         waserror= True;
     810             :       }
     811             :     }
     812             :   }
     813          48 :   FOREACHneighbor_(facet) {
     814          36 :     if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
     815           0 :       qh_fprintf(qh, qh->ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGEridge or DUPLICATEridge neighbor\n", facet->id);
     816           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
     817             :     }
     818          36 :     if (neighbor->visible) {
     819           0 :       qh_fprintf(qh, qh->ferr, 6401, "qhull internal error (qh_checkfacet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
     820             :         facet->id, neighbor->id);
     821           0 :       errother= neighbor;
     822           0 :       waserror= True;
     823             :     }
     824          36 :     neighbor->seen= True;
     825             :   }
     826          48 :   FOREACHneighbor_(facet) {
     827          36 :     if (!qh_setin(neighbor->neighbors, facet)) {
     828           0 :       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",
     829             :               facet->id, neighbor->id, neighbor->id, facet->id);
     830           0 :       errother= neighbor;
     831           0 :       waserror= True;
     832             :     }
     833          36 :     if (!neighbor->seen) {
     834           0 :       qh_fprintf(qh, qh->ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
     835             :               facet->id, neighbor->id);
     836           0 :       errother= neighbor;
     837           0 :       waserror= True;
     838             :     }
     839          36 :     neighbor->seen= False;
     840             :   }
     841          12 :   FOREACHridge_(facet->ridges) {
     842           0 :     qh_setcheck(qh, ridge->vertices, "vertices for r", ridge->id);
     843           0 :     ridge->seen= False;
     844             :   }
     845          12 :   FOREACHridge_(facet->ridges) {
     846           0 :     if (ridge->seen) {
     847           0 :       qh_fprintf(qh, qh->ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
     848             :               facet->id, ridge->id);
     849           0 :       errridge= ridge;
     850           0 :       waserror= True;
     851             :     }
     852           0 :     ridge->seen= True;
     853           0 :     numRvertices= qh_setsize(qh, ridge->vertices);
     854           0 :     if (numRvertices != qh->hull_dim - 1) {
     855           0 :       qh_fprintf(qh, qh->ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n",
     856           0 :                 ridge->top->id, ridge->bottom->id, numRvertices);
     857           0 :       errridge= ridge;
     858           0 :       waserror= True;
     859             :     }
     860           0 :     neighbor= otherfacet_(ridge, facet);
     861           0 :     neighbor->seen= True;
     862           0 :     if (!qh_setin(facet->neighbors, neighbor)) {
     863           0 :       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",
     864             :            facet->id, neighbor->id, ridge->id);
     865           0 :       errridge= ridge;
     866           0 :       waserror= True;
     867             :     }
     868           0 :     if (!facet->newfacet && !neighbor->newfacet) {
     869           0 :       if ((!ridge->tested) | ridge->nonconvex | ridge->mergevertex) {
     870           0 :         qh_fprintf(qh, qh->ferr, 6384, "qhull internal error (qh_checkfacet): ridge r%d is nonconvex (%d), mergevertex (%d) or not tested (%d) for facet f%d, neighbor f%d\n",
     871           0 :           ridge->id, ridge->nonconvex, ridge->mergevertex, ridge->tested, facet->id, neighbor->id);
     872           0 :         errridge= ridge;
     873           0 :         waserror= True;
     874             :       }
     875             :     }
     876             :   }
     877          12 :   if (!facet->simplicial) {
     878           0 :     FOREACHneighbor_(facet) {
     879           0 :       if (!neighbor->seen) {
     880           0 :         qh_fprintf(qh, qh->ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
     881             :               facet->id, neighbor->id);
     882           0 :         errother= neighbor;
     883           0 :         waserror= True;
     884             :       }
     885           0 :       intersection= qh_vertexintersect_new(qh, facet->vertices, neighbor->vertices);
     886           0 :       qh_settemppush(qh, intersection);
     887           0 :       FOREACHvertex_(facet->vertices) {
     888           0 :         vertex->seen= False;
     889           0 :         vertex->seen2= False;
     890             :       }
     891           0 :       FOREACHvertex_(intersection)
     892           0 :         vertex->seen= True;
     893           0 :       FOREACHridge_(facet->ridges) {
     894           0 :         if (neighbor != otherfacet_(ridge, facet))
     895           0 :             continue;
     896           0 :         FOREACHvertex_(ridge->vertices) {
     897           0 :           if (!vertex->seen) {
     898           0 :             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",
     899             :                   vertex->id, ridge->id, facet->id, neighbor->id);
     900           0 :             qh_errexit(qh, qh_ERRqhull, facet, ridge);
     901             :           }
     902           0 :           vertex->seen2= True;
     903             :         }
     904             :       }
     905           0 :       if (!newmerge) {
     906           0 :         FOREACHvertex_(intersection) {
     907           0 :           if (!vertex->seen2) {
     908           0 :             if (!qh->MERGING) {
     909           0 :               qh_fprintf(qh, qh->ferr, 6420, "qhull topology error (qh_checkfacet): vertex v%d in f%d intersect f%d but not in a ridge.  Last point was p%d\n",
     910             :                      vertex->id, facet->id, neighbor->id, qh->furthest_id);
     911           0 :               if (!qh->FORCEoutput) {
     912           0 :                 qh_errprint(qh, "ERRONEOUS", facet, neighbor, NULL, vertex);
     913           0 :                 qh_errexit(qh, qh_ERRtopology, NULL, NULL);
     914             :               }
     915             :             }else {
     916           0 :               trace4((qh, qh->ferr, 4025, "qh_checkfacet: vertex v%d in f%d intersect f%d but not in a ridge.  Repaired by qh_remove_extravertices in qh_reducevertices\n",
     917             :                 vertex->id, facet->id, neighbor->id));
     918             :             }
     919             :           }
     920             :         }
     921             :       }
     922           0 :       qh_settempfree(qh, &intersection);
     923             :     }
     924             :   }else { /* simplicial */
     925          48 :     FOREACHneighbor_(facet) {
     926          36 :       if (neighbor->simplicial && !facet->degenerate && !neighbor->degenerate) {
     927          36 :         skipA= SETindex_(facet->neighbors, neighbor);
     928          36 :         skipB= qh_setindex(neighbor->neighbors, facet);
     929          36 :         if (skipA<0 || skipB<0 || !qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) {
     930           0 :           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",
     931             :                    facet->id, skipA, neighbor->id, skipB);
     932           0 :           errother= neighbor;
     933           0 :           waserror= True;
     934             :         }
     935             :       }
     936             :     }
     937             :   }
     938          12 :   if (!newmerge && qh->CHECKduplicates && qh->hull_dim < 5 && (qh->IStracing > 2 || qh->CHECKfrequently)) {
     939           0 :     FOREACHridge_i_(qh, facet->ridges) {           /* expensive, if was merge and qh_maybe_duplicateridges hasn't been called yet */
     940           0 :       if (!ridge->mergevertex) {
     941           0 :         for (i=ridge_i+1; i < ridge_n; i++) {
     942           0 :           ridge2= SETelemt_(facet->ridges, i, ridgeT);
     943           0 :           if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
     944           0 :             if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
     945           0 :               if (qh_setequal(ridge->vertices, ridge2->vertices)) {
     946           0 :                 qh_fprintf(qh, qh->ferr, 6294, "qhull internal error (qh_checkfacet): ridges r%d and r%d (f%d) have the same vertices\n", /* same as duplicate ridge */
     947             :                     ridge->id, ridge2->id, facet->id);
     948           0 :                 errridge= ridge;
     949           0 :                 waserror= True;
     950             :               }
     951             :             }
     952             :           }
     953             :         }
     954             :       }
     955             :     }
     956             :   }
     957          12 :   if (waserror) {
     958           0 :     qh_errprint(qh, "ERRONEOUS", facet, errother, errridge, NULL);
     959           0 :     *waserrorp= True;
     960             :   }
     961          12 : } /* checkfacet */
     962             : 
     963             : /*-<a                             href="qh-poly_r.htm#TOC"
     964             :   >-------------------------------</a><a name="checkflipped_all">-</a>
     965             : 
     966             :   qh_checkflipped_all(qh, facetlist )
     967             :     checks orientation of facets in list against interior point
     968             : 
     969             :   notes:
     970             :     called by qh_checkoutput
     971             : */
     972           0 : void qh_checkflipped_all(qhT *qh, facetT *facetlist) {
     973             :   facetT *facet;
     974           0 :   boolT waserror= False;
     975             :   realT dist;
     976             : 
     977           0 :   if (facetlist == qh->facet_list)
     978           0 :     zzval_(Zflippedfacets)= 0;
     979           0 :   FORALLfacet_(facetlist) {
     980           0 :     if (facet->normal && !qh_checkflipped(qh, facet, &dist, !qh_ALL)) {
     981           0 :       qh_fprintf(qh, qh->ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
     982             :               facet->id, dist);
     983           0 :       if (!qh->FORCEoutput) {
     984           0 :         qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, NULL);
     985           0 :         waserror= True;
     986             :       }
     987             :     }
     988             :   }
     989           0 :   if (waserror) {
     990           0 :     qh_fprintf(qh, qh->ferr, 8101, "\n\
     991             : A flipped facet occurs when its distance to the interior point is\n\
     992           0 : greater than or equal to %2.2g, the maximum roundoff error.\n", -qh->DISTround);
     993           0 :     qh_errexit(qh, qh_ERRprec, NULL, NULL);
     994             :   }
     995           0 : } /* checkflipped_all */
     996             : 
     997             : /*-<a                             href="qh-poly_r.htm#TOC"
     998             :   >-------------------------------</a><a name="checklists">-</a>
     999             : 
    1000             :   qh_checklists(qh, facetlist )
    1001             :     Check and repair facetlist and qh.vertex_list for infinite loops or overwritten facets
    1002             :     Checks that qh.newvertex_list is on qh.vertex_list
    1003             :     if facetlist is qh.facet_list
    1004             :       Checks that qh.visible_list and qh.newfacet_list are on qh.facet_list
    1005             :     Updates qh.facetvisit and qh.vertexvisit
    1006             : 
    1007             :   returns:
    1008             :     True if no errors found
    1009             :     If false, repairs erroneous lists to prevent infinite loops by FORALL macros
    1010             : 
    1011             :   notes:
    1012             :     called by qh_buildtracing, qh_checkpolygon, qh_collectstatistics, qh_printfacetlist, qh_printsummary
    1013             :     not called by qh_printlists
    1014             : 
    1015             :   design:
    1016             :     if facetlist
    1017             :       check qh.facet_tail
    1018             :       for each facet
    1019             :         check for infinite loop or overwritten facet
    1020             :         check previous facet
    1021             :       if facetlist is qh.facet_list
    1022             :         check qh.next_facet, qh.visible_list and qh.newfacet_list
    1023             :     if vertexlist
    1024             :       check qh.vertex_tail
    1025             :       for each vertex
    1026             :         check for infinite loop or overwritten vertex
    1027             :         check previous vertex
    1028             :       check qh.newvertex_list
    1029             : */
    1030           3 : boolT qh_checklists(qhT *qh, facetT *facetlist) {
    1031           3 :   facetT *facet, *errorfacet= NULL, *errorfacet2= NULL, *previousfacet;
    1032           3 :   vertexT *vertex, *vertexlist, *previousvertex, *errorvertex= NULL;
    1033           3 :   boolT waserror= False, newseen= False, nextseen= False, newvertexseen= False, visibleseen= False;
    1034             : 
    1035           3 :   if (facetlist == qh->newfacet_list || facetlist == qh->visible_list) {
    1036           0 :     vertexlist= qh->vertex_list;
    1037           0 :     previousvertex= NULL;
    1038           0 :     trace2((qh, qh->ferr, 2110, "qh_checklists: check qh.%s_list f%d and qh.vertex_list v%d\n",
    1039             :         (facetlist == qh->newfacet_list ? "newfacet" : "visible"), facetlist->id, getid_(vertexlist)));
    1040             :   }else {
    1041           3 :     vertexlist= qh->vertex_list;
    1042           3 :     previousvertex= NULL;
    1043           3 :     trace2((qh, qh->ferr, 2111, "qh_checklists: check %slist f%d and qh.vertex_list v%d\n",
    1044             :         (facetlist == qh->facet_list ? "qh.facet_" : "facet"), getid_(facetlist), getid_(vertexlist)));
    1045             :   }
    1046           3 :   if (facetlist) {
    1047           3 :     if (qh->facet_tail == NULL || qh->facet_tail->id != 0 || qh->facet_tail->next != NULL) {
    1048           0 :       qh_fprintf(qh, qh->ferr, 6397, "qhull internal error (qh_checklists): either qh.facet_tail f%d is NULL, or its id is not 0, or its next is not NULL\n",
    1049           0 :           getid_(qh->facet_tail));
    1050           0 :       qh_errexit(qh, qh_ERRqhull, qh->facet_tail, NULL);
    1051             :     }
    1052           3 :     previousfacet= (facetlist == qh->facet_list ? NULL : facetlist->previous);
    1053           3 :     qh->visit_id++;
    1054          15 :     FORALLfacet_(facetlist) {
    1055          12 :       if (facet->visitid >= qh->visit_id || facet->id >= qh->facet_id) {
    1056           0 :         waserror= True;
    1057           0 :         errorfacet= facet;
    1058           0 :         errorfacet2= previousfacet;
    1059           0 :         if (facet->visitid == qh->visit_id)
    1060           0 :           qh_fprintf(qh, qh->ferr, 6039, "qhull internal error (qh_checklists): f%d already in facetlist causing an infinite loop ... f%d > f%d ... > f%d > f%d.  Truncate facetlist at f%d\n",
    1061           0 :             facet->id, facet->id, facet->next->id, getid_(previousfacet), facet->id, getid_(previousfacet));
    1062             :         else
    1063           0 :           qh_fprintf(qh, qh->ferr, 6350, "qhull internal error (qh_checklists): unknown or overwritten facet f%d, either id >= qh.facet_id (%d) or f.visitid %u > qh.visit_id %u.  Facetlist terminated at previous facet f%d\n",
    1064           0 :               facet->id, qh->facet_id, facet->visitid, qh->visit_id, getid_(previousfacet));
    1065           0 :         if (previousfacet)
    1066           0 :           previousfacet->next= qh->facet_tail;
    1067             :         else
    1068           0 :           facetlist= qh->facet_tail;
    1069           0 :         break;
    1070             :       }
    1071          12 :       facet->visitid= qh->visit_id;
    1072          12 :       if (facet->previous != previousfacet) {
    1073           0 :         qh_fprintf(qh, qh->ferr, 6416, "qhull internal error (qh_checklists): expecting f%d.previous == f%d.  Got f%d\n",
    1074           0 :           facet->id, getid_(previousfacet), getid_(facet->previous));
    1075           0 :         waserror= True;
    1076           0 :         errorfacet= facet;
    1077           0 :         errorfacet2= facet->previous;
    1078             :       }
    1079          12 :       previousfacet= facet;
    1080          12 :       if (facetlist == qh->facet_list) {
    1081          12 :         if (facet == qh->visible_list) {
    1082           0 :           if(newseen){
    1083           0 :             qh_fprintf(qh, qh->ferr, 6285, "qhull internal error (qh_checklists): qh.visible_list f%d is after qh.newfacet_list f%d.  It should be at, before, or NULL\n",
    1084           0 :               facet->id, getid_(qh->newfacet_list));
    1085           0 :             waserror= True;
    1086           0 :             errorfacet= facet;
    1087           0 :             errorfacet2= qh->newfacet_list;
    1088             :           }
    1089           0 :           visibleseen= True;
    1090             :         }
    1091          12 :         if (facet == qh->newfacet_list)
    1092           0 :           newseen= True;
    1093          12 :         if (facet == qh->facet_next)
    1094           3 :           nextseen= True;
    1095             :       }
    1096             :     }
    1097           3 :     if (facetlist == qh->facet_list) {
    1098           3 :       if (!nextseen && qh->facet_next && qh->facet_next->next) {
    1099           0 :         qh_fprintf(qh, qh->ferr, 6369, "qhull internal error (qh_checklists): qh.facet_next f%d for qh_addpoint is not on qh.facet_list f%d\n",
    1100           0 :           qh->facet_next->id, facetlist->id);
    1101           0 :         waserror= True;
    1102           0 :         errorfacet= qh->facet_next;
    1103           0 :         errorfacet2= facetlist;
    1104             :       }
    1105           3 :       if (!newseen && qh->newfacet_list && qh->newfacet_list->next) {
    1106           0 :         qh_fprintf(qh, qh->ferr, 6286, "qhull internal error (qh_checklists): qh.newfacet_list f%d is not on qh.facet_list f%d\n",
    1107           0 :           qh->newfacet_list->id, facetlist->id);
    1108           0 :         waserror= True;
    1109           0 :         errorfacet= qh->newfacet_list;
    1110           0 :         errorfacet2= facetlist;
    1111             :       }
    1112           3 :       if (!visibleseen && qh->visible_list && qh->visible_list->next) {
    1113           0 :         qh_fprintf(qh, qh->ferr, 6138, "qhull internal error (qh_checklists): qh.visible_list f%d is not on qh.facet_list f%d\n",
    1114           0 :           qh->visible_list->id, facetlist->id);
    1115           0 :         waserror= True;
    1116           0 :         errorfacet= qh->visible_list;
    1117           0 :         errorfacet2= facetlist;
    1118             :       }
    1119             :     }
    1120             :   }
    1121           3 :   if (vertexlist) {
    1122           3 :     if (qh->vertex_tail == NULL || qh->vertex_tail->id != 0 || qh->vertex_tail->next != NULL) {
    1123           0 :       qh_fprintf(qh, qh->ferr, 6366, "qhull internal error (qh_checklists): either qh.vertex_tail v%d is NULL, or its id is not 0, or its next is not NULL\n",
    1124           0 :            getid_(qh->vertex_tail));
    1125           0 :       qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, qh->vertex_tail);
    1126           0 :       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    1127             :     }
    1128           3 :     qh->vertex_visit++;
    1129          15 :     FORALLvertex_(vertexlist) {
    1130          12 :       if (vertex->visitid >= qh->vertex_visit || vertex->id >= qh->vertex_id) {
    1131           0 :         waserror= True;
    1132           0 :         errorvertex= vertex;
    1133           0 :         if (vertex->visitid == qh->visit_id)
    1134           0 :           qh_fprintf(qh, qh->ferr, 6367, "qhull internal error (qh_checklists): v%d already in vertexlist causing an infinite loop ... v%d > v%d ... > v%d > v%d.  Truncate vertexlist at v%d\n",
    1135           0 :             vertex->id, vertex->id, vertex->next->id, getid_(previousvertex), vertex->id, getid_(previousvertex));
    1136             :         else
    1137           0 :           qh_fprintf(qh, qh->ferr, 6368, "qhull internal error (qh_checklists): unknown or overwritten vertex v%d, either id >= qh.vertex_id (%d) or v.visitid %u > qh.visit_id %u.  vertexlist terminated at previous vertex v%d\n",
    1138           0 :             vertex->id, qh->vertex_id, vertex->visitid, qh->visit_id, getid_(previousvertex));
    1139           0 :         if (previousvertex)
    1140           0 :           previousvertex->next= qh->vertex_tail;
    1141             :         else
    1142           0 :           vertexlist= qh->vertex_tail;
    1143           0 :         break;
    1144             :       }
    1145          12 :       vertex->visitid= qh->vertex_visit;
    1146          12 :       if (vertex->previous != previousvertex) {
    1147           0 :         qh_fprintf(qh, qh->ferr, 6427, "qhull internal error (qh_checklists): expecting v%d.previous == v%d.  Got v%d\n",
    1148           0 :               vertex->id, previousvertex, getid_(vertex->previous));
    1149           0 :         waserror= True;
    1150           0 :         errorvertex= vertex;
    1151             :       }
    1152          12 :       previousvertex= vertex;
    1153          12 :       if(vertex == qh->newvertex_list)
    1154           0 :         newvertexseen= True;
    1155             :     }
    1156           3 :     if(!newvertexseen && qh->newvertex_list && qh->newvertex_list->next) {
    1157           0 :       qh_fprintf(qh, qh->ferr, 6287, "qhull internal error (qh_checklists): new vertex list v%d is not on vertex list\n", qh->newvertex_list->id);
    1158           0 :       waserror= True;
    1159           0 :       errorvertex= qh->newvertex_list;
    1160             :     }
    1161             :   }
    1162           3 :   if (waserror) {
    1163           0 :     qh_errprint(qh, "ERRONEOUS", errorfacet, errorfacet2, NULL, errorvertex);
    1164           0 :     return False;
    1165             :   }
    1166           3 :   return True;
    1167             : } /* checklists */
    1168             : 
    1169             : /*-<a                             href="qh-poly_r.htm#TOC"
    1170             :   >-------------------------------</a><a name="checkpolygon">-</a>
    1171             : 
    1172             :   qh_checkpolygon(qh, facetlist )
    1173             :     checks the correctness of the structure
    1174             : 
    1175             :   notes:
    1176             :     called by qh_addpoint, qh_all_vertexmerge, qh_check_output, qh_initialhull, qh_prepare_output, qh_triangulate
    1177             :     call with qh.facet_list or qh.newfacet_list or another list
    1178             :     checks num_facets and num_vertices if qh.facet_list
    1179             : 
    1180             :   design:
    1181             :     check and repair lists for infinite loop
    1182             :     for each facet
    1183             :       check f.newfacet and f.visible
    1184             :       check facet and outside set if qh.NEWtentative and not f.newfacet, or not f.visible
    1185             :     initializes vertexlist for qh.facet_list or qh.newfacet_list
    1186             :     for each vertex
    1187             :       check vertex
    1188             :       check v.newfacet
    1189             :     for each facet
    1190             :       count f.ridges
    1191             :       check and count f.vertices
    1192             :     if checking qh.facet_list
    1193             :       check facet count
    1194             :       if qh.VERTEXneighbors
    1195             :         check and count v.neighbors for all vertices
    1196             :         check v.neighbors count and report possible causes of mismatch
    1197             :         check that facets are in their v.neighbors
    1198             :       check vertex count
    1199             : */
    1200           3 : void qh_checkpolygon(qhT *qh, facetT *facetlist) {
    1201             :   facetT *facet, *neighbor, **neighborp;
    1202           3 :   facetT *errorfacet= NULL, *errorfacet2= NULL;
    1203             :   vertexT *vertex, **vertexp, *vertexlist;
    1204           3 :   int numfacets= 0, numvertices= 0, numridges= 0;
    1205           3 :   int totvneighbors= 0, totfacetvertices= 0;
    1206           3 :   boolT waserror= False, newseen= False, newvertexseen= False, nextseen= False, visibleseen= False;
    1207             :   boolT checkfacet;
    1208             : 
    1209           3 :   trace1((qh, qh->ferr, 1027, "qh_checkpolygon: check all facets from f%d, qh.NEWtentative? %d\n", facetlist->id, qh->NEWtentative));
    1210           3 :   if (!qh_checklists(qh, facetlist)) {
    1211           0 :     waserror= True;
    1212           0 :     qh_fprintf(qh, qh->ferr, 6374, "qhull internal error: qh_checklists failed in qh_checkpolygon\n");
    1213           0 :     if (qh->num_facets < 4000)
    1214           0 :       qh_printlists(qh);
    1215             :   }
    1216           3 :   if (facetlist != qh->facet_list || qh->ONLYgood)
    1217           0 :     nextseen= True; /* allow f.outsideset */
    1218          15 :   FORALLfacet_(facetlist) {
    1219          12 :     if (facet == qh->visible_list)
    1220           0 :       visibleseen= True;
    1221          12 :     if (facet == qh->newfacet_list)
    1222           0 :       newseen= True;
    1223          12 :     if (facet->newfacet && !newseen && !visibleseen) {
    1224           0 :         qh_fprintf(qh, qh->ferr, 6289, "qhull internal error (qh_checkpolygon): f%d is 'newfacet' but it is not on qh.newfacet_list f%d or visible_list f%d\n",  facet->id, getid_(qh->newfacet_list), getid_(qh->visible_list));
    1225           0 :         qh_errexit(qh, qh_ERRqhull, facet, NULL);
    1226             :     }
    1227          12 :     if (!facet->newfacet && newseen) {
    1228           0 :         qh_fprintf(qh, qh->ferr, 6292, "qhull internal error (qh_checkpolygon): f%d is on qh.newfacet_list f%d but it is not 'newfacet'\n",  facet->id, getid_(qh->newfacet_list));
    1229           0 :         qh_errexit(qh, qh_ERRqhull, facet, NULL);
    1230             :     }
    1231          12 :     if (facet->visible != (visibleseen & !newseen)) {
    1232           0 :       if(facet->visible)
    1233           0 :         qh_fprintf(qh, qh->ferr, 6290, "qhull internal error (qh_checkpolygon): f%d is 'visible' but it is not on qh.visible_list f%d\n", facet->id, getid_(qh->visible_list));
    1234             :       else
    1235           0 :         qh_fprintf(qh, qh->ferr, 6291, "qhull internal error (qh_checkpolygon): f%d is on qh.visible_list f%d but it is not 'visible'\n", facet->id, qh->newfacet_list->id);
    1236           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
    1237             :     }
    1238          12 :     if (qh->NEWtentative) {
    1239           0 :       checkfacet= !facet->newfacet;
    1240             :     }else {
    1241          12 :       checkfacet= !facet->visible;
    1242             :     }
    1243          12 :     if(checkfacet) {
    1244          12 :       if (!nextseen) {
    1245           3 :         if (facet == qh->facet_next)  /* previous facets do not have outsideset */
    1246           3 :           nextseen= True;
    1247           0 :         else if (qh_setsize(qh, facet->outsideset)) {
    1248           0 :           if (!qh->NARROWhull
    1249             : #if !qh_COMPUTEfurthest
    1250           0 :           || facet->furthestdist >= qh->MINoutside
    1251             : #endif
    1252             :           ) {
    1253           0 :             qh_fprintf(qh, qh->ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh.facet_next f%d\n",
    1254           0 :                      facet->id, getid_(qh->facet_next));
    1255           0 :             qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_next);
    1256             :           }
    1257             :         }
    1258             :       }
    1259          12 :       numfacets++;
    1260          12 :       qh_checkfacet(qh, facet, False, &waserror);
    1261           0 :     }else if (facet->visible && qh->NEWfacets) {
    1262           0 :       if (!SETempty_(facet->neighbors) || !SETempty_(facet->ridges)) {
    1263           0 :         qh_fprintf(qh, qh->ferr, 6376, "qhull internal error (qh_checkpolygon): expecting empty f.neighbors and f.ridges for visible facet f%d.  Got %d neighbors and %d ridges\n",
    1264             :           facet->id, qh_setsize(qh, facet->neighbors), qh_setsize(qh, facet->ridges));
    1265           0 :         qh_errexit(qh, qh_ERRqhull, facet, NULL);
    1266             :       }
    1267             :     }
    1268             :   }
    1269           3 :   if (facetlist == qh->facet_list) {
    1270           3 :     vertexlist= qh->vertex_list;
    1271           0 :   }else if (facetlist == qh->newfacet_list) {
    1272           0 :     vertexlist= qh->newvertex_list;
    1273             :   }else {
    1274           0 :     vertexlist= NULL;
    1275             :   }
    1276          15 :   FORALLvertex_(vertexlist) {
    1277          12 :     qh_checkvertex(qh, vertex, !qh_ALL, &waserror);
    1278          12 :     if(vertex == qh->newvertex_list)
    1279           0 :       newvertexseen= True;
    1280          12 :     vertex->seen= False;
    1281          12 :     vertex->visitid= 0;
    1282          12 :     if(vertex->newfacet && !newvertexseen && !vertex->deleted) {
    1283           0 :       qh_fprintf(qh, qh->ferr, 6288, "qhull internal error (qh_checkpolygon): v%d is 'newfacet' but it is not on new vertex list v%d\n", vertex->id, getid_(qh->newvertex_list));
    1284           0 :       qh_errexit(qh, qh_ERRqhull, qh->visible_list, NULL);
    1285             :     }
    1286             :   }
    1287          15 :   FORALLfacet_(facetlist) {
    1288          12 :     if (facet->visible)
    1289           0 :       continue;
    1290          12 :     if (facet->simplicial)
    1291          12 :       numridges += qh->hull_dim;
    1292             :     else
    1293           0 :       numridges += qh_setsize(qh, facet->ridges);
    1294          48 :     FOREACHvertex_(facet->vertices) {
    1295          36 :       vertex->visitid++;
    1296          36 :       if (!vertex->seen) {
    1297          12 :         vertex->seen= True;
    1298          12 :         numvertices++;
    1299          12 :         if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
    1300           0 :           qh_fprintf(qh, qh->ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
    1301             :                    vertex->point, vertex->id, qh->first_point);
    1302           0 :           waserror= True;
    1303             :         }
    1304             :       }
    1305             :     }
    1306             :   }
    1307           3 :   qh->vertex_visit += (unsigned int)numfacets;
    1308           3 :   if (facetlist == qh->facet_list) {
    1309           3 :     if (numfacets != qh->num_facets - qh->num_visible) {
    1310           0 :       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",
    1311             :               numfacets, qh->num_facets, qh->num_visible);
    1312           0 :       waserror= True;
    1313             :     }
    1314           3 :     qh->vertex_visit++;
    1315           3 :     if (qh->VERTEXneighbors) {
    1316           0 :       FORALLvertices {
    1317           0 :         if (!vertex->neighbors) {
    1318           0 :           qh_fprintf(qh, qh->ferr, 6407, "qhull internal error (qh_checkpolygon): missing vertex neighbors for v%d\n", vertex->id);
    1319           0 :           waserror= True;
    1320             :         }
    1321           0 :         qh_setcheck(qh, vertex->neighbors, "neighbors for v", vertex->id);
    1322           0 :         if (vertex->deleted)
    1323           0 :           continue;
    1324           0 :         totvneighbors += qh_setsize(qh, vertex->neighbors);
    1325             :       }
    1326           0 :       FORALLfacet_(facetlist) {
    1327           0 :         if (!facet->visible)
    1328           0 :           totfacetvertices += qh_setsize(qh, facet->vertices);
    1329             :       }
    1330           0 :       if (totvneighbors != totfacetvertices) {
    1331           0 :         qh_fprintf(qh, qh->ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent (tot_vneighbors %d != tot_facetvertices %d).  Maybe duplicate or missing vertex\n",
    1332             :                 totvneighbors, totfacetvertices);
    1333           0 :         waserror= True;
    1334           0 :         FORALLvertices {
    1335           0 :           if (vertex->deleted)
    1336           0 :             continue;
    1337           0 :           qh->visit_id++;
    1338           0 :           FOREACHneighbor_(vertex) {
    1339           0 :             if (neighbor->visitid==qh->visit_id) {
    1340           0 :               qh_fprintf(qh, qh->ferr, 6275, "qhull internal error (qh_checkpolygon): facet f%d occurs twice in neighbors of vertex v%d\n",
    1341             :                   neighbor->id, vertex->id);
    1342           0 :               errorfacet2= errorfacet;
    1343           0 :               errorfacet= neighbor;
    1344             :             }
    1345           0 :             neighbor->visitid= qh->visit_id;
    1346           0 :             if (!qh_setin(neighbor->vertices, vertex)) {
    1347           0 :               qh_fprintf(qh, qh->ferr, 6276, "qhull internal error (qh_checkpolygon): facet f%d is a neighbor of vertex v%d but v%d is not a vertex of f%d\n",
    1348             :                   neighbor->id, vertex->id, vertex->id, neighbor->id);
    1349           0 :               errorfacet2= errorfacet;
    1350           0 :               errorfacet= neighbor;
    1351             :             }
    1352             :           }
    1353             :         }
    1354           0 :         FORALLfacet_(facetlist){
    1355           0 :           if (!facet->visible) {
    1356             :             /* vertices are inverse sorted and are unlikely to be duplicated */
    1357           0 :             FOREACHvertex_(facet->vertices){
    1358           0 :               if (!qh_setin(vertex->neighbors, facet)) {
    1359           0 :                 qh_fprintf(qh, qh->ferr, 6277, "qhull internal error (qh_checkpolygon): v%d is a vertex of facet f%d but f%d is not a neighbor of v%d\n",
    1360             :                   vertex->id, facet->id, facet->id, vertex->id);
    1361           0 :                 errorfacet2= errorfacet;
    1362           0 :                 errorfacet= facet;
    1363             :               }
    1364             :             }
    1365             :           }
    1366             :         }
    1367             :       }
    1368             :     }
    1369           3 :     if (numvertices != qh->num_vertices - qh_setsize(qh, qh->del_vertices)) {
    1370           0 :       qh_fprintf(qh, qh->ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
    1371           0 :               numvertices, qh->num_vertices - qh_setsize(qh, qh->del_vertices));
    1372           0 :       waserror= True;
    1373             :     }
    1374           3 :     if (qh->hull_dim == 2 && numvertices != numfacets) {
    1375           0 :       qh_fprintf(qh, qh->ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
    1376             :         numvertices, numfacets);
    1377           0 :       waserror= True;
    1378             :     }
    1379           3 :     if (qh->hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
    1380           0 :       qh_fprintf(qh, qh->ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2.  A vertex appears twice in a edge list.  May occur during merging.\n",
    1381             :           numvertices, numfacets, numridges/2);
    1382             :       /* 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 */
    1383             :     }
    1384             :   }
    1385           3 :   if (waserror)
    1386           0 :     qh_errexit2(qh, qh_ERRqhull, errorfacet, errorfacet2);
    1387           3 : } /* checkpolygon */
    1388             : 
    1389             : 
    1390             : /*-<a                             href="qh-poly_r.htm#TOC"
    1391             :   >-------------------------------</a><a name="checkvertex">-</a>
    1392             : 
    1393             :   qh_checkvertex(qh, vertex, allchecks, &waserror )
    1394             :     check vertex for consistency
    1395             :     if allchecks, checks vertex->neighbors
    1396             : 
    1397             :   returns:
    1398             :     sets waserror if any error occurs
    1399             : 
    1400             :   notes:
    1401             :     called by qh_tracemerge and qh_checkpolygon
    1402             :     neighbors checked efficiently in qh_checkpolygon
    1403             : */
    1404          12 : void qh_checkvertex(qhT *qh, vertexT *vertex, boolT allchecks, boolT *waserrorp) {
    1405          12 :   boolT waserror= False;
    1406          12 :   facetT *neighbor, **neighborp, *errfacet=NULL;
    1407             : 
    1408          12 :   if (qh_pointid(qh, vertex->point) == qh_IDunknown) {
    1409           0 :     qh_fprintf(qh, qh->ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
    1410           0 :     waserror= True;
    1411             :   }
    1412          12 :   if (vertex->id >= qh->vertex_id) {
    1413           0 :     qh_fprintf(qh, qh->ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id v%d >= qh.vertex_id (%d)\n", vertex->id, qh->vertex_id);
    1414           0 :     waserror= True;
    1415             :   }
    1416          12 :   if (vertex->visitid > qh->vertex_visit) {
    1417           0 :     qh_fprintf(qh, qh->ferr, 6413, "qhull internal error (qh_checkvertex): expecting v%d.visitid <= qh.vertex_visit (%d).  Got visitid %d\n", vertex->id, qh->vertex_visit, vertex->visitid);
    1418           0 :     waserror= True;
    1419             :   }
    1420          12 :   if (allchecks && !waserror && !vertex->deleted) {
    1421           0 :     if (qh_setsize(qh, vertex->neighbors)) {
    1422           0 :       FOREACHneighbor_(vertex) {
    1423           0 :         if (!qh_setin(neighbor->vertices, vertex)) {
    1424           0 :           qh_fprintf(qh, qh->ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
    1425           0 :           errfacet= neighbor;
    1426           0 :           waserror= True;
    1427             :         }
    1428             :       }
    1429             :     }
    1430             :   }
    1431          12 :   if (waserror) {
    1432           0 :     qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
    1433           0 :     if (errfacet)
    1434           0 :       qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
    1435           0 :     *waserrorp= True;
    1436             :   }
    1437          12 : } /* checkvertex */
    1438             : 
    1439             : /*-<a                             href="qh-poly_r.htm#TOC"
    1440             :   >-------------------------------</a><a name="clearcenters">-</a>
    1441             : 
    1442             :   qh_clearcenters(qh, type )
    1443             :     clear old data from facet->center
    1444             : 
    1445             :   notes:
    1446             :     sets new centertype
    1447             :     nop if CENTERtype is the same
    1448             : */
    1449           0 : void qh_clearcenters(qhT *qh, qh_CENTER type) {
    1450             :   facetT *facet;
    1451             : 
    1452           0 :   if (qh->CENTERtype != type) {
    1453           0 :     FORALLfacets {
    1454           0 :       if (facet->tricoplanar && !facet->keepcentrum)
    1455           0 :           facet->center= NULL;  /* center is owned by the ->keepcentrum facet */
    1456           0 :       else if (qh->CENTERtype == qh_ASvoronoi){
    1457           0 :         if (facet->center) {
    1458           0 :           qh_memfree(qh, facet->center, qh->center_size);
    1459           0 :           facet->center= NULL;
    1460             :         }
    1461             :       }else /* qh.CENTERtype == qh_AScentrum */ {
    1462           0 :         if (facet->center) {
    1463           0 :           qh_memfree(qh, facet->center, qh->normal_size);
    1464           0 :           facet->center= NULL;
    1465             :         }
    1466             :       }
    1467             :     }
    1468           0 :     qh->CENTERtype= type;
    1469             :   }
    1470           0 :   trace2((qh, qh->ferr, 2043, "qh_clearcenters: switched to center type %d\n", type));
    1471           0 : } /* clearcenters */
    1472             : 
    1473             : /*-<a                             href="qh-poly_r.htm#TOC"
    1474             :   >-------------------------------</a><a name="createsimplex">-</a>
    1475             : 
    1476             :   qh_createsimplex(qh, vertices )
    1477             :     creates a simplex from a set of vertices
    1478             : 
    1479             :   returns:
    1480             :     initializes qh.facet_list to the simplex
    1481             : 
    1482             :   notes:
    1483             :     only called by qh_initialhull
    1484             : 
    1485             :   design:
    1486             :     for each vertex
    1487             :       create a new facet
    1488             :     for each new facet
    1489             :       create its neighbor set
    1490             : */
    1491           4 : void qh_createsimplex(qhT *qh, setT *vertices /* qh.facet_list */) {
    1492           4 :   facetT *facet= NULL, *newfacet;
    1493           4 :   boolT toporient= True;
    1494             :   int vertex_i, vertex_n, nth;
    1495           4 :   setT *newfacets= qh_settemp(qh, qh->hull_dim+1);
    1496             :   vertexT *vertex;
    1497             : 
    1498          20 :   FOREACHvertex_i_(qh, vertices) {
    1499          16 :     newfacet= qh_newfacet(qh);
    1500          16 :     newfacet->vertices= qh_setnew_delnthsorted(qh, vertices, vertex_n, vertex_i, 0);
    1501          16 :     if (toporient)
    1502           8 :       newfacet->toporient= True;
    1503          16 :     qh_appendfacet(qh, newfacet);
    1504          16 :     newfacet->newfacet= True;
    1505          16 :     qh_appendvertex(qh, vertex);
    1506          16 :     qh_setappend(qh, &newfacets, newfacet);
    1507          16 :     toporient ^= True;
    1508             :   }
    1509          20 :   FORALLnew_facets {
    1510          16 :     nth= 0;
    1511          80 :     FORALLfacet_(qh->newfacet_list) {
    1512          64 :       if (facet != newfacet)
    1513          48 :         SETelem_(newfacet->neighbors, nth++)= facet;
    1514             :     }
    1515          16 :     qh_settruncate(qh, newfacet->neighbors, qh->hull_dim);
    1516             :   }
    1517           4 :   qh_settempfree(qh, &newfacets);
    1518           4 :   trace1((qh, qh->ferr, 1028, "qh_createsimplex: created simplex\n"));
    1519           4 : } /* createsimplex */
    1520             : 
    1521             : /*-<a                             href="qh-poly_r.htm#TOC"
    1522             :   >-------------------------------</a><a name="delridge">-</a>
    1523             : 
    1524             :   qh_delridge(qh, ridge )
    1525             :     delete a ridge's vertices and frees its memory
    1526             : 
    1527             :   notes:
    1528             :     assumes r.top->ridges and r.bottom->ridges have been updated
    1529             : */
    1530       60813 : void qh_delridge(qhT *qh, ridgeT *ridge) {
    1531             : 
    1532       60813 :   if (ridge == qh->traceridge)
    1533           0 :     qh->traceridge= NULL;
    1534       60813 :   qh_setfree(qh, &(ridge->vertices));
    1535       60813 :   qh_memfree(qh, ridge, (int)sizeof(ridgeT));
    1536       60813 : } /* delridge */
    1537             : 
    1538             : /*-<a                             href="qh-poly_r.htm#TOC"
    1539             :   >-------------------------------</a><a name="delvertex">-</a>
    1540             : 
    1541             :   qh_delvertex(qh, vertex )
    1542             :     deletes a vertex and frees its memory
    1543             : 
    1544             :   notes:
    1545             :     assumes vertex->adjacencies have been updated if needed
    1546             :     unlinks from vertex_list
    1547             : */
    1548           0 : void qh_delvertex(qhT *qh, vertexT *vertex) {
    1549             : 
    1550           0 :   if (vertex->deleted && !vertex->partitioned && !qh->NOerrexit) {
    1551           0 :     qh_fprintf(qh, qh->ferr, 6395, "qhull internal error (qh_delvertex): vertex v%d was deleted but it was not partitioned as a coplanar point\n",
    1552             :       vertex->id);
    1553           0 :     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    1554             :   }
    1555           0 :   if (vertex == qh->tracevertex)
    1556           0 :     qh->tracevertex= NULL;
    1557           0 :   qh_removevertex(qh, vertex);
    1558           0 :   qh_setfree(qh, &vertex->neighbors);
    1559           0 :   qh_memfree(qh, vertex, (int)sizeof(vertexT));
    1560           0 : } /* delvertex */
    1561             : 
    1562             : 
    1563             : /*-<a                             href="qh-poly_r.htm#TOC"
    1564             :   >-------------------------------</a><a name="facet3vertex">-</a>
    1565             : 
    1566             :   qh_facet3vertex(qh )
    1567             :     return temporary set of 3-d vertices in qh_ORIENTclock order
    1568             : 
    1569             :   design:
    1570             :     if simplicial facet
    1571             :       build set from facet->vertices with facet->toporient
    1572             :     else
    1573             :       for each ridge in order
    1574             :         build set from ridge's vertices
    1575             : */
    1576           0 : setT *qh_facet3vertex(qhT *qh, facetT *facet) {
    1577             :   ridgeT *ridge, *firstridge;
    1578             :   vertexT *vertex;
    1579           0 :   int cntvertices, cntprojected=0;
    1580             :   setT *vertices;
    1581             : 
    1582           0 :   cntvertices= qh_setsize(qh, facet->vertices);
    1583           0 :   vertices= qh_settemp(qh, cntvertices);
    1584           0 :   if (facet->simplicial) {
    1585           0 :     if (cntvertices != 3) {
    1586           0 :       qh_fprintf(qh, qh->ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n",
    1587             :                   cntvertices, facet->id);
    1588           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
    1589             :     }
    1590           0 :     qh_setappend(qh, &vertices, SETfirst_(facet->vertices));
    1591           0 :     if (facet->toporient ^ qh_ORIENTclock)
    1592           0 :       qh_setappend(qh, &vertices, SETsecond_(facet->vertices));
    1593             :     else
    1594           0 :       qh_setaddnth(qh, &vertices, 0, SETsecond_(facet->vertices));
    1595           0 :     qh_setappend(qh, &vertices, SETelem_(facet->vertices, 2));
    1596             :   }else {
    1597           0 :     ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
    1598           0 :     while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) {
    1599           0 :       qh_setappend(qh, &vertices, vertex);
    1600           0 :       if (++cntprojected > cntvertices || ridge == firstridge)
    1601             :         break;
    1602             :     }
    1603           0 :     if (!ridge || cntprojected != cntvertices) {
    1604           0 :       qh_fprintf(qh, qh->ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n",
    1605             :                   facet->id, cntprojected);
    1606           0 :       qh_errexit(qh, qh_ERRqhull, facet, ridge);
    1607             :     }
    1608             :   }
    1609           0 :   return vertices;
    1610             : } /* facet3vertex */
    1611             : 
    1612             : /*-<a                             href="qh-poly_r.htm#TOC"
    1613             :   >-------------------------------</a><a name="findbestfacet">-</a>
    1614             : 
    1615             :   qh_findbestfacet(qh, point, bestoutside, bestdist, isoutside )
    1616             :     find facet that is furthest below a point
    1617             : 
    1618             :     for Delaunay triangulations,
    1619             :       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
    1620             :       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
    1621             : 
    1622             :   returns:
    1623             :     if bestoutside is set (e.g., qh_ALL)
    1624             :       returns best facet that is not upperdelaunay
    1625             :       if Delaunay and inside, point is outside circumsphere of bestfacet
    1626             :     else
    1627             :       returns first facet below point
    1628             :       if point is inside, returns nearest, !upperdelaunay facet
    1629             :     distance to facet
    1630             :     isoutside set if outside of facet
    1631             : 
    1632             :   notes:
    1633             :     Distance is measured by distance to the facet's hyperplane.  For
    1634             :     Delaunay facets, this is not the same as the containing facet.  It may
    1635             :     be an adjacent facet or a different tricoplanar facet.  See
    1636             :     <a href="../html/qh-code.htm#findfacet">locate a facet with qh_findbestfacet()</a>
    1637             : 
    1638             :     For tricoplanar facets, this finds one of the tricoplanar facets closest
    1639             :     to the point.
    1640             : 
    1641             :     If inside, qh_findbestfacet performs an exhaustive search
    1642             :        this may be too conservative.  Sometimes it is clearly required.
    1643             : 
    1644             :     qh_findbestfacet is not used by qhull.
    1645             :     uses qh.visit_id and qh.coplanarset
    1646             : 
    1647             :   see:
    1648             :     <a href="geom_r.c#findbest">qh_findbest</a>
    1649             : */
    1650           0 : facetT *qh_findbestfacet(qhT *qh, pointT *point, boolT bestoutside,
    1651             :            realT *bestdist, boolT *isoutside) {
    1652           0 :   facetT *bestfacet= NULL;
    1653           0 :   int numpart, totpart= 0;
    1654             : 
    1655           0 :   bestfacet= qh_findbest(qh, point, qh->facet_list,
    1656             :                             bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
    1657             :                             bestdist, isoutside, &totpart);
    1658           0 :   if (*bestdist < -qh->DISTround) {
    1659           0 :     bestfacet= qh_findfacet_all(qh, point, !qh_NOupper, bestdist, isoutside, &numpart);
    1660           0 :     totpart += numpart;
    1661           0 :     if ((isoutside && *isoutside && bestoutside)
    1662           0 :     || (isoutside && !*isoutside && bestfacet->upperdelaunay)) {
    1663           0 :       bestfacet= qh_findbest(qh, point, bestfacet,
    1664             :                             bestoutside, False, bestoutside,
    1665             :                             bestdist, isoutside, &totpart);
    1666           0 :       totpart += numpart;
    1667             :     }
    1668             :   }
    1669           0 :   trace3((qh, qh->ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
    1670             :           bestfacet->id, *bestdist, (isoutside ? *isoutside : UINT_MAX), totpart));
    1671           0 :   return bestfacet;
    1672             : } /* findbestfacet */
    1673             : 
    1674             : /*-<a                             href="qh-poly_r.htm#TOC"
    1675             :   >-------------------------------</a><a name="findbestlower">-</a>
    1676             : 
    1677             :   qh_findbestlower(qh, facet, point, bestdist, numpart )
    1678             :     returns best non-upper, non-flipped neighbor of facet for point
    1679             :     if needed, searches vertex neighbors
    1680             : 
    1681             :   returns:
    1682             :     returns bestdist and updates numpart
    1683             : 
    1684             :   notes:
    1685             :     called by qh_findbest() for points above an upperdelaunay facet
    1686             :     if Delaunay and inside, point is outside of circumsphere of bestfacet
    1687             : 
    1688             : */
    1689           0 : facetT *qh_findbestlower(qhT *qh, facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) {
    1690           0 :   facetT *neighbor, **neighborp, *bestfacet= NULL;
    1691           0 :   realT bestdist= -REALmax/2 /* avoid underflow */;
    1692             :   realT dist;
    1693             :   vertexT *vertex;
    1694           0 :   boolT isoutside= False;  /* not used */
    1695             : 
    1696           0 :   zinc_(Zbestlower);
    1697           0 :   FOREACHneighbor_(upperfacet) {
    1698           0 :     if (neighbor->upperdelaunay || neighbor->flipped)
    1699           0 :       continue;
    1700           0 :     (*numpart)++;
    1701           0 :     qh_distplane(qh, point, neighbor, &dist);
    1702           0 :     if (dist > bestdist) {
    1703           0 :       bestfacet= neighbor;
    1704           0 :       bestdist= dist;
    1705             :     }
    1706             :   }
    1707           0 :   if (!bestfacet) {
    1708           0 :     zinc_(Zbestlowerv);
    1709             :     /* rarely called, numpart does not count nearvertex computations */
    1710           0 :     vertex= qh_nearvertex(qh, upperfacet, point, &dist);
    1711           0 :     qh_vertexneighbors(qh);
    1712           0 :     FOREACHneighbor_(vertex) {
    1713           0 :       if (neighbor->upperdelaunay || neighbor->flipped)
    1714           0 :         continue;
    1715           0 :       (*numpart)++;
    1716           0 :       qh_distplane(qh, point, neighbor, &dist);
    1717           0 :       if (dist > bestdist) {
    1718           0 :         bestfacet= neighbor;
    1719           0 :         bestdist= dist;
    1720             :       }
    1721             :     }
    1722             :   }
    1723           0 :   if (!bestfacet) {
    1724           0 :     zinc_(Zbestlowerall);  /* invoked once per point in outsideset */
    1725           0 :     zmax_(Zbestloweralln, qh->num_facets);
    1726             :     /* [dec'15] Previously reported as QH6228 */
    1727           0 :     trace3((qh, qh->ferr, 3025, "qh_findbestlower: all neighbors of facet %d are flipped or upper Delaunay.  Search all facets\n",
    1728             :         upperfacet->id));
    1729             :     /* rarely called */
    1730           0 :     bestfacet= qh_findfacet_all(qh, point, qh_NOupper, &bestdist, &isoutside, numpart);
    1731             :   }
    1732           0 :   *bestdistp= bestdist;
    1733           0 :   trace3((qh, qh->ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n",
    1734             :           bestfacet->id, bestdist, upperfacet->id, qh_pointid(qh, point)));
    1735           0 :   return bestfacet;
    1736             : } /* findbestlower */
    1737             : 
    1738             : /*-<a                             href="qh-poly_r.htm#TOC"
    1739             :   >-------------------------------</a><a name="findfacet_all">-</a>
    1740             : 
    1741             :   qh_findfacet_all(qh, point, noupper, bestdist, isoutside, numpart )
    1742             :     exhaustive search for facet below a point
    1743             :     ignore flipped and visible facets, f.normal==NULL, and if noupper, f.upperdelaunay facets
    1744             : 
    1745             :     for Delaunay triangulations,
    1746             :       Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
    1747             :       Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
    1748             : 
    1749             :   returns:
    1750             :     returns first facet below point
    1751             :     if point is inside,
    1752             :       returns nearest facet
    1753             :     distance to facet
    1754             :     isoutside if point is outside of the hull
    1755             :     number of distance tests
    1756             : 
    1757             :   notes:
    1758             :     called by qh_findbestlower if all neighbors are flipped or upper Delaunay (QH3025)
    1759             :     primarily for library users (qh_findbestfacet), rarely used by Qhull
    1760             : */
    1761           0 : facetT *qh_findfacet_all(qhT *qh, pointT *point, boolT noupper, realT *bestdist, boolT *isoutside,
    1762             :                           int *numpart) {
    1763           0 :   facetT *bestfacet= NULL, *facet;
    1764             :   realT dist;
    1765           0 :   int totpart= 0;
    1766             : 
    1767           0 :   *bestdist= -REALmax;
    1768           0 :   *isoutside= False;
    1769           0 :   FORALLfacets {
    1770           0 :     if (facet->flipped || !facet->normal || facet->visible)
    1771           0 :       continue;
    1772           0 :     if (noupper && facet->upperdelaunay)
    1773           0 :       continue;
    1774           0 :     totpart++;
    1775           0 :     qh_distplane(qh, point, facet, &dist);
    1776           0 :     if (dist > *bestdist) {
    1777           0 :       *bestdist= dist;
    1778           0 :       bestfacet= facet;
    1779           0 :       if (dist > qh->MINoutside) {
    1780           0 :         *isoutside= True;
    1781           0 :         break;
    1782             :       }
    1783             :     }
    1784             :   }
    1785           0 :   *numpart= totpart;
    1786           0 :   trace3((qh, qh->ferr, 3016, "qh_findfacet_all: p%d, noupper? %d, f%d, dist %2.2g, isoutside %d, totpart %d\n",
    1787             :       qh_pointid(qh, point), noupper, getid_(bestfacet), *bestdist, *isoutside, totpart));
    1788           0 :   return bestfacet;
    1789             : } /* findfacet_all */
    1790             : 
    1791             : /*-<a                             href="qh-poly_r.htm#TOC"
    1792             :   >-------------------------------</a><a name="findgood">-</a>
    1793             : 
    1794             :   qh_findgood(qh, facetlist, goodhorizon )
    1795             :     identify good facets for qh.PRINTgood and qh_buildcone_onlygood
    1796             :     goodhorizon is count of good, horizon facets from qh_find_horizon, otherwise 0 from qh_findgood_all
    1797             :     if not qh.MERGING and qh.GOODvertex>0
    1798             :       facet includes point as vertex
    1799             :       if !match, returns goodhorizon
    1800             :     if qh.GOODpoint
    1801             :       facet is visible or coplanar (>0) or not visible (<0)
    1802             :     if qh.GOODthreshold
    1803             :       facet->normal matches threshold
    1804             :     if !goodhorizon and !match,
    1805             :       selects facet with closest angle to thresholds
    1806             :       sets GOODclosest
    1807             : 
    1808             :   returns:
    1809             :     number of new, good facets found
    1810             :     determines facet->good
    1811             :     may update qh.GOODclosest
    1812             : 
    1813             :   notes:
    1814             :     called from qh_initbuild, qh_buildcone_onlygood, and qh_findgood_all
    1815             :     qh_findgood_all (called from qh_prepare_output) further reduces the good region
    1816             : 
    1817             :   design:
    1818             :     count good facets
    1819             :     if not merging, clear good facets that fail qh.GOODvertex ('QVn', but not 'QV-n')
    1820             :     clear good facets that fail qh.GOODpoint ('QGn' or 'QG-n')
    1821             :     clear good facets that fail qh.GOODthreshold
    1822             :     if !goodhorizon and !find f.good,
    1823             :       sets GOODclosest to facet with closest angle to thresholds
    1824             : */
    1825           3 : int qh_findgood(qhT *qh, facetT *facetlist, int goodhorizon) {
    1826           3 :   facetT *facet, *bestfacet= NULL;
    1827           3 :   realT angle, bestangle= REALmax, dist;
    1828           3 :   int  numgood=0;
    1829             : 
    1830       29335 :   FORALLfacet_(facetlist) {
    1831       29332 :     if (facet->good)
    1832       29332 :       numgood++;
    1833             :   }
    1834           3 :   if (qh->GOODvertex>0 && !qh->MERGING) {
    1835           0 :     FORALLfacet_(facetlist) {
    1836           0 :       if (facet->good && !qh_isvertex(qh->GOODvertexp, facet->vertices)) {
    1837           0 :         facet->good= False;
    1838           0 :         numgood--;
    1839             :       }
    1840             :     }
    1841             :   }
    1842           3 :   if (qh->GOODpoint && numgood) {
    1843           0 :     FORALLfacet_(facetlist) {
    1844           0 :       if (facet->good && facet->normal) {
    1845           0 :         zinc_(Zdistgood);
    1846           0 :         qh_distplane(qh, qh->GOODpointp, facet, &dist);
    1847           0 :         if ((qh->GOODpoint > 0) ^ (dist > 0.0)) {
    1848           0 :           facet->good= False;
    1849           0 :           numgood--;
    1850             :         }
    1851             :       }
    1852             :     }
    1853             :   }
    1854           3 :   if (qh->GOODthreshold && (numgood || goodhorizon || qh->GOODclosest)) {
    1855           0 :     FORALLfacet_(facetlist) {
    1856           0 :       if (facet->good && facet->normal) {
    1857           0 :         if (!qh_inthresholds(qh, facet->normal, &angle)) {
    1858           0 :           facet->good= False;
    1859           0 :           numgood--;
    1860           0 :           if (angle < bestangle) {
    1861           0 :             bestangle= angle;
    1862           0 :             bestfacet= facet;
    1863             :           }
    1864             :         }
    1865             :       }
    1866             :     }
    1867           0 :     if (numgood == 0 && (goodhorizon == 0 || qh->GOODclosest)) {
    1868           0 :       if (qh->GOODclosest) {
    1869           0 :         if (qh->GOODclosest->visible)
    1870           0 :           qh->GOODclosest= NULL;
    1871             :         else {
    1872           0 :           int ret = qh_inthresholds(qh, qh->GOODclosest->normal, &angle);
    1873             :           QHULL_UNUSED(ret);
    1874           0 :           if (angle < bestangle)
    1875           0 :             bestfacet= qh->GOODclosest;
    1876             :         }
    1877             :       }
    1878           0 :       if (bestfacet && bestfacet != qh->GOODclosest) {   /* numgood == 0 */
    1879           0 :         if (qh->GOODclosest)
    1880           0 :           qh->GOODclosest->good= False;
    1881           0 :         qh->GOODclosest= bestfacet;
    1882           0 :         bestfacet->good= True;
    1883           0 :         numgood++;
    1884           0 :         trace2((qh, qh->ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n",
    1885             :            bestfacet->id, bestangle));
    1886           0 :         return numgood;
    1887             :       }
    1888           0 :     }else if (qh->GOODclosest) { /* numgood > 0 */
    1889           0 :       qh->GOODclosest->good= False;
    1890           0 :       qh->GOODclosest= NULL;
    1891             :     }
    1892             :   }
    1893           3 :   zadd_(Zgoodfacet, numgood);
    1894           3 :   trace2((qh, qh->ferr, 2045, "qh_findgood: found %d good facets with %d good horizon and qh.GOODclosest f%d\n",
    1895             :                numgood, goodhorizon, getid_(qh->GOODclosest)));
    1896           3 :   if (!numgood && qh->GOODvertex>0 && !qh->MERGING)
    1897           0 :     return goodhorizon;
    1898           3 :   return numgood;
    1899             : } /* findgood */
    1900             : 
    1901             : /*-<a                             href="qh-poly_r.htm#TOC"
    1902             :   >-------------------------------</a><a name="findgood_all">-</a>
    1903             : 
    1904             :   qh_findgood_all(qh, facetlist )
    1905             :     apply other constraints for good facets (used by qh.PRINTgood)
    1906             :     if qh.GOODvertex
    1907             :       facet includes (>0) or doesn't include (<0) point as vertex
    1908             :       if last good facet and ONLYgood, prints warning and continues
    1909             :     if qh.SPLITthresholds (e.g., qh.DELAUNAY)
    1910             :       facet->normal matches threshold, or if none, the closest one
    1911             :     calls qh_findgood
    1912             :     nop if good not used
    1913             : 
    1914             :   returns:
    1915             :     clears facet->good if not good
    1916             :     sets qh.num_good
    1917             : 
    1918             :   notes:
    1919             :     called by qh_prepare_output and qh_printneighborhood
    1920             :     unless qh.ONLYgood, calls qh_findgood first
    1921             : 
    1922             :   design:
    1923             :     uses qh_findgood to mark good facets
    1924             :     clear f.good for failed qh.GOODvertex
    1925             :     clear f.good for failed qh.SPLITthreholds
    1926             :        if no more good facets, select best of qh.SPLITthresholds
    1927             : */
    1928           3 : void qh_findgood_all(qhT *qh, facetT *facetlist) {
    1929           3 :   facetT *facet, *bestfacet=NULL;
    1930           3 :   realT angle, bestangle= REALmax;
    1931           3 :   int  numgood=0, startgood;
    1932             : 
    1933           3 :   if (!qh->GOODvertex && !qh->GOODthreshold && !qh->GOODpoint
    1934           3 :   && !qh->SPLITthresholds)
    1935           0 :     return;
    1936           3 :   if (!qh->ONLYgood)
    1937           3 :     qh_findgood(qh, qh->facet_list, 0);
    1938       29335 :   FORALLfacet_(facetlist) {
    1939       29332 :     if (facet->good)
    1940       29332 :       numgood++;
    1941             :   }
    1942           3 :   if (qh->GOODvertex <0 || (qh->GOODvertex > 0 && qh->MERGING)) {
    1943           0 :     FORALLfacet_(facetlist) {
    1944           0 :       if (facet->good && ((qh->GOODvertex > 0) ^ !!qh_isvertex(qh->GOODvertexp, facet->vertices))) { /* convert to bool */
    1945           0 :         if (!--numgood) {
    1946           0 :           if (qh->ONLYgood) {
    1947           0 :             qh_fprintf(qh, qh->ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
    1948             :                qh_pointid(qh, qh->GOODvertexp), facet->id);
    1949           0 :             return;
    1950           0 :           }else if (qh->GOODvertex > 0)
    1951           0 :             qh_fprintf(qh, qh->ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n",
    1952           0 :                 qh->GOODvertex-1, qh->GOODvertex-1);
    1953             :           else
    1954           0 :             qh_fprintf(qh, qh->ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n",
    1955           0 :                 -qh->GOODvertex - 1, -qh->GOODvertex - 1);
    1956             :         }
    1957           0 :         facet->good= False;
    1958             :       }
    1959             :     }
    1960             :   }
    1961           3 :   startgood= numgood;
    1962           3 :   if (qh->SPLITthresholds) {
    1963       29335 :     FORALLfacet_(facetlist) {
    1964       29332 :       if (facet->good) {
    1965       29332 :         if (!qh_inthresholds(qh, facet->normal, &angle)) {
    1966         500 :           facet->good= False;
    1967         500 :           numgood--;
    1968         500 :           if (angle < bestangle) {
    1969          11 :             bestangle= angle;
    1970          11 :             bestfacet= facet;
    1971             :           }
    1972             :         }
    1973             :       }
    1974             :     }
    1975           3 :     if (!numgood && bestfacet) {
    1976           0 :       bestfacet->good= True;
    1977           0 :       numgood++;
    1978           0 :       trace0((qh, qh->ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to split thresholds\n",
    1979             :            bestfacet->id, bestangle));
    1980           0 :       return;
    1981             :     }
    1982             :   }
    1983           3 :   if (numgood == 1 && !qh->PRINTgood && qh->GOODclosest && qh->GOODclosest->good) {
    1984           0 :     trace2((qh, qh->ferr, 2109, "qh_findgood_all: undo selection of qh.GOODclosest f%d since it would fail qh_inthresholds in qh_skipfacet\n",
    1985             :       qh->GOODclosest->id));
    1986           0 :     qh->GOODclosest->good= False;
    1987           0 :     numgood= 0;
    1988             :   }
    1989           3 :   qh->num_good= numgood;
    1990           3 :   trace0((qh, qh->ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n",
    1991             :         numgood, startgood));
    1992             : } /* findgood_all */
    1993             : 
    1994             : /*-<a                             href="qh-poly_r.htm#TOC"
    1995             :   >-------------------------------</a><a name="furthestnext">-</a>
    1996             : 
    1997             :   qh_furthestnext()
    1998             :     set qh.facet_next to facet with furthest of all furthest points
    1999             :     searches all facets on qh.facet_list
    2000             : 
    2001             :   notes:
    2002             :     this may help avoid precision problems
    2003             : */
    2004           3 : void qh_furthestnext(qhT *qh /* qh.facet_list */) {
    2005           3 :   facetT *facet, *bestfacet= NULL;
    2006           3 :   realT dist, bestdist= -REALmax;
    2007             : 
    2008          15 :   FORALLfacets {
    2009          12 :     if (facet->outsideset) {
    2010             : #if qh_COMPUTEfurthest
    2011             :       pointT *furthest;
    2012             :       furthest= (pointT *)qh_setlast(facet->outsideset);
    2013             :       zinc_(Zcomputefurthest);
    2014             :       qh_distplane(qh, furthest, facet, &dist);
    2015             : #else
    2016           6 :       dist= facet->furthestdist;
    2017             : #endif
    2018           6 :       if (dist > bestdist) {
    2019           6 :         bestfacet= facet;
    2020           6 :         bestdist= dist;
    2021             :       }
    2022             :     }
    2023             :   }
    2024           3 :   if (bestfacet) {
    2025           3 :     qh_removefacet(qh, bestfacet);
    2026           3 :     qh_prependfacet(qh, bestfacet, &qh->facet_next);
    2027           3 :     trace1((qh, qh->ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n",
    2028             :             bestfacet->id, bestdist));
    2029             :   }
    2030           3 : } /* furthestnext */
    2031             : 
    2032             : /*-<a                             href="qh-poly_r.htm#TOC"
    2033             :   >-------------------------------</a><a name="furthestout">-</a>
    2034             : 
    2035             :   qh_furthestout(qh, facet )
    2036             :     make furthest outside point the last point of outsideset
    2037             : 
    2038             :   returns:
    2039             :     updates facet->outsideset
    2040             :     clears facet->notfurthest
    2041             :     sets facet->furthestdist
    2042             : 
    2043             :   design:
    2044             :     determine best point of outsideset
    2045             :     make it the last point of outsideset
    2046             : */
    2047           0 : void qh_furthestout(qhT *qh, facetT *facet) {
    2048           0 :   pointT *point, **pointp, *bestpoint= NULL;
    2049           0 :   realT dist, bestdist= -REALmax;
    2050             : 
    2051           0 :   FOREACHpoint_(facet->outsideset) {
    2052           0 :     qh_distplane(qh, point, facet, &dist);
    2053           0 :     zinc_(Zcomputefurthest);
    2054           0 :     if (dist > bestdist) {
    2055           0 :       bestpoint= point;
    2056           0 :       bestdist= dist;
    2057             :     }
    2058             :   }
    2059           0 :   if (bestpoint) {
    2060           0 :     qh_setdel(facet->outsideset, point);
    2061           0 :     qh_setappend(qh, &facet->outsideset, point);
    2062             : #if !qh_COMPUTEfurthest
    2063           0 :     facet->furthestdist= bestdist;
    2064             : #endif
    2065             :   }
    2066           0 :   facet->notfurthest= False;
    2067           0 :   trace3((qh, qh->ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n",
    2068             :           qh_pointid(qh, point), facet->id));
    2069           0 : } /* furthestout */
    2070             : 
    2071             : 
    2072             : /*-<a                             href="qh-qhull_r.htm#TOC"
    2073             :   >-------------------------------</a><a name="infiniteloop">-</a>
    2074             : 
    2075             :   qh_infiniteloop(qh, facet )
    2076             :     report infinite loop error due to facet
    2077             : */
    2078           0 : void qh_infiniteloop(qhT *qh, facetT *facet) {
    2079             : 
    2080           0 :   qh_fprintf(qh, qh->ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected.  If visible, f.replace. If newfacet, f.samecycle\n");
    2081           0 :   qh_errexit(qh, qh_ERRqhull, facet, NULL);
    2082           0 : } /* qh_infiniteloop */
    2083             : 
    2084             : /*-<a                             href="qh-poly_r.htm#TOC"
    2085             :   >-------------------------------</a><a name="initbuild">-</a>
    2086             : 
    2087             :   qh_initbuild()
    2088             :     initialize hull and outside sets with point array
    2089             :     qh.FIRSTpoint/qh.NUMpoints is point array
    2090             :     if qh.GOODpoint
    2091             :       adds qh.GOODpoint to initial hull
    2092             : 
    2093             :   returns:
    2094             :     qh_facetlist with initial hull
    2095             :     points partioned into outside sets, coplanar sets, or inside
    2096             :     initializes qh.GOODpointp, qh.GOODvertexp,
    2097             : 
    2098             :   design:
    2099             :     initialize global variables used during qh_buildhull
    2100             :     determine precision constants and points with max/min coordinate values
    2101             :       if qh.SCALElast, scale last coordinate(for 'd')
    2102             :     initialize qh.newfacet_list, qh.facet_tail
    2103             :     initialize qh.vertex_list, qh.newvertex_list, qh.vertex_tail
    2104             :     determine initial vertices
    2105             :     build initial simplex
    2106             :     partition input points into facets of initial simplex
    2107             :     set up lists
    2108             :     if qh.ONLYgood
    2109             :       check consistency
    2110             :       add qh.GOODvertex if defined
    2111             : */
    2112           4 : void qh_initbuild(qhT *qh) {
    2113             :   setT *maxpoints, *vertices;
    2114             :   facetT *facet;
    2115             :   int i, numpart;
    2116             :   realT dist;
    2117             :   boolT isoutside;
    2118             : 
    2119           4 :   if (qh->PRINTstatistics) {
    2120           0 :     qh_fprintf(qh, qh->ferr, 9350, "qhull %s Statistics: %s | %s\n",
    2121           0 :       qh_version, qh->rbox_command, qh->qhull_command);
    2122           0 :     fflush(NULL);
    2123             :   }
    2124           4 :   qh->furthest_id= qh_IDunknown;
    2125           4 :   qh->lastreport= 0;
    2126           4 :   qh->lastfacets= 0;
    2127           4 :   qh->lastmerges= 0;
    2128           4 :   qh->lastplanes= 0;
    2129           4 :   qh->lastdist= 0;
    2130           4 :   qh->facet_id= qh->vertex_id= qh->ridge_id= 0;
    2131           4 :   qh->visit_id= qh->vertex_visit= 0;
    2132           4 :   qh->maxoutdone= False;
    2133             : 
    2134           4 :   if (qh->GOODpoint > 0)
    2135           0 :     qh->GOODpointp= qh_point(qh, qh->GOODpoint-1);
    2136           4 :   else if (qh->GOODpoint < 0)
    2137           0 :     qh->GOODpointp= qh_point(qh, -qh->GOODpoint-1);
    2138           4 :   if (qh->GOODvertex > 0)
    2139           0 :     qh->GOODvertexp= qh_point(qh, qh->GOODvertex-1);
    2140           4 :   else if (qh->GOODvertex < 0)
    2141           0 :     qh->GOODvertexp= qh_point(qh, -qh->GOODvertex-1);
    2142           4 :   if ((qh->GOODpoint
    2143           0 :        && (qh->GOODpointp < qh->first_point  /* also catches !GOODpointp */
    2144           0 :            || qh->GOODpointp > qh_point(qh, qh->num_points-1)))
    2145           4 :   || (qh->GOODvertex
    2146           0 :        && (qh->GOODvertexp < qh->first_point  /* also catches !GOODvertexp */
    2147           0 :            || qh->GOODvertexp > qh_point(qh, qh->num_points-1)))) {
    2148           0 :     qh_fprintf(qh, qh->ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n",
    2149           0 :              qh->num_points-1);
    2150           0 :     qh_errexit(qh, qh_ERRinput, NULL, NULL);
    2151             :   }
    2152           4 :   maxpoints= qh_maxmin(qh, qh->first_point, qh->num_points, qh->hull_dim);
    2153           4 :   if (qh->SCALElast)
    2154           4 :     qh_scalelast(qh, qh->first_point, qh->num_points, qh->hull_dim, qh->MINlastcoord, qh->MAXlastcoord, qh->MAXabs_coord);
    2155           4 :   qh_detroundoff(qh);
    2156           4 :   if (qh->DELAUNAY && qh->upper_threshold[qh->hull_dim-1] > REALmax/2
    2157           4 :                   && qh->lower_threshold[qh->hull_dim-1] < -REALmax/2) {
    2158         120 :     for (i=qh_PRINTEND; i--; ) {
    2159         116 :       if (qh->PRINTout[i] == qh_PRINTgeom && qh->DROPdim < 0
    2160           0 :           && !qh->GOODthreshold && !qh->SPLITthresholds)
    2161           0 :         break;  /* in this case, don't set upper_threshold */
    2162             :     }
    2163           4 :     if (i < 0) {
    2164           4 :       if (qh->UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
    2165           0 :         qh->lower_threshold[qh->hull_dim-1]= qh->ANGLEround * qh_ZEROdelaunay;
    2166           0 :         qh->GOODthreshold= True;
    2167             :       }else {
    2168           4 :         qh->upper_threshold[qh->hull_dim-1]= -qh->ANGLEround * qh_ZEROdelaunay;
    2169           4 :         if (!qh->GOODthreshold)
    2170           4 :           qh->SPLITthresholds= True; /* build upper-convex hull even if Qg */
    2171             :           /* qh_initqhull_globals errors if Qg without Pdk/etc. */
    2172             :       }
    2173             :     }
    2174             :   }
    2175           4 :   trace4((qh, qh->ferr, 4091, "qh_initbuild: create sentinels for qh.facet_tail and qh.vertex_tail\n"));
    2176           4 :   qh->facet_list= qh->newfacet_list= qh->facet_tail= qh_newfacet(qh);
    2177           4 :   qh->num_facets= qh->num_vertices= qh->num_visible= 0;
    2178           4 :   qh->vertex_list= qh->newvertex_list= qh->vertex_tail= qh_newvertex(qh, NULL);
    2179           4 :   vertices= qh_initialvertices(qh, qh->hull_dim, maxpoints, qh->first_point, qh->num_points);
    2180           4 :   qh_initialhull(qh, vertices);  /* initial qh->facet_list */
    2181           3 :   qh_partitionall(qh, vertices, qh->first_point, qh->num_points);
    2182           3 :   if (qh->PRINToptions1st || qh->TRACElevel || qh->IStracing) {
    2183           0 :     if (qh->TRACElevel || qh->IStracing)
    2184           0 :       qh_fprintf(qh, qh->ferr, 8103, "\nTrace level T%d, IStracing %d, point TP%d, merge TM%d, dist TW%2.2g, qh.tracefacet_id %d, traceridge_id %d, tracevertex_id %d, last qh.RERUN %d, %s | %s\n",
    2185           0 :          qh->TRACElevel, qh->IStracing, qh->TRACEpoint, qh->TRACEmerge, qh->TRACEdist, qh->tracefacet_id, qh->traceridge_id, qh->tracevertex_id, qh->TRACElastrun, qh->rbox_command, qh->qhull_command);
    2186           0 :     qh_fprintf(qh, qh->ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh->qhull_options);
    2187             :   }
    2188           3 :   qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
    2189           3 :   qh->facet_next= qh->facet_list;
    2190           3 :   qh_furthestnext(qh /* qh.facet_list */);
    2191           3 :   if (qh->PREmerge) {
    2192           3 :     qh->cos_max= qh->premerge_cos;
    2193           3 :     qh->centrum_radius= qh->premerge_centrum; /* overwritten by qh_premerge */
    2194             :   }
    2195           3 :   if (qh->ONLYgood) {
    2196           0 :     if (qh->GOODvertex > 0 && qh->MERGING) {
    2197           0 :       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");
    2198           0 :       qh_errexit(qh, qh_ERRinput, NULL, NULL);
    2199             :     }
    2200           0 :     if (!(qh->GOODthreshold || qh->GOODpoint
    2201           0 :          || (!qh->MERGEexact && !qh->PREmerge && qh->GOODvertexp))) {
    2202           0 :       qh_fprintf(qh, qh->ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
    2203           0 :       qh_errexit(qh, qh_ERRinput, NULL, NULL);
    2204             :     }
    2205           0 :     if (qh->GOODvertex > 0  && !qh->MERGING  /* matches qh_partitionall */
    2206           0 :     && !qh_isvertex(qh->GOODvertexp, vertices)) {
    2207           0 :       facet= qh_findbestnew(qh, qh->GOODvertexp, qh->facet_list,
    2208             :                           &dist, !qh_ALL, &isoutside, &numpart);
    2209           0 :       zadd_(Zdistgood, numpart);
    2210           0 :       if (!isoutside) {
    2211           0 :         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",
    2212             :                qh_pointid(qh, qh->GOODvertexp));
    2213           0 :         qh_errexit(qh, qh_ERRinput, NULL, NULL);
    2214             :       }
    2215           0 :       if (!qh_addpoint(qh, qh->GOODvertexp, facet, False)) {
    2216           0 :         qh_settempfree(qh, &vertices);
    2217           0 :         qh_settempfree(qh, &maxpoints);
    2218           0 :         return;
    2219             :       }
    2220             :     }
    2221           0 :     qh_findgood(qh, qh->facet_list, 0);
    2222             :   }
    2223           3 :   qh_settempfree(qh, &vertices);
    2224           3 :   qh_settempfree(qh, &maxpoints);
    2225           3 :   trace1((qh, qh->ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n"));
    2226             : } /* initbuild */
    2227             : 
    2228             : /*-<a                             href="qh-poly_r.htm#TOC"
    2229             :   >-------------------------------</a><a name="initialhull">-</a>
    2230             : 
    2231             :   qh_initialhull(qh, vertices )
    2232             :     constructs the initial hull as a DIM3 simplex of vertices
    2233             : 
    2234             :   notes:
    2235             :     only called by qh_initbuild
    2236             : 
    2237             :   design:
    2238             :     creates a simplex (initializes lists)
    2239             :     determines orientation of simplex
    2240             :     sets hyperplanes for facets
    2241             :     doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
    2242             :     checks for flipped facets and qh.NARROWhull
    2243             :     checks the result
    2244             : */
    2245           4 : void qh_initialhull(qhT *qh, setT *vertices) {
    2246             :   facetT *facet, *firstfacet, *neighbor, **neighborp;
    2247           4 :   realT angle, minangle= REALmax, dist;
    2248             : 
    2249           4 :   qh_createsimplex(qh, vertices /* qh.facet_list */);
    2250           4 :   qh_resetlists(qh, False, qh_RESETvisible);
    2251           4 :   qh->facet_next= qh->facet_list;      /* advance facet when processed */
    2252           4 :   qh->interior_point= qh_getcenter(qh, vertices);
    2253           4 :   if (qh->IStracing) {
    2254           0 :     qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: ");
    2255           0 :     qh_printpoint(qh, qh->ferr, "qh.interior_point", qh->interior_point);
    2256             :   }
    2257           4 :   firstfacet= qh->facet_list;
    2258           4 :   qh_setfacetplane(qh, firstfacet);   /* qh_joggle_restart if flipped */
    2259           4 :   if (firstfacet->flipped) {
    2260           1 :     trace1((qh, qh->ferr, 1065, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", firstfacet->id));
    2261           1 :     firstfacet->flipped= False;
    2262             :   }
    2263           4 :   zzinc_(Zdistcheck);
    2264           4 :   qh_distplane(qh, qh->interior_point, firstfacet, &dist);
    2265           4 :   if (dist > qh->DISTround) {  /* clearly flipped */
    2266           0 :     trace1((qh, qh->ferr, 1060, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Reversing orientation of all facets\n",
    2267             :           dist, firstfacet->id));
    2268           0 :     FORALLfacets
    2269           0 :       facet->toporient ^= (unsigned char)True;
    2270           0 :     qh_setfacetplane(qh, firstfacet);
    2271             :   }
    2272          20 :   FORALLfacets {
    2273          16 :     if (facet != firstfacet)
    2274          12 :       qh_setfacetplane(qh, facet);    /* qh_joggle_restart if flipped */
    2275             :   }
    2276          20 :   FORALLfacets {
    2277          16 :     if (facet->flipped) {
    2278           3 :       trace1((qh, qh->ferr, 1066, "qh_initialhull: ignore f%d flipped.  Test qh.interior_point (p-2) for clearly flipped\n", facet->id));
    2279           3 :       facet->flipped= False;
    2280             :     }
    2281          16 :     zzinc_(Zdistcheck);
    2282          16 :     qh_distplane(qh, qh->interior_point, facet, &dist);  /* duplicates qh_setfacetplane */
    2283          16 :     if (dist > qh->DISTround) {  /* clearly flipped, due to axis-parallel facet or coplanar firstfacet */
    2284           0 :       trace1((qh, qh->ferr, 1031, "qh_initialhull: initial orientation incorrect, qh.interior_point is %2.2g from f%d.  Either axis-parallel facet or coplanar firstfacet f%d.  Force outside orientation of all facets\n"));
    2285           0 :       FORALLfacets { /* reuse facet, then 'break' */
    2286           0 :         facet->flipped= False;
    2287           0 :         facet->toporient ^= (unsigned char)True;
    2288           0 :         qh_orientoutside(qh, facet);  /* force outside orientation for f.normal */
    2289             :       }
    2290           0 :       break;
    2291             :     }
    2292             :   }
    2293          16 :   FORALLfacets {
    2294          13 :     if (!qh_checkflipped(qh, facet, NULL, qh_ALL)) {
    2295           1 :       if (qh->DELAUNAY && ! qh->ATinfinity) {
    2296           0 :         qh_joggle_restart(qh, "initial Delaunay cocircular or cospherical");
    2297           0 :         if (qh->UPPERdelaunay)
    2298           0 :           qh_fprintf(qh, qh->ferr, 6240, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Option 'Qs' searches all points.  Use option 'QJ' to joggle the input, otherwise cannot compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n");
    2299             :         else
    2300           0 :           qh_fprintf(qh, qh->ferr, 6239, "Qhull precision error: initial Delaunay input sites are cocircular or cospherical.  Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points; it adds a point \"at infinity\".  Alternatively use option 'QJ' to joggle the input.  Use option 'Qs' to search all points for the initial simplex.\n");
    2301           0 :         qh_printvertexlist(qh, qh->ferr, "\ninput sites with last coordinate projected to a paraboloid\n", qh->facet_list, NULL, qh_ALL);
    2302           0 :         qh_errexit(qh, qh_ERRinput, NULL, NULL);
    2303             :       }else {
    2304           1 :         qh_joggle_restart(qh, "initial simplex is flat");
    2305           1 :         qh_fprintf(qh, qh->ferr, 6154, "Qhull precision error: Initial simplex is flat (facet %d is coplanar with the interior point)\n",
    2306             :                    facet->id);
    2307           1 :         qh_errexit(qh, qh_ERRsingular, NULL, NULL);  /* calls qh_printhelp_singular */
    2308             :       }
    2309             :     }
    2310          48 :     FOREACHneighbor_(facet) {
    2311          36 :       angle= qh_getangle(qh, facet->normal, neighbor->normal);
    2312          36 :       minimize_( minangle, angle);
    2313             :     }
    2314             :   }
    2315           3 :   if (minangle < qh_MAXnarrow && !qh->NOnarrow) {
    2316           0 :     realT diff= 1.0 + minangle;
    2317             : 
    2318           0 :     qh->NARROWhull= True;
    2319           0 :     qh_option(qh, "_narrow-hull", NULL, &diff);
    2320           0 :     if (minangle < qh_WARNnarrow && !qh->RERUN && qh->PRINTprecision)
    2321           0 :       qh_printhelp_narrowhull(qh, qh->ferr, minangle);
    2322             :   }
    2323           3 :   zzval_(Zprocessed)= qh->hull_dim+1;
    2324           3 :   qh_checkpolygon(qh, qh->facet_list);
    2325           3 :   qh_checkconvex(qh, qh->facet_list, qh_DATAfault);
    2326           3 :   if (qh->IStracing >= 1) {
    2327           0 :     qh_fprintf(qh, qh->ferr, 8105, "qh_initialhull: simplex constructed\n");
    2328             :   }
    2329           3 : } /* initialhull */
    2330             : 
    2331             : /*-<a                             href="qh-poly_r.htm#TOC"
    2332             :   >-------------------------------</a><a name="initialvertices">-</a>
    2333             : 
    2334             :   qh_initialvertices(qh, dim, maxpoints, points, numpoints )
    2335             :     determines a non-singular set of initial vertices
    2336             :     maxpoints may include duplicate points
    2337             : 
    2338             :   returns:
    2339             :     temporary set of dim+1 vertices in descending order by vertex id
    2340             :     if qh.RANDOMoutside && !qh.ALLpoints
    2341             :       picks random points
    2342             :     if dim >= qh_INITIALmax,
    2343             :       uses min/max x and max points with non-zero determinants
    2344             : 
    2345             :   notes:
    2346             :     unless qh.ALLpoints,
    2347             :       uses maxpoints as long as determinate is non-zero
    2348             : */
    2349           4 : setT *qh_initialvertices(qhT *qh, int dim, setT *maxpoints, pointT *points, int numpoints) {
    2350             :   pointT *point, **pointp;
    2351             :   setT *vertices, *simplex, *tested;
    2352             :   realT randr;
    2353             :   int idx, point_i, point_n, k;
    2354           4 :   boolT nearzero= False;
    2355             : 
    2356           4 :   vertices= qh_settemp(qh, dim + 1);
    2357           4 :   simplex= qh_settemp(qh, dim + 1);
    2358           4 :   if (qh->ALLpoints)
    2359           0 :     qh_maxsimplex(qh, dim, NULL, points, numpoints, &simplex);
    2360           4 :   else if (qh->RANDOMoutside) {
    2361           0 :     while (qh_setsize(qh, simplex) != dim+1) {
    2362           0 :       randr= qh_RANDOMint;
    2363           0 :       randr= randr/(qh_RANDOMmax+1);
    2364           0 :       randr= floor(qh->num_points * randr);
    2365           0 :       idx= (int)randr;
    2366           0 :       while (qh_setin(simplex, qh_point(qh, idx))) {
    2367           0 :         idx++; /* in case qh_RANDOMint always returns the same value */
    2368           0 :         idx= idx < qh->num_points ? idx : 0;
    2369             :       }
    2370           0 :       qh_setappend(qh, &simplex, qh_point(qh, idx));
    2371             :     }
    2372           4 :   }else if (qh->hull_dim >= qh_INITIALmax) {
    2373           0 :     tested= qh_settemp(qh, dim+1);
    2374           0 :     qh_setappend(qh, &simplex, SETfirst_(maxpoints));   /* max and min X coord */
    2375           0 :     qh_setappend(qh, &simplex, SETsecond_(maxpoints));
    2376           0 :     qh_maxsimplex(qh, fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
    2377           0 :     k= qh_setsize(qh, simplex);
    2378           0 :     FOREACHpoint_i_(qh, maxpoints) {
    2379           0 :       if (k >= dim)  /* qh_maxsimplex for last point */
    2380           0 :         break;
    2381           0 :       if (point_i & 0x1) {     /* first try up to dim, max. coord. points */
    2382           0 :         if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
    2383           0 :           qh_detsimplex(qh, point, simplex, k, &nearzero);
    2384           0 :           if (nearzero)
    2385           0 :             qh_setappend(qh, &tested, point);
    2386             :           else {
    2387           0 :             qh_setappend(qh, &simplex, point);
    2388           0 :             k++;
    2389             :           }
    2390             :         }
    2391             :       }
    2392             :     }
    2393           0 :     FOREACHpoint_i_(qh, maxpoints) {
    2394           0 :       if (k >= dim)  /* qh_maxsimplex for last point */
    2395           0 :         break;
    2396           0 :       if ((point_i & 0x1) == 0) {  /* then test min. coord points */
    2397           0 :         if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
    2398           0 :           qh_detsimplex(qh, point, simplex, k, &nearzero);
    2399           0 :           if (nearzero)
    2400           0 :             qh_setappend(qh, &tested, point);
    2401             :           else {
    2402           0 :             qh_setappend(qh, &simplex, point);
    2403           0 :             k++;
    2404             :           }
    2405             :         }
    2406             :       }
    2407             :     }
    2408             :     /* remove tested points from maxpoints */
    2409           0 :     FOREACHpoint_i_(qh, maxpoints) {
    2410           0 :       if (qh_setin(simplex, point) || qh_setin(tested, point))
    2411           0 :         SETelem_(maxpoints, point_i)= NULL;
    2412             :     }
    2413           0 :     qh_setcompact(qh, maxpoints);
    2414           0 :     idx= 0;
    2415           0 :     while (k < dim && (point= qh_point(qh, idx++))) {
    2416           0 :       if (!qh_setin(simplex, point) && !qh_setin(tested, point)){
    2417           0 :         qh_detsimplex(qh, point, simplex, k, &nearzero);
    2418           0 :         if (!nearzero){
    2419           0 :           qh_setappend(qh, &simplex, point);
    2420           0 :           k++;
    2421             :         }
    2422             :       }
    2423             :     }
    2424           0 :     qh_settempfree(qh, &tested);
    2425           0 :     qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
    2426             :   }else /* qh.hull_dim < qh_INITIALmax */
    2427           4 :     qh_maxsimplex(qh, dim, maxpoints, points, numpoints, &simplex);
    2428          20 :   FOREACHpoint_(simplex)
    2429          16 :     qh_setaddnth(qh, &vertices, 0, qh_newvertex(qh, point)); /* descending order */
    2430           4 :   qh_settempfree(qh, &simplex);
    2431           4 :   return vertices;
    2432             : } /* initialvertices */
    2433             : 
    2434             : 
    2435             : /*-<a                             href="qh-poly_r.htm#TOC"
    2436             :   >-------------------------------</a><a name="isvertex">-</a>
    2437             : 
    2438             :   qh_isvertex( point, vertices )
    2439             :     returns vertex if point is in vertex set, else returns NULL
    2440             : 
    2441             :   notes:
    2442             :     for qh.GOODvertex
    2443             : */
    2444           0 : vertexT *qh_isvertex(pointT *point, setT *vertices) {
    2445             :   vertexT *vertex, **vertexp;
    2446             : 
    2447           0 :   FOREACHvertex_(vertices) {
    2448           0 :     if (vertex->point == point)
    2449           0 :       return vertex;
    2450             :   }
    2451           0 :   return NULL;
    2452             : } /* isvertex */
    2453             : 
    2454             : /*-<a                             href="qh-poly_r.htm#TOC"
    2455             :   >-------------------------------</a><a name="makenewfacets">-</a>
    2456             : 
    2457             :   qh_makenewfacets(qh, point )
    2458             :     make new facets from point and qh.visible_list
    2459             : 
    2460             :   returns:
    2461             :     apex (point) of the new facets
    2462             :     qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
    2463             :     qh.newvertex_list= list of vertices in new facets with ->newfacet set
    2464             : 
    2465             :     if (qh.NEWtentative)
    2466             :       newfacets reference horizon facets, but not vice versa
    2467             :       ridges reference non-simplicial horizon ridges, but not vice versa
    2468             :       does not change existing facets
    2469             :     else
    2470             :       sets qh.NEWfacets
    2471             :       new facets attached to horizon facets and ridges
    2472             :       for visible facets,
    2473             :         visible->r.replace is corresponding new facet
    2474             : 
    2475             :   see also:
    2476             :     qh_makenewplanes() -- make hyperplanes for facets
    2477             :     qh_attachnewfacets() -- attachnewfacets if not done here qh->NEWtentative
    2478             :     qh_matchnewfacets() -- match up neighbors
    2479             :     qh_update_vertexneighbors() -- update vertex neighbors and delvertices
    2480             :     qh_deletevisible() -- delete visible facets
    2481             :     qh_checkpolygon() --check the result
    2482             :     qh_triangulate() -- triangulate a non-simplicial facet
    2483             : 
    2484             :   design:
    2485             :     for each visible facet
    2486             :       make new facets to its horizon facets
    2487             :       update its f.replace
    2488             :       clear its neighbor set
    2489             : */
    2490       14660 : vertexT *qh_makenewfacets(qhT *qh, pointT *point /* qh.visible_list */) {
    2491       14660 :   facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
    2492             :   vertexT *apex;
    2493       14660 :   int numnew=0;
    2494             : 
    2495       14660 :   if (qh->CHECKfrequently) {
    2496           0 :     qh_checkdelridge(qh);
    2497             :   }
    2498       14660 :   qh->newfacet_list= qh->facet_tail;
    2499       14660 :   qh->newvertex_list= qh->vertex_tail;
    2500       14660 :   apex= qh_newvertex(qh, point);
    2501       14660 :   qh_appendvertex(qh, apex);
    2502       14660 :   qh->visit_id++;
    2503       53569 :   FORALLvisible_facets {
    2504      160811 :     FOREACHneighbor_(visible)
    2505      121902 :       neighbor->seen= False;
    2506       38909 :     if (visible->ridges) {
    2507       17670 :       visible->visitid= qh->visit_id;
    2508       17670 :       newfacet2= qh_makenew_nonsimplicial(qh, visible, apex, &numnew);
    2509             :     }
    2510       38909 :     if (visible->simplicial)
    2511       34070 :       newfacet= qh_makenew_simplicial(qh, visible, apex, &numnew);
    2512       38909 :     if (!qh->NEWtentative) {
    2513       38909 :       if (newfacet2)  /* newfacet is null if all ridges defined */
    2514       17495 :         newfacet= newfacet2;
    2515       38909 :       if (newfacet)
    2516       38095 :         visible->f.replace= newfacet;
    2517             :       else
    2518         814 :         zinc_(Zinsidevisible);
    2519       38909 :       if (visible->ridges)      /* ridges and neighbors are no longer valid for visible facet */
    2520       17670 :         SETfirst_(visible->ridges)= NULL;
    2521       38909 :       SETfirst_(visible->neighbors)= NULL;
    2522             :     }
    2523             :   }
    2524       14660 :   if (!qh->NEWtentative)
    2525       14660 :     qh->NEWfacets= True;
    2526       14660 :   trace1((qh, qh->ferr, 1032, "qh_makenewfacets: created %d new facets f%d..f%d from point p%d to horizon\n",
    2527             :     numnew, qh->first_newfacet, qh->facet_id-1, qh_pointid(qh, point)));
    2528       14660 :   if (qh->IStracing >= 4)
    2529           0 :     qh_printfacetlist(qh, qh->newfacet_list, NULL, qh_ALL);
    2530       14660 :   return apex;
    2531             : } /* makenewfacets */
    2532             : 
    2533             : #ifndef qh_NOmerge
    2534             : /*-<a                             href="qh-poly_r.htm#TOC"
    2535             :   >-------------------------------</a><a name="matchdupridge">-</a>
    2536             : 
    2537             :   qh_matchdupridge(qh, atfacet, atskip, hashsize, hashcount )
    2538             :     match duplicate ridges in qh.hash_table for atfacet@atskip
    2539             :     duplicates marked with ->dupridge and qh_DUPLICATEridge
    2540             : 
    2541             :   returns:
    2542             :     vertex-facet distance (>0.0) for qh_MERGEridge ridge
    2543             :     updates hashcount
    2544             :     set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)
    2545             : 
    2546             :   see also:
    2547             :     qh_matchneighbor
    2548             : 
    2549             :   notes:
    2550             :     only called by qh_matchnewfacets for qh_buildcone and qh_triangulate_facet
    2551             :     assumes atfacet is simplicial
    2552             :     assumes atfacet->neighbors @ atskip == qh_DUPLICATEridge
    2553             :     usually keeps ridge with the widest merge
    2554             :     both MRGdupridge and MRGflipped are required merges -- rbox 100 C1,2e-13 D4 t1 | qhull d Qbb
    2555             :       can merge flipped f11842 skip 3 into f11862 skip 2 and vice versa (forced by goodmatch/goodmatch2)
    2556             :          blocks -- cannot merge f11862 skip 2 and f11863 skip2 (the widest merge)
    2557             :          must block -- can merge f11843 skip 3 into f11842 flipped skip 3, but not vice versa
    2558             :       can merge f11843 skip 3 into f11863 skip 2, but not vice versa
    2559             :     working/unused.h: [jan'19] Dropped qh_matchdupridge_coplanarhorizon, it was the same or slightly worse.  Complex addition, rarely occurs
    2560             : 
    2561             :   design:
    2562             :     compute hash value for atfacet and atskip
    2563             :     repeat twice -- once to make best matches, once to match the rest
    2564             :       for each possible facet in qh.hash_table
    2565             :         if it is a matching facet with the same orientation and pass 2
    2566             :           make match
    2567             :           unless tricoplanar, mark match for merging (qh_MERGEridge)
    2568             :           [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
    2569             :         if it is a matching facet with the same orientation and pass 1
    2570             :           test if this is a better match
    2571             :       if pass 1,
    2572             :         make best match (it will not be merged)
    2573             :         set newfacet, facet, matchfacet's hyperplane (removes from mergecycle of coplanarhorizon facets)
    2574             : 
    2575             : */
    2576           0 : coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
    2577           0 :   boolT same, ismatch, isduplicate= False;
    2578             :   int hash, scan;
    2579             :   facetT *facet, *newfacet, *nextfacet;
    2580           0 :   facetT *maxmatch= NULL, *maxmatch2= NULL, *goodmatch= NULL, *goodmatch2= NULL;
    2581           0 :   int skip, newskip, nextskip= 0, makematch;
    2582           0 :   int maxskip= 0, maxskip2= 0, goodskip= 0, goodskip2= 0;
    2583           0 :   coordT maxdist= -REALmax, maxdist2= 0.0, dupdist, dupdist2, low, high, maxgood, gooddist= 0.0;
    2584             : 
    2585           0 :   maxgood= qh_WIDEdupridge * (qh->ONEmerge + qh->DISTround);
    2586           0 :   hash= qh_gethash(qh, hashsize, atfacet->vertices, qh->hull_dim, 1,
    2587           0 :                      SETelem_(atfacet->vertices, atskip));
    2588           0 :   trace2((qh, qh->ferr, 2046, "qh_matchdupridge: find dupridge matches for f%d skip %d hash %d hashcount %d\n",
    2589             :           atfacet->id, atskip, hash, *hashcount));
    2590           0 :   for (makematch=0; makematch < 2; makematch++) { /* makematch is false on the first pass and 1 on the second */
    2591           0 :     qh->visit_id++;
    2592           0 :     for (newfacet=atfacet, newskip=atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
    2593           0 :       zinc_(Zhashlookup);
    2594           0 :       nextfacet= NULL; /* exit when ismatch found */
    2595           0 :       newfacet->visitid= qh->visit_id;
    2596           0 :       for (scan=hash; (facet= SETelemt_(qh->hash_table, scan, facetT));
    2597           0 :            scan= (++scan >= hashsize ? 0 : scan)) {
    2598           0 :         if (!facet->dupridge || facet->visitid == qh->visit_id)
    2599           0 :           continue;
    2600           0 :         zinc_(Zhashtests);
    2601           0 :         if (qh_matchvertices(qh, 1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
    2602           0 :           if (SETelem_(newfacet->vertices, newskip) == SETelem_(facet->vertices, skip)) {
    2603           0 :             trace3((qh, qh->ferr, 3053, "qh_matchdupridge: duplicate ridge due to duplicate facets (f%d skip %d and f%d skip %d) previously reported as QH7084.  Maximize dupdist to force vertex merge\n",
    2604             :               newfacet->id, newskip, facet->id, skip));
    2605           0 :             isduplicate= True;
    2606             :           }
    2607           0 :           ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient));
    2608           0 :           if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
    2609           0 :             if (!makematch) {  /* occurs if many merges, e.g., rbox 100 W0 C2,1e-13 D6 t1546872462 | qhull C0 Qt Tcv */
    2610           0 :               qh_fprintf(qh, qh->ferr, 6155, "qhull topology error (qh_matchdupridge): missing qh_DUPLICATEridge at f%d skip %d for new f%d skip %d hash %d ismatch %d.  Set by qh_matchneighbor\n",
    2611             :                 facet->id, skip, newfacet->id, newskip, hash, ismatch);
    2612           0 :               qh_errexit2(qh, qh_ERRtopology, facet, newfacet);
    2613             :             }
    2614           0 :           }else if (!ismatch) {
    2615           0 :             nextfacet= facet;
    2616           0 :             nextskip= skip;
    2617           0 :           }else if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
    2618           0 :             if (makematch) {
    2619           0 :               if (newfacet->tricoplanar) {
    2620           0 :                 SETelem_(facet->neighbors, skip)= newfacet;
    2621           0 :                 SETelem_(newfacet->neighbors, newskip)= facet;
    2622           0 :                 *hashcount -= 2; /* removed two unmatched facets */
    2623           0 :                 trace2((qh, qh->ferr, 2075, "qh_matchdupridge: allow tricoplanar dupridge for new f%d skip %d and f%d skip %d\n",
    2624             :                     newfacet->id, newskip, facet->id, skip));
    2625           0 :               }else if (goodmatch && goodmatch2) {
    2626           0 :                 SETelem_(goodmatch2->neighbors, goodskip2)= qh_MERGEridge;  /* undo selection of goodmatch */
    2627           0 :                 SETelem_(facet->neighbors, skip)= newfacet;
    2628           0 :                 SETelem_(newfacet->neighbors, newskip)= facet;
    2629           0 :                 *hashcount -= 2; /* removed two unmatched facets */
    2630           0 :                 trace2((qh, qh->ferr, 2105, "qh_matchdupridge: make good forced merge of dupridge f%d skip %d into f%d skip %d, keep new f%d skip %d and f%d skip %d, dist %4.4g\n",
    2631             :                   goodmatch->id, goodskip, goodmatch2->id, goodskip2, newfacet->id, newskip, facet->id, skip, gooddist));
    2632           0 :                 goodmatch2= NULL;
    2633             :               }else {
    2634           0 :                 SETelem_(facet->neighbors, skip)= newfacet;
    2635           0 :                 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;  /* resolved by qh_mark_dupridges */
    2636           0 :                 *hashcount -= 2; /* removed two unmatched facets */
    2637           0 :                 trace3((qh, qh->ferr, 3073, "qh_matchdupridge: make forced merge of dupridge for new f%d skip %d and f%d skip %d, maxdist %4.4g in qh_forcedmerges\n",
    2638             :                   newfacet->id, newskip, facet->id, skip, maxdist2));
    2639             :               }
    2640             :             }else { /* !makematch */
    2641           0 :               if (!facet->normal)
    2642           0 :                 qh_setfacetplane(qh, facet); /* qh_mergecycle will ignore 'mergehorizon' facets with normals, too many cases otherwise */
    2643           0 :               if (!newfacet->normal)
    2644           0 :                 qh_setfacetplane(qh, newfacet);
    2645           0 :               dupdist= qh_getdistance(qh, facet, newfacet, &low, &high); /* ignore low/high */
    2646           0 :               dupdist2= qh_getdistance(qh, newfacet, facet, &low, &high);
    2647           0 :               if (isduplicate) {
    2648           0 :                 goodmatch= NULL;
    2649           0 :                 minimize_(dupdist, dupdist2);
    2650           0 :                 maxdist= dupdist;
    2651           0 :                 maxdist2= REALmax/2;
    2652           0 :                 maxmatch= facet;
    2653           0 :                 maxskip= skip;
    2654           0 :                 maxmatch2= newfacet;
    2655           0 :                 maxskip2= newskip;
    2656           0 :                 break; /* force maxmatch */
    2657           0 :               }else if (facet->flipped && !newfacet->flipped && dupdist < maxgood) {
    2658           0 :                 if (!goodmatch || !goodmatch->flipped || dupdist < gooddist) {
    2659           0 :                   goodmatch= facet;
    2660           0 :                   goodskip= skip;
    2661           0 :                   goodmatch2= newfacet;
    2662           0 :                   goodskip2= newskip;
    2663           0 :                   gooddist= dupdist;
    2664           0 :                   trace3((qh, qh->ferr, 3070, "qh_matchdupridge: try good dupridge flipped f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
    2665             :                     goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
    2666             :                 }
    2667           0 :               }else if (newfacet->flipped && !facet->flipped && dupdist2 < maxgood) {
    2668           0 :                 if (!goodmatch || !goodmatch->flipped || dupdist2 < gooddist) {
    2669           0 :                   goodmatch= newfacet;
    2670           0 :                   goodskip= newskip;
    2671           0 :                   goodmatch2= facet;
    2672           0 :                   goodskip2= skip;
    2673           0 :                   gooddist= dupdist2;
    2674           0 :                   trace3((qh, qh->ferr, 3071, "qh_matchdupridge: try good dupridge flipped new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
    2675             :                     goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
    2676             :                 }
    2677           0 :               }else if (dupdist < maxgood && (!newfacet->flipped || facet->flipped)) { /* disallow not-flipped->flipped */
    2678           0 :                 if (!goodmatch || (!goodmatch->flipped && dupdist < gooddist)) {
    2679           0 :                   goodmatch= facet;
    2680           0 :                   goodskip= skip;
    2681           0 :                   goodmatch2= newfacet;
    2682           0 :                   goodskip2= newskip;
    2683           0 :                   gooddist= dupdist;
    2684           0 :                   trace3((qh, qh->ferr, 3072, "qh_matchdupridge: try good dupridge f%d skip %d into new f%d skip %d at dist %2.2g otherdist %2.2g\n",
    2685             :                     goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist2));
    2686             :                 }
    2687           0 :               }else if (dupdist2 < maxgood && (!facet->flipped || newfacet->flipped)) { /* disallow not-flipped->flipped */
    2688           0 :                 if (!goodmatch || (!goodmatch->flipped && dupdist2 < gooddist)) {
    2689           0 :                   goodmatch= newfacet;
    2690           0 :                   goodskip= newskip;
    2691           0 :                   goodmatch2= facet;
    2692           0 :                   goodskip2= skip;
    2693           0 :                   gooddist= dupdist2;
    2694           0 :                   trace3((qh, qh->ferr, 3018, "qh_matchdupridge: try good dupridge new f%d skip %d into f%d skip %d at dist %2.2g otherdist %2.2g\n",
    2695             :                     goodmatch->id, goodskip, goodmatch2->id, goodskip2, gooddist, dupdist));
    2696             :                 }
    2697           0 :               }else if (!goodmatch) { /* otherwise match the furthest apart facets */
    2698           0 :                 if (!newfacet->flipped || facet->flipped) {
    2699           0 :                   minimize_(dupdist, dupdist2);
    2700             :                 }
    2701           0 :                 if (dupdist > maxdist) { /* could keep !flipped->flipped, but probably lost anyway */
    2702           0 :                   maxdist2= maxdist;
    2703           0 :                   maxdist= dupdist;
    2704           0 :                   maxmatch= facet;
    2705           0 :                   maxskip= skip;
    2706           0 :                   maxmatch2= newfacet;
    2707           0 :                   maxskip2= newskip;
    2708           0 :                   trace3((qh, qh->ferr, 3055, "qh_matchdupridge: try furthest dupridge f%d skip %d new f%d skip %d at dist %2.2g\n",
    2709             :                     maxmatch->id, maxskip, maxmatch2->id, maxskip2, maxdist));
    2710           0 :                 }else if (dupdist > maxdist2)
    2711           0 :                   maxdist2= dupdist;
    2712             :               }
    2713             :             }
    2714             :           }
    2715             :         }
    2716             :       } /* end of foreach entry in qh.hash_table starting at 'hash' */
    2717           0 :       if (makematch && SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
    2718           0 :         qh_fprintf(qh, qh->ferr, 6156, "qhull internal error (qh_matchdupridge): no MERGEridge match for dupridge new f%d skip %d at hash %d..%d\n",
    2719             :                     newfacet->id, newskip, hash, scan);
    2720           0 :         qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
    2721             :       }
    2722             :     } /* end of foreach newfacet at 'hash' */
    2723           0 :     if (!makematch) {
    2724           0 :       if (goodmatch) {
    2725           0 :         SETelem_(goodmatch->neighbors, goodskip)= goodmatch2;
    2726           0 :         SETelem_(goodmatch2->neighbors, goodskip2)= goodmatch;
    2727           0 :         *hashcount -= 2; /* removed two unmatched facets */
    2728           0 :         if (goodmatch->flipped) {
    2729           0 :           if (!goodmatch2->flipped) {
    2730           0 :             zzinc_(Zflipridge);
    2731             :           }else {
    2732           0 :             zzinc_(Zflipridge2);
    2733             :             /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
    2734             :           }
    2735             :         }
    2736             :         /* previously traced */
    2737           0 :       }else if (maxmatch) {
    2738           0 :         SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; /* maxmatch!=NULL by QH6157 */
    2739           0 :         SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
    2740           0 :         *hashcount -= 2; /* removed two unmatched facets */
    2741           0 :         zzinc_(Zmultiridge);
    2742             :         /* qh_joggle_restart called by qh_matchneighbor if qh_DUPLICATEridge */
    2743           0 :         trace0((qh, qh->ferr, 25, "qh_matchdupridge: keep dupridge f%d skip %d and f%d skip %d, dist %4.4g\n",
    2744             :           maxmatch2->id, maxskip2, maxmatch->id, maxskip, maxdist));
    2745             :       } else {
    2746           0 :         qh_fprintf(qh, qh->ferr, 6157, "qhull internal error (qh_matchdupridge): no maximum or good match for dupridge new f%d skip %d at hash %d..%d\n",
    2747             :           atfacet->id, atskip, hash, scan);
    2748           0 :         qh_errexit(qh, qh_ERRqhull, atfacet, NULL);
    2749             :       }
    2750             :     }
    2751             :   }
    2752           0 :   if (goodmatch)
    2753           0 :     return gooddist;
    2754           0 :   return maxdist2;
    2755             : } /* matchdupridge */
    2756             : 
    2757             : #else /* qh_NOmerge */
    2758             : coordT qh_matchdupridge(qhT *qh, facetT *atfacet, int atskip, int hashsize, int *hashcount) {
    2759             :   QHULL_UNUSED(qh)
    2760             :   QHULL_UNUSED(atfacet)
    2761             :   QHULL_UNUSED(atskip)
    2762             :   QHULL_UNUSED(hashsize)
    2763             :   QHULL_UNUSED(hashcount)
    2764             : 
    2765             :   return 0.0;
    2766             : }
    2767             : #endif /* qh_NOmerge */
    2768             : 
    2769             : /*-<a                             href="qh-poly_r.htm#TOC"
    2770             :   >-------------------------------</a><a name="nearcoplanar">-</a>
    2771             : 
    2772             :   qh_nearcoplanar()
    2773             :     for all facets, remove near-inside points from facet->coplanarset</li>
    2774             :     coplanar points defined by innerplane from qh_outerinner()
    2775             : 
    2776             :   returns:
    2777             :     if qh->KEEPcoplanar && !qh->KEEPinside
    2778             :       facet->coplanarset only contains coplanar points
    2779             :     if qh.JOGGLEmax
    2780             :       drops inner plane by another qh.JOGGLEmax diagonal since a
    2781             :         vertex could shift out while a coplanar point shifts in
    2782             : 
    2783             :   notes:
    2784             :     used for qh.PREmerge and qh.JOGGLEmax
    2785             :     must agree with computation of qh.NEARcoplanar in qh_detroundoff
    2786             : 
    2787             :   design:
    2788             :     if not keeping coplanar or inside points
    2789             :       free all coplanar sets
    2790             :     else if not keeping both coplanar and inside points
    2791             :       remove !coplanar or !inside points from coplanar sets
    2792             : */
    2793           3 : void qh_nearcoplanar(qhT *qh /* qh.facet_list */) {
    2794             :   facetT *facet;
    2795             :   pointT *point, **pointp;
    2796             :   int numpart;
    2797             :   realT dist, innerplane;
    2798             : 
    2799           3 :   if (!qh->KEEPcoplanar && !qh->KEEPinside) {
    2800           0 :     FORALLfacets {
    2801           0 :       if (facet->coplanarset)
    2802           0 :         qh_setfree(qh, &facet->coplanarset);
    2803             :     }
    2804           3 :   }else if (!qh->KEEPcoplanar || !qh->KEEPinside) {
    2805           0 :     qh_outerinner(qh, NULL, NULL, &innerplane);
    2806           0 :     if (qh->JOGGLEmax < REALmax/2)
    2807           0 :       innerplane -= qh->JOGGLEmax * sqrt((realT)qh->hull_dim);
    2808           0 :     numpart= 0;
    2809           0 :     FORALLfacets {
    2810           0 :       if (facet->coplanarset) {
    2811           0 :         FOREACHpoint_(facet->coplanarset) {
    2812           0 :           numpart++;
    2813           0 :           qh_distplane(qh, point, facet, &dist);
    2814           0 :           if (dist < innerplane) {
    2815           0 :             if (!qh->KEEPinside)
    2816           0 :               SETref_(point)= NULL;
    2817           0 :           }else if (!qh->KEEPcoplanar)
    2818           0 :             SETref_(point)= NULL;
    2819             :         }
    2820           0 :         qh_setcompact(qh, facet->coplanarset);
    2821             :       }
    2822             :     }
    2823           0 :     zzadd_(Zcheckpart, numpart);
    2824             :   }
    2825           3 : } /* nearcoplanar */
    2826             : 
    2827             : /*-<a                             href="qh-poly_r.htm#TOC"
    2828             :   >-------------------------------</a><a name="nearvertex">-</a>
    2829             : 
    2830             :   qh_nearvertex(qh, facet, point, bestdist )
    2831             :     return nearest vertex in facet to point
    2832             : 
    2833             :   returns:
    2834             :     vertex and its distance
    2835             : 
    2836             :   notes:
    2837             :     if qh.DELAUNAY
    2838             :       distance is measured in the input set
    2839             :     searches neighboring tricoplanar facets (requires vertexneighbors)
    2840             :       Slow implementation.  Recomputes vertex set for each point.
    2841             :     The vertex set could be stored in the qh.keepcentrum facet.
    2842             : */
    2843           0 : vertexT *qh_nearvertex(qhT *qh, facetT *facet, pointT *point, realT *bestdistp) {
    2844           0 :   realT bestdist= REALmax, dist;
    2845           0 :   vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
    2846             :   coordT *center;
    2847             :   facetT *neighbor, **neighborp;
    2848             :   setT *vertices;
    2849           0 :   int dim= qh->hull_dim;
    2850             : 
    2851           0 :   if (qh->DELAUNAY)
    2852           0 :     dim--;
    2853           0 :   if (facet->tricoplanar) {
    2854           0 :     if (!qh->VERTEXneighbors || !facet->center) {
    2855           0 :       qh_fprintf(qh, qh->ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
    2856           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
    2857             :     }
    2858           0 :     vertices= qh_settemp(qh, qh->TEMPsize);
    2859           0 :     apex= SETfirstt_(facet->vertices, vertexT);
    2860           0 :     center= facet->center;
    2861           0 :     FOREACHneighbor_(apex) {
    2862           0 :       if (neighbor->center == center) {
    2863           0 :         FOREACHvertex_(neighbor->vertices)
    2864           0 :           qh_setappend(qh, &vertices, vertex);
    2865             :       }
    2866             :     }
    2867             :   }else
    2868           0 :     vertices= facet->vertices;
    2869           0 :   FOREACHvertex_(vertices) {
    2870           0 :     dist= qh_pointdist(vertex->point, point, -dim);
    2871           0 :     if (dist < bestdist) {
    2872           0 :       bestdist= dist;
    2873           0 :       bestvertex= vertex;
    2874             :     }
    2875             :   }
    2876           0 :   if (facet->tricoplanar)
    2877           0 :     qh_settempfree(qh, &vertices);
    2878           0 :   *bestdistp= sqrt(bestdist);
    2879           0 :   if (!bestvertex) {
    2880           0 :       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));
    2881           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
    2882             :   }
    2883             :   /* coverity[var_deref_op] */
    2884           0 :   trace3((qh, qh->ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n",
    2885             :         bestvertex->id, *bestdistp, facet->id, qh_pointid(qh, point))); /* bestvertex!=0 by QH2161 */
    2886           0 :   return bestvertex;
    2887             : } /* nearvertex */
    2888             : 
    2889             : /*-<a                             href="qh-poly_r.htm#TOC"
    2890             :   >-------------------------------</a><a name="newhashtable">-</a>
    2891             : 
    2892             :   qh_newhashtable(qh, newsize )
    2893             :     returns size of qh.hash_table of at least newsize slots
    2894             : 
    2895             :   notes:
    2896             :     assumes qh.hash_table is NULL
    2897             :     qh_HASHfactor determines the number of extra slots
    2898             :     size is not divisible by 2, 3, or 5
    2899             : */
    2900       29065 : int qh_newhashtable(qhT *qh, int newsize) {
    2901             :   int size;
    2902             : 
    2903       29065 :   size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
    2904             :   while (True) {
    2905       32395 :     if (newsize<0 || size<0) {
    2906           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 */
    2907           0 :         qh_errexit(qh, qhmem_ERRmem, NULL, NULL);
    2908             :     }
    2909       32395 :     if ((size%3) && (size%5))
    2910       29065 :       break;
    2911        3330 :     size += 2;
    2912             :     /* loop terminates because there is an infinite number of primes */
    2913             :   }
    2914       29065 :   qh->hash_table= qh_setnew(qh, size);
    2915       29065 :   qh_setzero(qh, qh->hash_table, 0, size);
    2916       29065 :   return size;
    2917             : } /* newhashtable */
    2918             : 
    2919             : /*-<a                             href="qh-poly_r.htm#TOC"
    2920             :   >-------------------------------</a><a name="newvertex">-</a>
    2921             : 
    2922             :   qh_newvertex(qh, point )
    2923             :     returns a new vertex for point
    2924             : */
    2925       14680 : vertexT *qh_newvertex(qhT *qh, pointT *point) {
    2926             :   vertexT *vertex;
    2927             : 
    2928       14680 :   zinc_(Ztotvertices);
    2929       14680 :   vertex= (vertexT *)qh_memalloc(qh, (int)sizeof(vertexT));
    2930       14680 :   memset((char *) vertex, (size_t)0, sizeof(vertexT));
    2931       14680 :   if (qh->vertex_id == UINT_MAX) {
    2932           0 :     qh_memfree(qh, vertex, (int)sizeof(vertexT));
    2933           0 :     qh_fprintf(qh, qh->ferr, 6159, "qhull error: 2^32 or more vertices.  vertexT.id field overflows.  Vertices would not be sorted correctly.\n");
    2934           0 :     qh_errexit(qh, qh_ERRother, NULL, NULL);
    2935             :   }
    2936       14680 :   if (qh->vertex_id == qh->tracevertex_id)
    2937           0 :     qh->tracevertex= vertex;
    2938       14680 :   vertex->id= qh->vertex_id++;
    2939       14680 :   vertex->point= point;
    2940       14680 :   trace4((qh, qh->ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(qh, vertex->point),
    2941             :           vertex->id));
    2942       14680 :   return(vertex);
    2943             : } /* newvertex */
    2944             : 
    2945             : /*-<a                             href="qh-poly_r.htm#TOC"
    2946             :   >-------------------------------</a><a name="nextfacet2d">-</a>
    2947             : 
    2948             :   qh_nextfacet2d( facet, &nextvertex )
    2949             :     return next facet and vertex for a 2d facet in qh_ORIENTclock order
    2950             :     returns NULL on error
    2951             : 
    2952             :   notes:
    2953             :     in qh_ORIENTclock order (default counter-clockwise)
    2954             :     nextvertex is in between the two facets
    2955             :     does not use qhT or qh_errexit [QhullFacet.cpp]
    2956             : 
    2957             :   design:
    2958             :     see io_r.c/qh_printextremes_2d
    2959             : */
    2960           0 : facetT *qh_nextfacet2d(facetT *facet, vertexT **nextvertexp) {
    2961             :   facetT *nextfacet;
    2962             : 
    2963           0 :   if (facet->toporient ^ qh_ORIENTclock) {
    2964           0 :     *nextvertexp= SETfirstt_(facet->vertices, vertexT);
    2965           0 :     nextfacet= SETfirstt_(facet->neighbors, facetT);
    2966             :   }else {
    2967           0 :     *nextvertexp= SETsecondt_(facet->vertices, vertexT);
    2968           0 :     nextfacet= SETsecondt_(facet->neighbors, facetT);
    2969             :   }
    2970           0 :   return nextfacet;
    2971             : } /* nextfacet2d */
    2972             : 
    2973             : /*-<a                             href="qh-poly_r.htm#TOC"
    2974             :   >-------------------------------</a><a name="nextridge3d">-</a>
    2975             : 
    2976             :   qh_nextridge3d( atridge, facet, &vertex )
    2977             :     return next ridge and vertex for a 3d facet
    2978             :     returns NULL on error
    2979             :     [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qhT.
    2980             : 
    2981             :   notes:
    2982             :     in qh_ORIENTclock order
    2983             :     this is a O(n^2) implementation to trace all ridges
    2984             :     be sure to stop on any 2nd visit
    2985             :     same as QhullRidge::nextRidge3d
    2986             :     does not use qhT or qh_errexit [QhullFacet.cpp]
    2987             : 
    2988             :   design:
    2989             :     for each ridge
    2990             :       exit if it is the ridge after atridge
    2991             : */
    2992           0 : ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) {
    2993             :   vertexT *atvertex, *vertex, *othervertex;
    2994             :   ridgeT *ridge, **ridgep;
    2995             : 
    2996           0 :   if ((atridge->top == facet) ^ qh_ORIENTclock)
    2997           0 :     atvertex= SETsecondt_(atridge->vertices, vertexT);
    2998             :   else
    2999           0 :     atvertex= SETfirstt_(atridge->vertices, vertexT);
    3000           0 :   FOREACHridge_(facet->ridges) {
    3001           0 :     if (ridge == atridge)
    3002           0 :       continue;
    3003           0 :     if ((ridge->top == facet) ^ qh_ORIENTclock) {
    3004           0 :       othervertex= SETsecondt_(ridge->vertices, vertexT);
    3005           0 :       vertex= SETfirstt_(ridge->vertices, vertexT);
    3006             :     }else {
    3007           0 :       vertex= SETsecondt_(ridge->vertices, vertexT);
    3008           0 :       othervertex= SETfirstt_(ridge->vertices, vertexT);
    3009             :     }
    3010           0 :     if (vertex == atvertex) {
    3011           0 :       if (vertexp)
    3012           0 :         *vertexp= othervertex;
    3013           0 :       return ridge;
    3014             :     }
    3015             :   }
    3016           0 :   return NULL;
    3017             : } /* nextridge3d */
    3018             : 
    3019             : /*-<a                             href="qh-poly_r.htm#TOC"
    3020             :   >-------------------------------</a><a name="opposite_vertex">-</a>
    3021             : 
    3022             :   qh_opposite_vertex(qh, facetA, neighbor )
    3023             :     return the opposite vertex in facetA to neighbor
    3024             : 
    3025             : */
    3026           0 : vertexT *qh_opposite_vertex(qhT *qh, facetT *facetA,  facetT *neighbor) {
    3027           0 :     vertexT *opposite= NULL;
    3028             :     facetT *facet;
    3029             :     int facet_i, facet_n;
    3030             : 
    3031           0 :     if (facetA->simplicial) {
    3032           0 :       FOREACHfacet_i_(qh, facetA->neighbors) {
    3033           0 :         if (facet == neighbor) {
    3034           0 :           opposite= SETelemt_(facetA->vertices, facet_i, vertexT);
    3035           0 :           break;
    3036             :         }
    3037             :       }
    3038             :     }
    3039           0 :     if (!opposite) {
    3040           0 :       qh_fprintf(qh, qh->ferr, 6396, "qhull internal error (qh_opposite_vertex): opposite vertex in facet f%d to neighbor f%d is not defined.  Either is facet is not simplicial or neighbor not found\n",
    3041             :         facetA->id, neighbor->id);
    3042           0 :       qh_errexit2(qh, qh_ERRqhull, facetA, neighbor);
    3043             :     }
    3044           0 :     return opposite;
    3045             : } /* opposite_vertex */
    3046             : 
    3047             : /*-<a                             href="qh-poly_r.htm#TOC"
    3048             :   >-------------------------------</a><a name="outcoplanar">-</a>
    3049             : 
    3050             :   qh_outcoplanar()
    3051             :     move points from all facets' outsidesets to their coplanarsets
    3052             : 
    3053             :   notes:
    3054             :     for post-processing under qh.NARROWhull
    3055             : 
    3056             :   design:
    3057             :     for each facet
    3058             :       for each outside point for facet
    3059             :         partition point into coplanar set
    3060             : */
    3061           0 : void qh_outcoplanar(qhT *qh /* facet_list */) {
    3062             :   pointT *point, **pointp;
    3063             :   facetT *facet;
    3064             :   realT dist;
    3065             : 
    3066           0 :   trace1((qh, qh->ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh->NARROWhull\n"));
    3067           0 :   FORALLfacets {
    3068           0 :     FOREACHpoint_(facet->outsideset) {
    3069           0 :       qh->num_outside--;
    3070           0 :       if (qh->KEEPcoplanar || qh->KEEPnearinside) {
    3071           0 :         qh_distplane(qh, point, facet, &dist);
    3072           0 :         zinc_(Zpartition);
    3073           0 :         qh_partitioncoplanar(qh, point, facet, &dist, qh->findbestnew);
    3074             :       }
    3075             :     }
    3076           0 :     qh_setfree(qh, &facet->outsideset);
    3077             :   }
    3078           0 : } /* outcoplanar */
    3079             : 
    3080             : /*-<a                             href="qh-poly_r.htm#TOC"
    3081             :   >-------------------------------</a><a name="point">-</a>
    3082             : 
    3083             :   qh_point(qh, id )
    3084             :     return point for a point id, or NULL if unknown
    3085             : 
    3086             :   alternative code:
    3087             :     return((pointT *)((unsigned long)qh.first_point
    3088             :            + (unsigned long)((id)*qh.normal_size)));
    3089             : */
    3090       14673 : pointT *qh_point(qhT *qh, int id) {
    3091             : 
    3092       14673 :   if (id < 0)
    3093           0 :     return NULL;
    3094       14673 :   if (id < qh->num_points)
    3095       14673 :     return qh->first_point + id * qh->hull_dim;
    3096           0 :   id -= qh->num_points;
    3097           0 :   if (id < qh_setsize(qh, qh->other_points))
    3098           0 :     return SETelemt_(qh->other_points, id, pointT);
    3099           0 :   return NULL;
    3100             : } /* point */
    3101             : 
    3102             : /*-<a                             href="qh-poly_r.htm#TOC"
    3103             :   >-------------------------------</a><a name="point_add">-</a>
    3104             : 
    3105             :   qh_point_add(qh, set, point, elem )
    3106             :     stores elem at set[point.id]
    3107             : 
    3108             :   returns:
    3109             :     access function for qh_pointfacet and qh_pointvertex
    3110             : 
    3111             :   notes:
    3112             :     checks point.id
    3113             : */
    3114       29345 : void qh_point_add(qhT *qh, setT *set, pointT *point, void *elem) {
    3115             :   int id, size;
    3116             : 
    3117       29345 :   SETreturnsize_(set, size);
    3118       29345 :   if ((id= qh_pointid(qh, point)) < 0)
    3119           0 :     qh_fprintf(qh, qh->ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n",
    3120             :       point, id);
    3121       29345 :   else if (id >= size) {
    3122           0 :     qh_fprintf(qh, qh->ferr, 6160, "qhull internal error (point_add): point p%d is out of bounds(%d)\n",
    3123             :              id, size);
    3124           0 :     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
    3125             :   }else
    3126       29345 :     SETelem_(set, id)= elem;
    3127       29345 : } /* point_add */
    3128             : 
    3129             : 
    3130             : /*-<a                             href="qh-poly_r.htm#TOC"
    3131             :   >-------------------------------</a><a name="pointfacet">-</a>
    3132             : 
    3133             :   qh_pointfacet()
    3134             :     return temporary set of facet for each point
    3135             :     the set is indexed by point id
    3136             :     at most one facet per point, arbitrary selection
    3137             : 
    3138             :   notes:
    3139             :     each point is assigned to at most one of vertices, coplanarset, or outsideset
    3140             :     unassigned points are interior points or
    3141             :     vertices assigned to one of its facets
    3142             :     coplanarset assigned to the facet
    3143             :     outside set assigned to the facet
    3144             :     NULL if no facet for point (inside)
    3145             :       includes qh.GOODpointp
    3146             : 
    3147             :   access:
    3148             :     FOREACHfacet_i_(qh, facets) { ... }
    3149             :     SETelem_(facets, i)
    3150             : 
    3151             :   design:
    3152             :     for each facet
    3153             :       add each vertex
    3154             :       add each coplanar point
    3155             :       add each outside point
    3156             : */
    3157           3 : setT *qh_pointfacet(qhT *qh /* qh.facet_list */) {
    3158           3 :   int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
    3159             :   setT *facets;
    3160             :   facetT *facet;
    3161             :   vertexT *vertex, **vertexp;
    3162             :   pointT *point, **pointp;
    3163             : 
    3164           3 :   facets= qh_settemp(qh, numpoints);
    3165           3 :   qh_setzero(qh, facets, 0, numpoints);
    3166           3 :   qh->vertex_visit++;
    3167       14462 :   FORALLfacets {
    3168       72709 :     FOREACHvertex_(facet->vertices) {
    3169       58250 :       if (vertex->visitid != qh->vertex_visit) {
    3170       14672 :         vertex->visitid= qh->vertex_visit;
    3171       14672 :         qh_point_add(qh, facets, vertex->point, facet);
    3172             :       }
    3173             :     }
    3174       14460 :     FOREACHpoint_(facet->coplanarset)
    3175           1 :       qh_point_add(qh, facets, point, facet);
    3176       14459 :     FOREACHpoint_(facet->outsideset)
    3177           0 :       qh_point_add(qh, facets, point, facet);
    3178             :   }
    3179           3 :   return facets;
    3180             : } /* pointfacet */
    3181             : 
    3182             : /*-<a                             href="qh-poly_r.htm#TOC"
    3183             :   >-------------------------------</a><a name="pointvertex">-</a>
    3184             : 
    3185             :   qh_pointvertex(qh )
    3186             :     return temporary set of vertices indexed by point id
    3187             :     entry is NULL if no vertex for a point
    3188             :       this will include qh.GOODpointp
    3189             : 
    3190             :   access:
    3191             :     FOREACHvertex_i_(qh, vertices) { ... }
    3192             :     SETelem_(vertices, i)
    3193             : */
    3194           3 : setT *qh_pointvertex(qhT *qh /* qh.facet_list */) {
    3195           3 :   int numpoints= qh->num_points + qh_setsize(qh, qh->other_points);
    3196             :   setT *vertices;
    3197             :   vertexT *vertex;
    3198             : 
    3199           3 :   vertices= qh_settemp(qh, numpoints);
    3200           3 :   qh_setzero(qh, vertices, 0, numpoints);
    3201       14675 :   FORALLvertices
    3202       14672 :     qh_point_add(qh, vertices, vertex->point, vertex);
    3203           3 :   return vertices;
    3204             : } /* pointvertex */
    3205             : 
    3206             : 
    3207             : /*-<a                             href="qh-poly_r.htm#TOC"
    3208             :   >-------------------------------</a><a name="prependfacet">-</a>
    3209             : 
    3210             :   qh_prependfacet(qh, facet, facetlist )
    3211             :     prepend facet to the start of a facetlist
    3212             : 
    3213             :   returns:
    3214             :     increments qh.numfacets
    3215             :     updates facetlist, qh.facet_list, facet_next
    3216             : 
    3217             :   notes:
    3218             :     be careful of prepending since it can lose a pointer.
    3219             :       e.g., can lose _next by deleting and then prepending before _next
    3220             : */
    3221       63266 : void qh_prependfacet(qhT *qh, facetT *facet, facetT **facetlist) {
    3222             :   facetT *prevfacet, *list;
    3223             : 
    3224       63266 :   trace4((qh, qh->ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n",
    3225             :           facet->id, getid_(*facetlist)));
    3226       63266 :   if (!*facetlist)
    3227           2 :     (*facetlist)= qh->facet_tail;
    3228       63266 :   list= *facetlist;
    3229       63266 :   prevfacet= list->previous;
    3230       63266 :   facet->previous= prevfacet;
    3231       63266 :   if (prevfacet)
    3232       63263 :     prevfacet->next= facet;
    3233       63266 :   list->previous= facet;
    3234       63266 :   facet->next= *facetlist;
    3235       63266 :   if (qh->facet_list == list)  /* this may change *facetlist */
    3236           3 :     qh->facet_list= facet;
    3237       63266 :   if (qh->facet_next == list)
    3238           5 :     qh->facet_next= facet;
    3239       63266 :   *facetlist= facet;
    3240       63266 :   qh->num_facets++;
    3241       63266 : } /* prependfacet */
    3242             : 
    3243             : 
    3244             : /*-<a                             href="qh-poly_r.htm#TOC"
    3245             :   >-------------------------------</a><a name="printhashtable">-</a>
    3246             : 
    3247             :   qh_printhashtable(qh, fp )
    3248             :     print hash table to fp
    3249             : 
    3250             :   notes:
    3251             :     not in I/O to avoid bringing io_r.c in
    3252             : 
    3253             :   design:
    3254             :     for each hash entry
    3255             :       if defined
    3256             :         if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
    3257             :           print entry and neighbors
    3258             : */
    3259           0 : void qh_printhashtable(qhT *qh, FILE *fp) {
    3260             :   facetT *facet, *neighbor;
    3261           0 :   int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
    3262             :   vertexT *vertex, **vertexp;
    3263             : 
    3264           0 :   FOREACHfacet_i_(qh, qh->hash_table) {
    3265           0 :     if (facet) {
    3266           0 :       FOREACHneighbor_i_(qh, facet) {
    3267           0 :         if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
    3268             :           break;
    3269             :       }
    3270           0 :       if (neighbor_i == neighbor_n)
    3271           0 :         continue;
    3272           0 :       qh_fprintf(qh, fp, 9283, "hash %d f%d ", facet_i, facet->id);
    3273           0 :       FOREACHvertex_(facet->vertices)
    3274           0 :         qh_fprintf(qh, fp, 9284, "v%d ", vertex->id);
    3275           0 :       qh_fprintf(qh, fp, 9285, "\n neighbors:");
    3276           0 :       FOREACHneighbor_i_(qh, facet) {
    3277           0 :         if (neighbor == qh_MERGEridge)
    3278           0 :           id= -3;
    3279           0 :         else if (neighbor == qh_DUPLICATEridge)
    3280           0 :           id= -2;
    3281             :         else
    3282           0 :           id= getid_(neighbor);
    3283           0 :         qh_fprintf(qh, fp, 9286, " %d", id);
    3284             :       }
    3285           0 :       qh_fprintf(qh, fp, 9287, "\n");
    3286             :     }
    3287             :   }
    3288           0 : } /* printhashtable */
    3289             : 
    3290             : /*-<a                             href="qh-poly_r.htm#TOC"
    3291             :   >-------------------------------</a><a name="printlists">-</a>
    3292             : 
    3293             :   qh_printlists(qh)
    3294             :     print out facet and vertex lists for debugging (without 'f/v' tags)
    3295             : 
    3296             :   notes:
    3297             :     not in I/O to avoid bringing io_r.c in
    3298             : */
    3299           0 : void qh_printlists(qhT *qh) {
    3300             :   facetT *facet;
    3301             :   vertexT *vertex;
    3302           0 :   int count= 0;
    3303             : 
    3304           0 :   qh_fprintf(qh, qh->ferr, 3062, "qh_printlists: max_outside %2.2g all facets:", qh->max_outside);
    3305           0 :   FORALLfacets{
    3306           0 :     if (++count % 100 == 0)
    3307           0 :       qh_fprintf(qh, qh->ferr, 8109, "\n     ");
    3308           0 :     qh_fprintf(qh, qh->ferr, 8110, " %d", facet->id);
    3309             :   }
    3310           0 :     qh_fprintf(qh, qh->ferr, 8111, "\n  qh.visible_list f%d, newfacet_list f%d, facet_next f%d for qh_addpoint\n  qh.newvertex_list v%d all vertices:",
    3311           0 :       getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->facet_next), getid_(qh->newvertex_list));
    3312           0 :   count= 0;
    3313           0 :   FORALLvertices{
    3314           0 :     if (++count % 100 == 0)
    3315           0 :       qh_fprintf(qh, qh->ferr, 8112, "\n     ");
    3316           0 :     qh_fprintf(qh, qh->ferr, 8113, " %d", vertex->id);
    3317             :   }
    3318           0 :   qh_fprintf(qh, qh->ferr, 8114, "\n");
    3319           0 : } /* printlists */
    3320             : 
    3321             : /*-<a                             href="qh-poly.htm#TOC"
    3322             :   >-------------------------------</a><a name="addfacetvertex">-</a>
    3323             : 
    3324             :   qh_replacefacetvertex(qh, facet, oldvertex, newvertex )
    3325             :     replace oldvertex with newvertex in f.vertices
    3326             :     vertices are inverse sorted by vertex->id
    3327             : 
    3328             :   returns:
    3329             :     toporient is flipped if an odd parity, position change
    3330             : 
    3331             :   notes:
    3332             :     for simplicial facets in qh_rename_adjacentvertex
    3333             :     see qh_addfacetvertex
    3334             : */
    3335           0 : void qh_replacefacetvertex(qhT *qh, facetT *facet, vertexT *oldvertex, vertexT *newvertex) {
    3336             :   vertexT *vertex;
    3337             :   facetT *neighbor;
    3338           0 :   int vertex_i, vertex_n= 0;
    3339           0 :   int old_i= -1, new_i= -1;
    3340             : 
    3341           0 :   trace3((qh, qh->ferr, 3038, "qh_replacefacetvertex: replace v%d with v%d in f%d\n", oldvertex->id, newvertex->id, facet->id));
    3342           0 :   if (!facet->simplicial) {
    3343           0 :     qh_fprintf(qh, qh->ferr, 6283, "qhull internal error (qh_replacefacetvertex): f%d is not simplicial\n", facet->id);
    3344           0 :     qh_errexit(qh, qh_ERRqhull, facet, NULL);
    3345             :   }
    3346           0 :   FOREACHvertex_i_(qh, facet->vertices) {
    3347           0 :     if (new_i == -1 && vertex->id < newvertex->id) {
    3348           0 :       new_i= vertex_i;
    3349           0 :     }else if (vertex->id == newvertex->id) {
    3350           0 :       qh_fprintf(qh, qh->ferr, 6281, "qhull internal error (qh_replacefacetvertex): f%d already contains new v%d\n", facet->id, newvertex->id);
    3351           0 :       qh_errexit(qh, qh_ERRqhull, facet, NULL);
    3352             :     }
    3353           0 :     if (vertex->id == oldvertex->id) {
    3354           0 :       old_i= vertex_i;
    3355             :     }
    3356             :   }
    3357           0 :   if (old_i == -1) {
    3358           0 :     qh_fprintf(qh, qh->ferr, 6282, "qhull internal error (qh_replacefacetvertex): f%d does not contain old v%d\n", facet->id, oldvertex->id);
    3359           0 :     qh_errexit(qh, qh_ERRqhull, facet, NULL);
    3360             :   }
    3361           0 :   if (new_i == -1) {
    3362           0 :     new_i= vertex_n;
    3363             :   }
    3364           0 :   if (old_i < new_i)
    3365           0 :     new_i--;
    3366           0 :   if ((old_i & 0x1) != (new_i & 0x1))
    3367           0 :     facet->toporient ^= 1;
    3368           0 :   qh_setdelnthsorted(qh, facet->vertices, old_i);
    3369           0 :   qh_setaddnth(qh, &facet->vertices, new_i, newvertex);
    3370           0 :   neighbor= SETelemt_(facet->neighbors, old_i, facetT);
    3371           0 :   qh_setdelnthsorted(qh, facet->neighbors, old_i);
    3372           0 :   qh_setaddnth(qh, &facet->neighbors, new_i, neighbor);
    3373           0 : } /* replacefacetvertex */
    3374             : 
    3375             : /*-<a                             href="qh-poly_r.htm#TOC"
    3376             :   >-------------------------------</a><a name="resetlists">-</a>
    3377             : 
    3378             :   qh_resetlists(qh, stats, qh_RESETvisible )
    3379             :     reset newvertex_list, newfacet_list, visible_list, NEWfacets, NEWtentative
    3380             :     if stats,
    3381             :       maintains statistics
    3382             :     if resetVisible,
    3383             :       visible_list is restored to facet_list
    3384             :       otherwise, f.visible/f.replace is retained
    3385             : 
    3386             :   returns:
    3387             :     newvertex_list, newfacet_list, visible_list are NULL
    3388             : 
    3389             :   notes:
    3390             :     To delete visible facets, call qh_deletevisible before qh_resetlists
    3391             : */
    3392       29075 : void qh_resetlists(qhT *qh, boolT stats, boolT resetVisible /* qh.newvertex_list newfacet_list visible_list */) {
    3393             :   vertexT *vertex;
    3394             :   facetT *newfacet, *visible;
    3395       29075 :   int totnew=0, totver=0;
    3396             : 
    3397       29075 :   trace2((qh, qh->ferr, 2066, "qh_resetlists: reset newvertex_list v%d, newfacet_list f%d, visible_list f%d, facet_list f%d next f%d vertex_list v%d -- NEWfacets? %d, NEWtentative? %d, stats? %d\n",
    3398             :     getid_(qh->newvertex_list), getid_(qh->newfacet_list), getid_(qh->visible_list), getid_(qh->facet_list), getid_(qh->facet_next), getid_(qh->vertex_list), qh->NEWfacets, qh->NEWtentative, stats));
    3399       29075 :   if (stats) {
    3400      150966 :     FORALLvertex_(qh->newvertex_list)
    3401      136306 :       totver++;
    3402       88064 :     FORALLnew_facets
    3403       73404 :       totnew++;
    3404       14660 :     zadd_(Zvisvertextot, totver);
    3405       14660 :     zmax_(Zvisvertexmax, totver);
    3406       14660 :     zadd_(Znewfacettot, totnew);
    3407       14660 :     zmax_(Znewfacetmax, totnew);
    3408             :   }
    3409      180042 :   FORALLvertex_(qh->newvertex_list)
    3410      150967 :     vertex->newfacet= False;
    3411       29075 :   qh->newvertex_list= NULL;
    3412       29075 :   qh->first_newfacet= 0;
    3413      160583 :   FORALLnew_facets {
    3414      131508 :     newfacet->newfacet= False;
    3415      131508 :     newfacet->dupridge= False;
    3416             :   }
    3417       29075 :   qh->newfacet_list= NULL;
    3418       29075 :   if (resetVisible) {
    3419       14667 :     FORALLvisible_facets {
    3420           0 :       visible->f.replace= NULL;
    3421           0 :       visible->visible= False;
    3422             :     }
    3423       14667 :     qh->num_visible= 0;
    3424             :   }
    3425       29075 :   qh->visible_list= NULL;
    3426       29075 :   qh->NEWfacets= False;
    3427       29075 :   qh->NEWtentative= False;
    3428       29075 : } /* resetlists */
    3429             : 
    3430             : /*-<a                             href="qh-poly_r.htm#TOC"
    3431             :   >-------------------------------</a><a name="setvoronoi_all">-</a>
    3432             : 
    3433             :   qh_setvoronoi_all(qh)
    3434             :     compute Voronoi centers for all facets
    3435             :     includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
    3436             : 
    3437             :   returns:
    3438             :     facet->center is the Voronoi center
    3439             : 
    3440             :   notes:
    3441             :     unused/untested code: please email bradb@shore.net if this works ok for you
    3442             : 
    3443             :   use:
    3444             :     FORALLvertices {...} to locate the vertex for a point.
    3445             :     FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
    3446             : */
    3447           0 : void qh_setvoronoi_all(qhT *qh) {
    3448             :   facetT *facet;
    3449             : 
    3450           0 :   qh_clearcenters(qh, qh_ASvoronoi);
    3451           0 :   qh_vertexneighbors(qh);
    3452             : 
    3453           0 :   FORALLfacets {
    3454           0 :     if (!facet->normal || !facet->upperdelaunay || qh->UPPERdelaunay) {
    3455           0 :       if (!facet->center)
    3456           0 :         facet->center= qh_facetcenter(qh, facet->vertices);
    3457             :     }
    3458             :   }
    3459           0 : } /* setvoronoi_all */
    3460             : 
    3461             : #ifndef qh_NOmerge
    3462             : /*-<a                             href="qh-poly_r.htm#TOC"
    3463             :   >-------------------------------</a><a name="triangulate">-</a>
    3464             : 
    3465             :   qh_triangulate()
    3466             :     triangulate non-simplicial facets on qh.facet_list,
    3467             :     if qh->VORONOI, sets Voronoi centers of non-simplicial facets
    3468             :     nop if hasTriangulation
    3469             : 
    3470             :   returns:
    3471             :     all facets simplicial
    3472             :     each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
    3473             :     resets qh.newfacet_list and visible_list
    3474             : 
    3475             :   notes:
    3476             :     called by qh_prepare_output and user_eg2_r.c
    3477             :     call after qh_check_output since may switch to Voronoi centers, and qh_checkconvex skips f.tricoplanar facets
    3478             :     Output may overwrite ->f.triowner with ->f.area
    3479             :     while running, 'triangulated_facet_list' is a list of
    3480             :        one non-simplicial facet followed by its 'f.tricoplanar' triangulated facets
    3481             :     See qh_buildcone
    3482             : */
    3483           3 : void qh_triangulate(qhT *qh /* qh.facet_list */) {
    3484             :   facetT *facet, *nextfacet, *owner;
    3485           3 :   facetT *neighbor, *visible= NULL, *facet1, *facet2, *triangulated_facet_list= NULL;
    3486           3 :   facetT *orig_neighbor= NULL, *otherfacet;
    3487           3 :   vertexT *triangulated_vertex_list= NULL;
    3488             :   mergeT *merge;
    3489             :   mergeType mergetype;
    3490             :   int neighbor_i, neighbor_n;
    3491           3 :   boolT onlygood= qh->ONLYgood;
    3492             : 
    3493           3 :   if (qh->hasTriangulation)
    3494           0 :       return;
    3495           3 :   trace1((qh, qh->ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n"));
    3496           3 :   if (qh->hull_dim == 2)
    3497           0 :     return;
    3498           3 :   if (qh->VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
    3499           0 :     qh_clearcenters(qh, qh_ASvoronoi);
    3500           0 :     qh_vertexneighbors(qh);
    3501             :   }
    3502           3 :   qh->ONLYgood= False; /* for makenew_nonsimplicial */
    3503           3 :   qh->visit_id++;
    3504           3 :   qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
    3505           3 :   qh->newvertex_list= qh->vertex_tail;
    3506       86955 :   for (facet=qh->facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
    3507       86952 :     nextfacet= facet->next;
    3508       86952 :     if (facet->visible || facet->simplicial)
    3509       72547 :       continue;
    3510             :     /* 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 */
    3511       14405 :     if (!triangulated_facet_list)
    3512           2 :       triangulated_facet_list= facet;  /* will be first triangulated facet */
    3513       14405 :     qh_triangulate_facet(qh, facet, &triangulated_vertex_list); /* qh_resetlists ! */
    3514             :   }
    3515             :   /* qh_checkpolygon invalid due to f.visible without qh.visible_list */
    3516           3 :   trace2((qh, qh->ferr, 2047, "qh_triangulate: delete null facets from facetlist f%d.  A null facet has the same first (apex) and second vertices\n", getid_(triangulated_facet_list)));
    3517      101305 :   for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
    3518      101302 :     nextfacet= facet->next;
    3519      101302 :     if (facet->visible)
    3520       43214 :       continue;
    3521       58088 :     if (facet->ridges) {
    3522       29040 :       if (qh_setsize(qh, facet->ridges) > 0) {
    3523           0 :         qh_fprintf(qh, qh->ferr, 6161, "qhull internal error (qh_triangulate): ridges still defined for f%d\n", facet->id);
    3524           0 :         qh_errexit(qh, qh_ERRqhull, facet, NULL);
    3525             :       }
    3526       29040 :       qh_setfree(qh, &facet->ridges);
    3527             :     }
    3528       58088 :     if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
    3529       28810 :       zinc_(Ztrinull);
    3530       28810 :       qh_triangulate_null(qh, facet); /* will delete facet */
    3531             :     }
    3532             :   }
    3533           3 :   trace2((qh, qh->ferr, 2048, "qh_triangulate: delete %d or more mirrored facets.  Mirrored facets have the same vertices due to a null facet\n", qh_setsize(qh, qh->degen_mergeset)));
    3534           3 :   qh->visible_list= qh->facet_tail;
    3535           3 :   while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
    3536           0 :     facet1= merge->facet1;
    3537           0 :     facet2= merge->facet2;
    3538           0 :     mergetype= merge->mergetype;
    3539           0 :     qh_memfree(qh, merge, (int)sizeof(mergeT));
    3540           0 :     if (mergetype == MRGmirror) {
    3541           0 :       zinc_(Ztrimirror);
    3542           0 :       qh_triangulate_mirror(qh, facet1, facet2);  /* will delete both facets */
    3543             :     }
    3544             :   }
    3545           3 :   qh_freemergesets(qh);
    3546           3 :   trace2((qh, qh->ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(triangulated_vertex_list)));
    3547           3 :   qh->newvertex_list= triangulated_vertex_list;  /* all vertices of triangulated facets */
    3548           3 :   qh->visible_list= NULL;
    3549           3 :   qh_update_vertexneighbors(qh /* qh.newvertex_list, empty newfacet_list and visible_list */);
    3550           3 :   qh_resetlists(qh, False, !qh_RESETvisible /* qh.newvertex_list, empty newfacet_list and visible_list */);
    3551             : 
    3552           3 :   trace2((qh, qh->ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(triangulated_facet_list)));
    3553           3 :   trace2((qh, qh->ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
    3554       72496 :   FORALLfacet_(triangulated_facet_list) {
    3555       72493 :     if (facet->tricoplanar && !facet->visible) {
    3556      117112 :       FOREACHneighbor_i_(qh, facet) {
    3557       87834 :         if (neighbor_i == 0) {  /* first iteration */
    3558       29278 :           if (neighbor->tricoplanar)
    3559       29272 :             orig_neighbor= neighbor->f.triowner;
    3560             :           else
    3561           6 :             orig_neighbor= neighbor;
    3562             :         }else {
    3563       58556 :           if (neighbor->tricoplanar)
    3564       58554 :             otherfacet= neighbor->f.triowner;
    3565             :           else
    3566           2 :             otherfacet= neighbor;
    3567       58556 :           if (orig_neighbor == otherfacet) {
    3568           0 :             zinc_(Ztridegen);
    3569           0 :             facet->degenerate= True;
    3570           0 :             break;
    3571             :           }
    3572             :         }
    3573             :       }
    3574             :     }
    3575             :   }
    3576           3 :   if (qh->IStracing >= 4)
    3577           0 :     qh_printlists(qh);
    3578           3 :   trace2((qh, qh->ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
    3579           3 :   owner= NULL;
    3580           3 :   visible= NULL;
    3581       86901 :   for (facet=triangulated_facet_list; facet && facet->next; facet= nextfacet) {
    3582             :     /* deleting facets, triangulated_facet_list is no longer valid */
    3583       86898 :     nextfacet= facet->next;
    3584       86898 :     if (facet->visible) {
    3585       43215 :       if (facet->tricoplanar) { /* a null or mirrored facet */
    3586       28810 :         qh_delfacet(qh, facet);
    3587       28810 :         qh->num_visible--;
    3588             :       }else {  /* a non-simplicial facet followed by its tricoplanars */
    3589       14405 :         if (visible && !owner) {
    3590             :           /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
    3591           0 :           trace2((qh, qh->ferr, 2053, "qh_triangulate: delete f%d.  All tricoplanar facets degenerate for non-simplicial facet\n",
    3592             :                        visible->id));
    3593           0 :           qh_delfacet(qh, visible);
    3594           0 :           qh->num_visible--;
    3595             :         }
    3596       14405 :         visible= facet;
    3597       14405 :         owner= NULL;
    3598             :       }
    3599       43683 :     }else if (facet->tricoplanar) {
    3600       43683 :       if (facet->f.triowner != visible || visible==NULL) {
    3601           0 :         qh_fprintf(qh, qh->ferr, 6162, "qhull internal error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
    3602           0 :         qh_errexit2(qh, qh_ERRqhull, facet, visible);
    3603             :       }
    3604       43683 :       if (owner)
    3605       29278 :         facet->f.triowner= owner;
    3606       14405 :       else if (!facet->degenerate) {
    3607       14405 :         owner= facet;
    3608       14405 :         nextfacet= visible->next; /* rescan tricoplanar facets with owner, visible!=0 by QH6162 */
    3609       14405 :         facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
    3610       14405 :         facet->coplanarset= visible->coplanarset;
    3611       14405 :         facet->outsideset= visible->outsideset;
    3612       14405 :         visible->coplanarset= NULL;
    3613       14405 :         visible->outsideset= NULL;
    3614       14405 :         if (!qh->TRInormals) { /* center and normal copied to tricoplanar facets */
    3615       14405 :           visible->center= NULL;
    3616       14405 :           visible->normal= NULL;
    3617             :         }
    3618       14405 :         qh_delfacet(qh, visible);
    3619       14405 :         qh->num_visible--;
    3620             :       }
    3621             :     }
    3622       86898 :     facet->degenerate= False; /* reset f.degenerate set by qh_triangulate*/
    3623             :   }
    3624           3 :   if (visible && !owner) {
    3625           0 :     trace2((qh, qh->ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
    3626             :                  visible->id));
    3627           0 :     qh_delfacet(qh, visible);
    3628           0 :     qh->num_visible--;
    3629             :   }
    3630           3 :   qh->ONLYgood= onlygood; /* restore value */
    3631           3 :   if (qh->CHECKfrequently)
    3632           0 :     qh_checkpolygon(qh, qh->facet_list);
    3633           3 :   qh->hasTriangulation= True;
    3634             : } /* triangulate */
    3635             : 
    3636             : 
    3637             : /*-<a                             href="qh-poly_r.htm#TOC"
    3638             :   >-------------------------------</a><a name="triangulate_facet">-</a>
    3639             : 
    3640             :   qh_triangulate_facet(qh, facetA, &firstVertex )
    3641             :     triangulate a non-simplicial facet
    3642             :       if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
    3643             :   returns:
    3644             :     qh.newfacet_list == simplicial facets
    3645             :       facet->tricoplanar set and ->keepcentrum false
    3646             :       facet->degenerate set if duplicated apex
    3647             :       facet->f.trivisible set to facetA
    3648             :       facet->center copied from facetA (created if qh_ASvoronoi)
    3649             :         qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
    3650             :       facet->normal,offset,maxoutside copied from facetA
    3651             : 
    3652             :   notes:
    3653             :       only called by qh_triangulate
    3654             :       qh_makenew_nonsimplicial uses neighbor->seen for the same
    3655             :       if qh.TRInormals, newfacet->normal will need qh_free
    3656             :         if qh.TRInormals and qh_AScentrum, newfacet->center will need qh_free
    3657             :         keepcentrum is also set on Zwidefacet in qh_mergefacet
    3658             :         freed by qh_clearcenters
    3659             : 
    3660             :   see also:
    3661             :       qh_addpoint() -- add a point
    3662             :       qh_makenewfacets() -- construct a cone of facets for a new vertex
    3663             : 
    3664             :   design:
    3665             :       if qh_ASvoronoi,
    3666             :          compute Voronoi center (facet->center)
    3667             :       select first vertex (highest ID to preserve ID ordering of ->vertices)
    3668             :       triangulate from vertex to ridges
    3669             :       copy facet->center, normal, offset
    3670             :       update vertex neighbors
    3671             : */
    3672       14405 : void qh_triangulate_facet(qhT *qh, facetT *facetA, vertexT **first_vertex) {
    3673             :   facetT *newfacet;
    3674             :   facetT *neighbor, **neighborp;
    3675             :   vertexT *apex;
    3676       14405 :   int numnew=0;
    3677             : 
    3678       14405 :   trace3((qh, qh->ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
    3679             : 
    3680       14405 :   qh->first_newfacet= qh->facet_id;
    3681       14405 :   if (qh->IStracing >= 4)
    3682           0 :     qh_printfacet(qh, qh->ferr, facetA);
    3683       72493 :   FOREACHneighbor_(facetA) {
    3684       58088 :     neighbor->seen= False;
    3685       58088 :     neighbor->coplanarhorizon= False;
    3686             :   }
    3687       14405 :   if (qh->CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
    3688           0 :   && fabs_(facetA->normal[qh->hull_dim -1]) >= qh->ANGLEround * qh_ZEROdelaunay) {
    3689           0 :     facetA->center= qh_facetcenter(qh, facetA->vertices);
    3690             :   }
    3691       14405 :   qh->visible_list= qh->newfacet_list= qh->facet_tail;
    3692       14405 :   facetA->visitid= qh->visit_id;
    3693       14405 :   apex= SETfirstt_(facetA->vertices, vertexT);
    3694       14405 :   qh_makenew_nonsimplicial(qh, facetA, apex, &numnew);
    3695       14405 :   qh_willdelete(qh, facetA, NULL);
    3696       72493 :   FORALLnew_facets {
    3697       58088 :     newfacet->tricoplanar= True;
    3698       58088 :     newfacet->f.trivisible= facetA;
    3699       58088 :     newfacet->degenerate= False;
    3700       58088 :     newfacet->upperdelaunay= facetA->upperdelaunay;
    3701       58088 :     newfacet->good= facetA->good;
    3702       58088 :     if (qh->TRInormals) { /* 'Q11' triangulate duplicates ->normal and ->center */
    3703           0 :       newfacet->keepcentrum= True;
    3704           0 :       if(facetA->normal){
    3705           0 :         newfacet->normal= (double *)qh_memalloc(qh, qh->normal_size);
    3706           0 :         memcpy((char *)newfacet->normal, facetA->normal, (size_t)qh->normal_size);
    3707             :       }
    3708           0 :       if (qh->CENTERtype == qh_AScentrum)
    3709           0 :         newfacet->center= qh_getcentrum(qh, newfacet);
    3710           0 :       else if (qh->CENTERtype == qh_ASvoronoi && facetA->center){
    3711           0 :         newfacet->center= (double *)qh_memalloc(qh, qh->center_size);
    3712           0 :         memcpy((char *)newfacet->center, facetA->center, (size_t)qh->center_size);
    3713             :       }
    3714             :     }else {
    3715       58088 :       newfacet->keepcentrum= False;
    3716             :       /* one facet will have keepcentrum=True at end of qh_triangulate */
    3717       58088 :       newfacet->normal= facetA->normal;
    3718       58088 :       newfacet->center= facetA->center;
    3719             :     }
    3720       58088 :     newfacet->offset= facetA->offset;
    3721             : #if qh_MAXoutside
    3722       58088 :     newfacet->maxoutside= facetA->maxoutside;
    3723             : #endif
    3724             :   }
    3725       14405 :   qh_matchnewfacets(qh /* qh.newfacet_list */); /* ignore returned value, maxdupdist */
    3726       14405 :   zinc_(Ztricoplanar);
    3727       14405 :   zadd_(Ztricoplanartot, numnew);
    3728       14405 :   zmax_(Ztricoplanarmax, numnew);
    3729       14405 :   if (!(*first_vertex))
    3730           2 :     (*first_vertex)= qh->newvertex_list;
    3731       14405 :   qh->newvertex_list= NULL;
    3732       14405 :   qh->visible_list= NULL;
    3733             :   /* only update v.neighbors for qh.newfacet_list.  qh.visible_list and qh.newvertex_list are NULL */
    3734       14405 :   qh_update_vertexneighbors(qh /* qh.newfacet_list */);
    3735       14405 :   qh_resetlists(qh, False, !qh_RESETvisible /* qh.newfacet_list */);
    3736       14405 : } /* triangulate_facet */
    3737             : 
    3738             : /*-<a                             href="qh-poly_r.htm#TOC"
    3739             :   >-------------------------------</a><a name="triangulate_link">-</a>
    3740             : 
    3741             :   qh_triangulate_link(qh, oldfacetA, facetA, oldfacetB, facetB)
    3742             :     relink facetA to facetB via null oldfacetA or mirrored oldfacetA and oldfacetB
    3743             :   returns:
    3744             :     if neighbors are already linked, will merge as MRGmirror (qh.degen_mergeset, 4-d and up)
    3745             : */
    3746       28810 : void qh_triangulate_link(qhT *qh, facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
    3747       28810 :   int errmirror= False;
    3748             : 
    3749       28810 :   if (oldfacetA == oldfacetB) {
    3750       28810 :     trace3((qh, qh->ferr, 3052, "qh_triangulate_link: relink neighbors f%d and f%d of null facet f%d\n",
    3751             :       facetA->id, facetB->id, oldfacetA->id));
    3752             :   }else {
    3753           0 :     trace3((qh, qh->ferr, 3021, "qh_triangulate_link: relink neighbors f%d and f%d of mirrored facets f%d and f%d\n",
    3754             :       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id));
    3755             :   }
    3756       28810 :   if (qh_setin(facetA->neighbors, facetB)) {
    3757           0 :     if (!qh_setin(facetB->neighbors, facetA))
    3758           0 :       errmirror= True;
    3759           0 :     else if (!facetA->redundant || !facetB->redundant || !qh_hasmerge(qh->degen_mergeset, MRGmirror, facetA, facetB))
    3760           0 :       qh_appendmergeset(qh, facetA, facetB, MRGmirror, 0.0, 1.0);
    3761       28810 :   }else if (qh_setin(facetB->neighbors, facetA))
    3762           0 :     errmirror= True;
    3763       28810 :   if (errmirror) {
    3764           0 :     qh_fprintf(qh, qh->ferr, 6163, "qhull internal error (qh_triangulate_link): neighbors f%d and f%d do not match for null facet or mirrored facets f%d and f%d\n",
    3765             :        facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
    3766           0 :     qh_errexit2(qh, qh_ERRqhull, facetA, facetB);
    3767             :   }
    3768       28810 :   qh_setreplace(qh, facetB->neighbors, oldfacetB, facetA);
    3769       28810 :   qh_setreplace(qh, facetA->neighbors, oldfacetA, facetB);
    3770       28810 : } /* triangulate_link */
    3771             : 
    3772             : /*-<a                             href="qh-poly_r.htm#TOC"
    3773             :   >-------------------------------</a><a name="triangulate_mirror">-</a>
    3774             : 
    3775             :   qh_triangulate_mirror(qh, facetA, facetB)
    3776             :     delete two mirrored facets identified by qh_triangulate_null() and itself
    3777             :       a mirrored facet shares the same vertices of a logical ridge
    3778             :   design:
    3779             :     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
    3780             :     if they are already neighbors, the opposing neighbors become MRGmirror facets
    3781             : */
    3782           0 : void qh_triangulate_mirror(qhT *qh, facetT *facetA, facetT *facetB) {
    3783             :   facetT *neighbor, *neighborB;
    3784             :   int neighbor_i, neighbor_n;
    3785             : 
    3786           0 :   trace3((qh, qh->ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d and link their neighbors\n",
    3787             :          facetA->id, facetB->id));
    3788           0 :   FOREACHneighbor_i_(qh, facetA) {
    3789           0 :     neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
    3790           0 :     if (neighbor == facetB && neighborB == facetA)
    3791           0 :       continue; /* occurs twice */
    3792           0 :     else if (neighbor->redundant && neighborB->redundant) { /* also mirrored facets (D5+) */
    3793           0 :       if (qh_hasmerge(qh->degen_mergeset, MRGmirror, neighbor, neighborB))
    3794           0 :         continue;
    3795             :     }
    3796           0 :     if (neighbor->visible && neighborB->visible) /* previously deleted as mirrored facets */
    3797           0 :       continue;
    3798           0 :     qh_triangulate_link(qh, facetA, neighbor, facetB, neighborB);
    3799             :   }
    3800           0 :   qh_willdelete(qh, facetA, NULL);
    3801           0 :   qh_willdelete(qh, facetB, NULL);
    3802           0 : } /* triangulate_mirror */
    3803             : 
    3804             : /*-<a                             href="qh-poly_r.htm#TOC"
    3805             :   >-------------------------------</a><a name="triangulate_null">-</a>
    3806             : 
    3807             :   qh_triangulate_null(qh, facetA)
    3808             :     remove null facetA from qh_triangulate_facet()
    3809             :       a null facet has vertex #1 (apex) == vertex #2
    3810             :   returns:
    3811             :     adds facetA to ->visible for deletion after qh_update_vertexneighbors
    3812             :     qh->degen_mergeset contains mirror facets (4-d and up only)
    3813             :   design:
    3814             :     since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
    3815             :     if they are already neighbors, the opposing neighbors will be merged (MRGmirror)
    3816             : */
    3817       28810 : void qh_triangulate_null(qhT *qh, facetT *facetA) {
    3818             :   facetT *neighbor, *otherfacet;
    3819             : 
    3820       28810 :   trace3((qh, qh->ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
    3821       28810 :   neighbor= SETfirstt_(facetA->neighbors, facetT);
    3822       28810 :   otherfacet= SETsecondt_(facetA->neighbors, facetT);
    3823       28810 :   qh_triangulate_link(qh, facetA, neighbor, facetA, otherfacet);
    3824       28810 :   qh_willdelete(qh, facetA, NULL);
    3825       28810 : } /* triangulate_null */
    3826             : 
    3827             : #else /* qh_NOmerge */
    3828             : void qh_triangulate(qhT *qh) {
    3829             :   QHULL_UNUSED(qh)
    3830             : }
    3831             : #endif /* qh_NOmerge */
    3832             : 
    3833             : /*-<a                             href="qh-poly_r.htm#TOC"
    3834             :   >-------------------------------</a><a name="vertexintersect">-</a>
    3835             : 
    3836             :   qh_vertexintersect(qh, verticesA, verticesB )
    3837             :     intersects two vertex sets (inverse id ordered)
    3838             :     vertexsetA is a temporary set at the top of qh->qhmem.tempstack
    3839             : 
    3840             :   returns:
    3841             :     replaces vertexsetA with the intersection
    3842             : 
    3843             :   notes:
    3844             :     only called by qh_neighbor_intersections
    3845             :     if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
    3846             :       cleaned by qh_remove_extravertices in qh_reduce_vertices
    3847             :     could optimize by overwriting vertexsetA
    3848             : */
    3849           0 : void qh_vertexintersect(qhT *qh, setT **vertexsetA, setT *vertexsetB) {
    3850             :   setT *intersection;
    3851             : 
    3852           0 :   intersection= qh_vertexintersect_new(qh, *vertexsetA, vertexsetB);
    3853           0 :   qh_settempfree(qh, vertexsetA);
    3854           0 :   *vertexsetA= intersection;
    3855           0 :   qh_settemppush(qh, intersection);
    3856           0 : } /* vertexintersect */
    3857             : 
    3858             : /*-<a                             href="qh-poly_r.htm#TOC"
    3859             :   >-------------------------------</a><a name="vertexintersect_new">-</a>
    3860             : 
    3861             :   qh_vertexintersect_new(qh, verticesA, verticesB )
    3862             :     intersects two vertex sets (inverse id ordered)
    3863             : 
    3864             :   returns:
    3865             :     a new set
    3866             : 
    3867             :   notes:
    3868             :     called by qh_checkfacet, qh_vertexintersect, qh_rename_sharedvertex, qh_findbest_pinchedvertex, qh_neighbor_intersections
    3869             :     if !qh.QHULLfinished, non-simplicial facets may have f.vertices with extraneous vertices
    3870             :        cleaned by qh_remove_extravertices in qh_reduce_vertices
    3871             : */
    3872           0 : setT *qh_vertexintersect_new(qhT *qh, setT *vertexsetA, setT *vertexsetB) {
    3873           0 :   setT *intersection= qh_setnew(qh, qh->hull_dim - 1);
    3874           0 :   vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
    3875           0 :   vertexT **vertexB= SETaddr_(vertexsetB, vertexT);
    3876             : 
    3877           0 :   while (*vertexA && *vertexB) {
    3878           0 :     if (*vertexA  == *vertexB) {
    3879           0 :       qh_setappend(qh, &intersection, *vertexA);
    3880           0 :       vertexA++; vertexB++;
    3881             :     }else {
    3882           0 :       if ((*vertexA)->id > (*vertexB)->id)
    3883           0 :         vertexA++;
    3884             :       else
    3885           0 :         vertexB++;
    3886             :     }
    3887             :   }
    3888           0 :   return intersection;
    3889             : } /* vertexintersect_new */
    3890             : 
    3891             : /*-<a                             href="qh-poly_r.htm#TOC"
    3892             :   >-------------------------------</a><a name="vertexneighbors">-</a>
    3893             : 
    3894             :   qh_vertexneighbors(qh)
    3895             :     for each vertex in qh.facet_list,
    3896             :       determine its neighboring facets
    3897             : 
    3898             :   returns:
    3899             :     sets qh.VERTEXneighbors
    3900             :       nop if qh.VERTEXneighbors already set
    3901             :       qh_addpoint() will maintain them
    3902             : 
    3903             :   notes:
    3904             :     assumes all vertex->neighbors are NULL
    3905             : 
    3906             :   design:
    3907             :     for each facet
    3908             :       for each vertex
    3909             :         append facet to vertex->neighbors
    3910             : */
    3911           3 : void qh_vertexneighbors(qhT *qh /* qh.facet_list */) {
    3912             :   facetT *facet;
    3913             :   vertexT *vertex, **vertexp;
    3914             : 
    3915           3 :   if (qh->VERTEXneighbors)
    3916           0 :     return;
    3917           3 :   trace1((qh, qh->ferr, 1035, "qh_vertexneighbors: determining neighboring facets for each vertex\n"));
    3918           3 :   qh->vertex_visit++;
    3919          41 :   FORALLfacets {
    3920          38 :     if (facet->visible)
    3921           6 :       continue;
    3922         128 :     FOREACHvertex_(facet->vertices) {
    3923          96 :       if (vertex->visitid != qh->vertex_visit) {
    3924          22 :         vertex->visitid= qh->vertex_visit;
    3925          22 :         vertex->neighbors= qh_setnew(qh, qh->hull_dim);
    3926             :       }
    3927          96 :       qh_setappend(qh, &vertex->neighbors, facet);
    3928             :     }
    3929             :   }
    3930           3 :   qh->VERTEXneighbors= True;
    3931             : } /* vertexneighbors */
    3932             : 
    3933             : /*-<a                             href="qh-poly_r.htm#TOC"
    3934             :   >-------------------------------</a><a name="vertexsubset">-</a>
    3935             : 
    3936             :   qh_vertexsubset( vertexsetA, vertexsetB )
    3937             :     returns True if vertexsetA is a subset of vertexsetB
    3938             :     assumes vertexsets are sorted
    3939             : 
    3940             :   note:
    3941             :     empty set is a subset of any other set
    3942             : */
    3943           0 : boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
    3944           0 :   vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
    3945           0 :   vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
    3946             : 
    3947             :   while (True) {
    3948           0 :     if (!*vertexA)
    3949           0 :       return True;
    3950           0 :     if (!*vertexB)
    3951           0 :       return False;
    3952           0 :     if ((*vertexA)->id > (*vertexB)->id)
    3953           0 :       return False;
    3954           0 :     if (*vertexA  == *vertexB)
    3955           0 :       vertexA++;
    3956           0 :     vertexB++;
    3957             :   }
    3958             :   return False; /* avoid warnings */
    3959             : } /* vertexsubset */

Generated by: LCOV version 1.14