LCOV - code coverage report
Current view: top level - alg/internal_libqhull - geom_r.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 284 581 48.9 %
Date: 2024-05-01 14:25:35 Functions: 12 16 75.0 %

          Line data    Source code
       1             : /*<html><pre>  -<a                             href="qh-geom_r.htm"
       2             :   >-------------------------------</a><a name="TOP">-</a>
       3             : 
       4             :    geom_r.c
       5             :    geometric routines of qhull
       6             : 
       7             :    see qh-geom_r.htm and geom_r.h
       8             : 
       9             :    Copyright (c) 1993-2020 The Geometry Center.
      10             :    $Id: //main/2019/qhull/src/libqhull_r/geom_r.c#5 $$Change: 2953 $
      11             :    $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
      12             : 
      13             :    infrequent code goes into geom2_r.c
      14             : */
      15             : 
      16             : #include "qhull_ra.h"
      17             : 
      18             : /*-<a                             href="qh-geom_r.htm#TOC"
      19             :   >-------------------------------</a><a name="distplane">-</a>
      20             : 
      21             :   qh_distplane(qh, point, facet, dist )
      22             :     return distance from point to facet
      23             : 
      24             :   returns:
      25             :     dist
      26             :     if qh.RANDOMdist, joggles result
      27             : 
      28             :   notes:
      29             :     dist > 0 if point is above facet (i.e., outside)
      30             :     does not error (for qh_sortfacets, qh_outerinner)
      31             :     for nearly coplanar points, the returned values may be duplicates
      32             :       for example pairs of nearly incident points, rbox 175 C1,2e-13 t1538759579 | qhull d T4
      33             :       622 qh_distplane: e-014  # count of two or more duplicate values for unique calls
      34             :       258 qh_distplane: e-015
      35             :       38 qh_distplane: e-016
      36             :       40 qh_distplane: e-017
      37             :       6 qh_distplane: e-018
      38             :       5 qh_distplane: -e-018
      39             :       33 qh_distplane: -e-017
      40             :          3153 qh_distplane: -2.775557561562891e-017  # duplicated value for 3153 unique calls
      41             :       42 qh_distplane: -e-016
      42             :       307 qh_distplane: -e-015
      43             :       1271 qh_distplane: -e-014
      44             :       13 qh_distplane: -e-013
      45             : 
      46             :   see:
      47             :     qh_distnorm in geom2_r.c
      48             :     qh_distplane [geom_r.c], QhullFacet::distance, and QhullHyperplane::distance are copies
      49             : */
      50     1324710 : void qh_distplane(qhT *qh, pointT *point, facetT *facet, realT *dist) {
      51     1324710 :   coordT *normal= facet->normal, *coordp, randr;
      52             :   int k;
      53             : 
      54     1324710 :   switch (qh->hull_dim){
      55           0 :   case 2:
      56           0 :     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
      57           0 :     break;
      58     1324710 :   case 3:
      59     1324710 :     *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
      60     1324710 :     break;
      61           0 :   case 4:
      62           0 :     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
      63           0 :     break;
      64           0 :   case 5:
      65           0 :     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
      66           0 :     break;
      67           0 :   case 6:
      68           0 :     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
      69           0 :     break;
      70           0 :   case 7:
      71           0 :     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
      72           0 :     break;
      73           0 :   case 8:
      74           0 :     *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
      75           0 :     break;
      76           0 :   default:
      77           0 :     *dist= facet->offset;
      78           0 :     coordp= point;
      79           0 :     for (k=qh->hull_dim; k--; )
      80           0 :       *dist += *coordp++ * *normal++;
      81           0 :     break;
      82             :   }
      83     1324710 :   zzinc_(Zdistplane);
      84     1324710 :   if (!qh->RANDOMdist && qh->IStracing < 4)
      85     1324710 :     return;
      86           0 :   if (qh->RANDOMdist) {
      87           0 :     randr= qh_RANDOMint;
      88           0 :     *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
      89           0 :       qh->RANDOMfactor * qh->MAXabs_coord;
      90             :   }
      91             : #ifndef qh_NOtrace
      92           0 :   if (qh->IStracing >= 4) {
      93           0 :     qh_fprintf(qh, qh->ferr, 8001, "qh_distplane: ");
      94           0 :     qh_fprintf(qh, qh->ferr, 8002, qh_REAL_1, *dist);
      95           0 :     qh_fprintf(qh, qh->ferr, 8003, "from p%d to f%d\n", qh_pointid(qh, point), facet->id);
      96             :   }
      97             : #endif
      98           0 :   return;
      99             : } /* distplane */
     100             : 
     101             : 
     102             : /*-<a                             href="qh-geom_r.htm#TOC"
     103             :   >-------------------------------</a><a name="findbest">-</a>
     104             : 
     105             :   qh_findbest(qh, point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
     106             :     find facet that is furthest below a point
     107             :     for upperDelaunay facets
     108             :       returns facet only if !qh_NOupper and clearly above
     109             : 
     110             :   input:
     111             :     starts search at 'startfacet' (can not be flipped)
     112             :     if !bestoutside(qh_ALL), stops at qh.MINoutside
     113             : 
     114             :   returns:
     115             :     best facet (reports error if NULL)
     116             :     early out if isoutside defined and bestdist > qh.MINoutside
     117             :     dist is distance to facet
     118             :     isoutside is true if point is outside of facet
     119             :     numpart counts the number of distance tests
     120             : 
     121             :   see also:
     122             :     qh_findbestnew()
     123             : 
     124             :   notes:
     125             :     If merging (testhorizon), searches horizon facets of coplanar best facets because
     126             :     after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
     127             :       avoid calls to distplane, function calls, and real number operations.
     128             :     caller traces result
     129             :     Optimized for outside points.   Tried recording a search set for qh_findhorizon.
     130             :     Made code more complicated.
     131             : 
     132             :   when called by qh_partitionvisible():
     133             :     indicated by qh_ISnewfacets
     134             :     qh.newfacet_list is list of simplicial, new facets
     135             :     qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
     136             :     qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
     137             : 
     138             :   when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(),
     139             :                  qh_check_bestdist(), qh_addpoint()
     140             :     indicated by !qh_ISnewfacets
     141             :     returns best facet in neighborhood of given facet
     142             :       this is best facet overall if dist >= -qh.MAXcoplanar
     143             :         or hull has at least a "spherical" curvature
     144             : 
     145             :   design:
     146             :     initialize and test for early exit
     147             :     repeat while there are better facets
     148             :       for each neighbor of facet
     149             :         exit if outside facet found
     150             :         test for better facet
     151             :     if point is inside and partitioning
     152             :       test for new facets with a "sharp" intersection
     153             :       if so, future calls go to qh_findbestnew()
     154             :     test horizon facets
     155             : */
     156       23311 : facetT *qh_findbest(qhT *qh, pointT *point, facetT *startfacet,
     157             :                      boolT bestoutside, boolT isnewfacets, boolT noupper,
     158             :                      realT *dist, boolT *isoutside, int *numpart) {
     159       23311 :   realT bestdist= -REALmax/2 /* avoid underflow */;
     160             :   facetT *facet, *neighbor, **neighborp;
     161       23311 :   facetT *bestfacet= NULL, *lastfacet= NULL;
     162       23311 :   int oldtrace= qh->IStracing;
     163       23311 :   unsigned int visitid= ++qh->visit_id;
     164       23311 :   int numpartnew=0;
     165       23311 :   boolT testhorizon= True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
     166             : 
     167       23311 :   zinc_(Zfindbest);
     168             : #ifndef qh_NOtrace
     169       23311 :   if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
     170           0 :     if (qh->TRACElevel > qh->IStracing)
     171           0 :       qh->IStracing= qh->TRACElevel;
     172           0 :     qh_fprintf(qh, qh->ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g,",
     173             :              qh_pointid(qh, point), startfacet->id, isnewfacets, bestoutside, qh->MINoutside);
     174           0 :     qh_fprintf(qh, qh->ferr, 8005, " testhorizon? %d, noupper? %d,", testhorizon, noupper);
     175           0 :     qh_fprintf(qh, qh->ferr, 8006, " Last qh_addpoint p%d,", qh->furthest_id);
     176           0 :     qh_fprintf(qh, qh->ferr, 8007, " Last merge #%d, max_outside %2.2g\n", zzval_(Ztotmerge), qh->max_outside);
     177             :   }
     178             : #endif
     179       23311 :   if (isoutside)
     180       23311 :     *isoutside= True;
     181       23311 :   if (!startfacet->flipped) {  /* test startfacet before testing its neighbors */
     182       23311 :     *numpart= 1;
     183       23311 :     qh_distplane(qh, point, startfacet, dist);  /* this code is duplicated below */
     184       23311 :     if (!bestoutside && *dist >= qh->MINoutside
     185       10386 :     && (!startfacet->upperdelaunay || !noupper)) {
     186       10386 :       bestfacet= startfacet;
     187       10386 :       goto LABELreturn_best;
     188             :     }
     189       12925 :     bestdist= *dist;
     190       12925 :     if (!startfacet->upperdelaunay) {
     191       12920 :       bestfacet= startfacet;
     192             :     }
     193             :   }else
     194           0 :     *numpart= 0;
     195       12925 :   startfacet->visitid= visitid;
     196       12925 :   facet= startfacet;
     197       16772 :   while (facet) {
     198       16769 :     trace4((qh, qh->ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n",
     199             :                 facet->id, bestdist, getid_(bestfacet)));
     200       16769 :     lastfacet= facet;
     201       38719 :     FOREACHneighbor_(facet) {
     202       38716 :       if (!neighbor->newfacet && isnewfacets)
     203       16767 :         continue;
     204       21949 :       if (neighbor->visitid == visitid)
     205        1173 :         continue;
     206       20776 :       neighbor->visitid= visitid;
     207       20776 :       if (!neighbor->flipped) {  /* code duplicated above */
     208       20776 :         (*numpart)++;
     209       20776 :         qh_distplane(qh, point, neighbor, dist);
     210       20776 :         if (*dist > bestdist) {
     211       16825 :           if (!bestoutside && *dist >= qh->MINoutside
     212       12922 :           && (!neighbor->upperdelaunay || !noupper)) {
     213       12922 :             bestfacet= neighbor;
     214       12922 :             goto LABELreturn_best;
     215             :           }
     216        3903 :           if (!neighbor->upperdelaunay) {
     217        3843 :             bestfacet= neighbor;
     218        3843 :             bestdist= *dist;
     219        3843 :             break; /* switch to neighbor */
     220          60 :           }else if (!bestfacet) {
     221           1 :             bestdist= *dist;
     222           1 :             break; /* switch to neighbor */
     223             :           }
     224             :         } /* end of *dist>bestdist */
     225             :       } /* end of !flipped */
     226             :     } /* end of FOREACHneighbor */
     227        3847 :     facet= neighbor;  /* non-NULL only if *dist>bestdist */
     228             :   } /* end of while facet (directed search) */
     229           3 :   if (isnewfacets) {
     230           1 :     if (!bestfacet) { /* startfacet is upperdelaunay (or flipped) w/o !flipped newfacet neighbors */
     231           0 :       bestdist= -REALmax/2;
     232           0 :       bestfacet= qh_findbestnew(qh, point, qh->newfacet_list, &bestdist, bestoutside, isoutside, &numpartnew);
     233           0 :       testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
     234           1 :     }else if (!qh->findbest_notsharp && bestdist < -qh->DISTround) {
     235           0 :       if (qh_sharpnewfacets(qh)) {
     236             :         /* seldom used, qh_findbestnew will retest all facets */
     237           0 :         zinc_(Zfindnewsharp);
     238           0 :         bestfacet= qh_findbestnew(qh, point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
     239           0 :         testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
     240           0 :         qh->findbestnew= True;
     241             :       }else
     242           0 :         qh->findbest_notsharp= True;
     243             :     }
     244             :   }
     245           3 :   if (!bestfacet)
     246           0 :     bestfacet= qh_findbestlower(qh, lastfacet, point, &bestdist, numpart); /* lastfacet is non-NULL because startfacet is non-NULL */
     247           3 :   if (testhorizon) /* qh_findbestnew not called */
     248           3 :     bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
     249           3 :   *dist= bestdist;
     250           3 :   if (isoutside && bestdist < qh->MINoutside)
     251           3 :     *isoutside= False;
     252           0 : LABELreturn_best:
     253       23311 :   zadd_(Zfindbesttot, *numpart);
     254       23311 :   zmax_(Zfindbestmax, *numpart);
     255       23311 :   (*numpart) += numpartnew;
     256       23311 :   qh->IStracing= oldtrace;
     257       23311 :   return bestfacet;
     258             : }  /* findbest */
     259             : 
     260             : 
     261             : /*-<a                             href="qh-geom_r.htm#TOC"
     262             :   >-------------------------------</a><a name="findbesthorizon">-</a>
     263             : 
     264             :   qh_findbesthorizon(qh, qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
     265             :     search coplanar and better horizon facets from startfacet/bestdist
     266             :     ischeckmax turns off statistics and minsearch update
     267             :     all arguments must be initialized, including *bestdist and *numpart
     268             :     qh.coplanarfacetset used to maintain current search set, reset whenever best facet is substantially better
     269             :   returns(ischeckmax):
     270             :     best facet
     271             :     updates f.maxoutside for neighbors of searched facets (if qh_MAXoutside)
     272             :   returns(!ischeckmax):
     273             :     best facet that is not upperdelaunay or newfacet (qh.first_newfacet)
     274             :     allows upperdelaunay that is clearly outside
     275             :   returns:
     276             :     bestdist is distance to bestfacet
     277             :     numpart -- updates number of distance tests
     278             : 
     279             :   notes:
     280             :     called by qh_findbest if point is not outside a facet (directed search)
     281             :     called by qh_findbestnew if point is not outside a new facet
     282             :     called by qh_check_maxout for each point in hull
     283             :     called by qh_check_bestdist for each point in hull (rarely used)
     284             : 
     285             :     no early out -- use qh_findbest() or qh_findbestnew()
     286             :     Searches coplanar or better horizon facets
     287             : 
     288             :   when called by qh_check_maxout() (qh_IScheckmax)
     289             :     startfacet must be closest to the point
     290             :       Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
     291             :       even though other facets are below the point.
     292             :     updates facet->maxoutside for good, visited facets
     293             :     may return NULL
     294             : 
     295             :     searchdist is qh.max_outside + 2 * DISTround
     296             :       + max( MINvisible('Vn'), MAXcoplanar('Un'));
     297             :     This setting is a guess.  It must be at least max_outside + 2*DISTround
     298             :     because a facet may have a geometric neighbor across a vertex
     299             : 
     300             :   design:
     301             :     for each horizon facet of coplanar best facets
     302             :       continue if clearly inside
     303             :       unless upperdelaunay or clearly outside
     304             :          update best facet
     305             : */
     306       14677 : facetT *qh_findbesthorizon(qhT *qh, boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
     307       14677 :   facetT *bestfacet= startfacet;
     308             :   realT dist;
     309             :   facetT *neighbor, **neighborp, *facet;
     310       14677 :   facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */
     311       14677 :   int numpartinit= *numpart, coplanarfacetset_size, numcoplanar= 0, numfacet= 0;
     312       14677 :   unsigned int visitid= ++qh->visit_id;
     313       14677 :   boolT newbest= False; /* for tracing */
     314             :   realT minsearch, searchdist;  /* skip facets that are too far from point */
     315             :   boolT is_5x_minsearch;
     316             : 
     317       14677 :   if (!ischeckmax) {
     318           4 :     zinc_(Zfindhorizon);
     319             :   }else {
     320             : #if qh_MAXoutside
     321       14673 :     if ((!qh->ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
     322           0 :       startfacet->maxoutside= *bestdist;
     323             : #endif
     324             :   }
     325       14677 :   searchdist= qh_SEARCHdist; /* an expression, a multiple of qh.max_outside and precision constants */
     326       14677 :   minsearch= *bestdist - searchdist;
     327       14677 :   if (ischeckmax) {
     328             :     /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
     329       14673 :     minimize_(minsearch, -searchdist);
     330             :   }
     331       14677 :   coplanarfacetset_size= 0;
     332       14677 :   startfacet->visitid= visitid;
     333       14677 :   facet= startfacet;
     334             :   while (True) {
     335       58266 :     numfacet++;
     336       58266 :     is_5x_minsearch= (ischeckmax && facet->nummerge > 10 && qh_setsize(qh, facet->neighbors) > 100);  /* QH11033 FIX: qh_findbesthorizon: many tests for facets with many merges and neighbors.  Can hide coplanar facets, e.g., 'rbox 1000 s Z1 G1e-13' with 4400+ neighbors */
     337       58266 :     trace4((qh, qh->ferr, 4002, "qh_findbesthorizon: test neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g is_5x? %d searchdist %2.2g\n",
     338             :                 facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
     339             :                 minsearch, is_5x_minsearch, searchdist));
     340      347782 :     FOREACHneighbor_(facet) {
     341      289516 :       if (neighbor->visitid == visitid)
     342       74378 :         continue;
     343      215138 :       neighbor->visitid= visitid;
     344      215138 :       if (!neighbor->flipped) {  /* neighbors of flipped facets always searched via nextfacet */
     345      215138 :         qh_distplane(qh, point, neighbor, &dist); /* duplicate qh_distpane for new facets, they may be coplanar */
     346      215138 :         (*numpart)++;
     347      215138 :         if (dist > *bestdist) {
     348       15948 :           if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh->MINoutside)) {
     349       15946 :             if (!ischeckmax) {
     350           0 :               minsearch= dist - searchdist;
     351           0 :               if (dist > *bestdist + searchdist) {
     352           0 :                 zinc_(Zfindjump);  /* everything in qh.coplanarfacetset at least searchdist below */
     353           0 :                 coplanarfacetset_size= 0;
     354             :               }
     355             :             }
     356       15946 :             bestfacet= neighbor;
     357       15946 :             *bestdist= dist;
     358       15946 :             newbest= True;
     359             :           }
     360      199190 :         }else if (is_5x_minsearch) {
     361       56807 :           if (dist < 5 * minsearch)
     362       56783 :             continue; /* skip this neighbor, do not set nextfacet.  dist is negative */
     363      142383 :         }else if (dist < minsearch)
     364      114766 :           continue;  /* skip this neighbor, do not set nextfacet.  If ischeckmax, dist can't be positive */
     365             : #if qh_MAXoutside
     366       43589 :         if (ischeckmax && dist > neighbor->maxoutside)
     367           0 :           neighbor->maxoutside= dist;
     368             : #endif
     369             :       } /* end of !flipped, need to search neighbor */
     370       43589 :       if (nextfacet) {
     371       14678 :         numcoplanar++;
     372       14678 :         if (!coplanarfacetset_size++) {
     373       14677 :           SETfirst_(qh->coplanarfacetset)= nextfacet;
     374       14677 :           SETtruncate_(qh->coplanarfacetset, 1);
     375             :         }else
     376           1 :           qh_setappend(qh, &qh->coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
     377             :                                                  and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
     378             :       }
     379       43589 :       nextfacet= neighbor;
     380             :     } /* end of EACHneighbor */
     381       58266 :     facet= nextfacet;
     382       58266 :     if (facet)
     383       28911 :       nextfacet= NULL;
     384       29355 :     else if (!coplanarfacetset_size)
     385       14677 :       break;
     386       14678 :     else if (!--coplanarfacetset_size) {
     387       14677 :       facet= SETfirstt_(qh->coplanarfacetset, facetT);
     388       14677 :       SETtruncate_(qh->coplanarfacetset, 0);
     389             :     }else
     390           1 :       facet= (facetT *)qh_setdellast(qh->coplanarfacetset);
     391             :   } /* while True, i.e., "for each facet in qh.coplanarfacetset" */
     392       14677 :   if (!ischeckmax) {
     393           4 :     zadd_(Zfindhorizontot, *numpart - numpartinit);
     394           4 :     zmax_(Zfindhorizonmax, *numpart - numpartinit);
     395           4 :     if (newbest)
     396           0 :       zinc_(Znewbesthorizon);
     397             :   }
     398       14677 :   trace4((qh, qh->ferr, 4003, "qh_findbesthorizon: p%d, newbest? %d, bestfacet f%d, bestdist %2.2g, numfacet %d, coplanarfacets %d, numdist %d\n",
     399             :     qh_pointid(qh, point), newbest, getid_(bestfacet), *bestdist, numfacet, numcoplanar, *numpart - numpartinit));
     400       14677 :   return bestfacet;
     401             : }  /* findbesthorizon */
     402             : 
     403             : /*-<a                             href="qh-geom_r.htm#TOC"
     404             :   >-------------------------------</a><a name="findbestnew">-</a>
     405             : 
     406             :   qh_findbestnew(qh, point, startfacet, dist, isoutside, numpart )
     407             :     find best newfacet for point
     408             :     searches all of qh.newfacet_list starting at startfacet
     409             :     searches horizon facets of coplanar best newfacets
     410             :     searches all facets if startfacet == qh.facet_list
     411             :   returns:
     412             :     best new or horizon facet that is not upperdelaunay
     413             :     early out if isoutside and not 'Qf'
     414             :     dist is distance to facet
     415             :     isoutside is true if point is outside of facet
     416             :     numpart is number of distance tests
     417             : 
     418             :   notes:
     419             :     Always used for merged new facets (see qh_USEfindbestnew)
     420             :     Avoids upperdelaunay facet unless (isoutside and outside)
     421             : 
     422             :     Uses qh.visit_id, qh.coplanarfacetset.
     423             :     If share visit_id with qh_findbest, coplanarfacetset is incorrect.
     424             : 
     425             :     If merging (testhorizon), searches horizon facets of coplanar best facets because
     426             :     a point maybe coplanar to the bestfacet, below its horizon facet,
     427             :     and above a horizon facet of a coplanar newfacet.  For example,
     428             :       rbox 1000 s Z1 G1e-13 | qhull
     429             :       rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
     430             : 
     431             :     qh_findbestnew() used if
     432             :        qh_sharpnewfacets -- newfacets contains a sharp angle
     433             :        if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
     434             : 
     435             :   see also:
     436             :     qh_partitionall() and qh_findbest()
     437             : 
     438             :   design:
     439             :     for each new facet starting from startfacet
     440             :       test distance from point to facet
     441             :       return facet if clearly outside
     442             :       unless upperdelaunay and a lowerdelaunay exists
     443             :          update best facet
     444             :     test horizon facets
     445             : */
     446      184783 : facetT *qh_findbestnew(qhT *qh, pointT *point, facetT *startfacet,
     447             :            realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
     448      184783 :   realT bestdist= -REALmax/2;
     449      184783 :   facetT *bestfacet= NULL, *facet;
     450      184783 :   int oldtrace= qh->IStracing, i;
     451      184783 :   unsigned int visitid= ++qh->visit_id;
     452      184783 :   realT distoutside= 0.0;
     453             :   boolT isdistoutside; /* True if distoutside is defined */
     454             :   /* boolT testhorizon= True; */ /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
     455             : 
     456      184783 :   if (!startfacet || !startfacet->next) {
     457           0 :     if (qh->MERGING) {
     458           0 :       qh_fprintf(qh, qh->ferr, 6001, "qhull topology error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
     459           0 :       qh_errexit(qh, qh_ERRtopology, NULL, NULL);
     460             :     }else {
     461           0 :       qh_fprintf(qh, qh->ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
     462             :               qh->furthest_id);
     463           0 :       qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     464             :     }
     465             :   }
     466      184783 :   zinc_(Zfindnew);
     467      184783 :   if (qh->BESToutside || bestoutside)
     468           1 :     isdistoutside= False;
     469             :   else {
     470      184782 :     isdistoutside= True;
     471      184782 :     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
     472             :   }
     473      184783 :   if (isoutside)
     474      184783 :     *isoutside= True;
     475      184783 :   *numpart= 0;
     476             : #ifndef qh_NOtrace
     477      184783 :   if (qh->IStracing >= 4 || (qh->TRACElevel && qh->TRACEpoint >= 0 && qh->TRACEpoint == qh_pointid(qh, point))) {
     478           0 :     if (qh->TRACElevel > qh->IStracing)
     479           0 :       qh->IStracing= qh->TRACElevel;
     480           0 :     qh_fprintf(qh, qh->ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g,",
     481             :              qh_pointid(qh, point), startfacet->id, isdistoutside, distoutside);
     482           0 :     qh_fprintf(qh, qh->ferr, 8009, " Last qh_addpoint p%d, qh.visit_id %d, vertex_visit %d,",  qh->furthest_id, visitid, qh->vertex_visit);
     483           0 :     qh_fprintf(qh, qh->ferr, 8010, " Last merge #%d\n", zzval_(Ztotmerge));
     484             :   }
     485             : #endif
     486             :   /* visit all new facets starting with startfacet, maybe qh->facet_list */
     487      214807 :   for (i=0, facet=startfacet; i < 2; i++, facet= qh->newfacet_list) {
     488      413958 :     FORALLfacet_(facet) {
     489      383935 :       if (facet == startfacet && i)
     490           1 :         break;
     491      383934 :       facet->visitid= visitid;
     492      383934 :       if (!facet->flipped) {
     493      383934 :         qh_distplane(qh, point, facet, dist);
     494      383934 :         (*numpart)++;
     495      383934 :         if (*dist > bestdist) {
     496      321428 :           if (!facet->upperdelaunay || *dist >= qh->MINoutside) {
     497      316692 :             bestfacet= facet;
     498      316692 :             if (isdistoutside && *dist >= distoutside)
     499      184782 :               goto LABELreturn_bestnew;
     500      131910 :             bestdist= *dist;
     501             :           }
     502             :         }
     503             :       } /* end of !flipped */
     504             :     } /* FORALLfacet from startfacet or qh->newfacet_list */
     505             :   }
     506             :   /* if (testhorizon || !bestfacet) */ /* testhorizon is always True.  Keep the same code as qh_findbest */
     507           1 :   bestfacet= qh_findbesthorizon(qh, !qh_IScheckmax, point, bestfacet ? bestfacet : startfacet,
     508             :                                         !qh_NOupper, &bestdist, numpart);
     509           1 :   *dist= bestdist;
     510           1 :   if (isoutside && *dist < qh->MINoutside)
     511           1 :     *isoutside= False;
     512           0 : LABELreturn_bestnew:
     513      184783 :   zadd_(Zfindnewtot, *numpart);
     514      184783 :   zmax_(Zfindnewmax, *numpart);
     515      184783 :   trace4((qh, qh->ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g for p%d f%d bestoutside? %d \n",
     516             :     getid_(bestfacet), *dist, qh_pointid(qh, point), startfacet->id, bestoutside));
     517      184783 :   qh->IStracing= oldtrace;
     518      184783 :   return bestfacet;
     519             : }  /* findbestnew */
     520             : 
     521             : /* ============ hyperplane functions -- keep code together [?] ============ */
     522             : 
     523             : /*-<a                             href="qh-geom_r.htm#TOC"
     524             :   >-------------------------------</a><a name="backnormal">-</a>
     525             : 
     526             :   qh_backnormal(qh, rows, numrow, numcol, sign, normal, nearzero )
     527             :     given an upper-triangular rows array and a sign,
     528             :     solve for normal equation x using back substitution over rows U
     529             : 
     530             :   returns:
     531             :      normal= x
     532             : 
     533             :      if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2),
     534             :        if fails on last row
     535             :          this means that the hyperplane intersects [0,..,1]
     536             :          sets last coordinate of normal to sign
     537             :        otherwise
     538             :          sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
     539             :          sets nearzero
     540             : 
     541             :   notes:
     542             :      assumes numrow == numcol-1
     543             : 
     544             :      see Golub & van Loan, 1983, Eq. 4.4-9 for "Gaussian elimination with complete pivoting"
     545             : 
     546             :      solves Ux=b where Ax=b and PA=LU
     547             :      b= [0,...,0,sign or 0]  (sign is either -1 or +1)
     548             :      last row of A= [0,...,0,1]
     549             : 
     550             :      1) Ly=Pb == y=b since P only permutes the 0's of   b
     551             : 
     552             :   design:
     553             :     for each row from end
     554             :       perform back substitution
     555             :       if near zero
     556             :         use qh_divzero for division
     557             :         if zero divide and not last row
     558             :           set tail of normal to 0
     559             : */
     560           0 : void qh_backnormal(qhT *qh, realT **rows, int numrow, int numcol, boolT sign,
     561             :         coordT *normal, boolT *nearzero) {
     562             :   int i, j;
     563             :   coordT *normalp, *normal_tail, *ai, *ak;
     564             :   realT diagonal;
     565             :   boolT waszero;
     566           0 :   int zerocol= -1;
     567             : 
     568           0 :   normalp= normal + numcol - 1;
     569           0 :   *normalp--= (sign ? -1.0 : 1.0);
     570           0 :   for (i=numrow; i--; ) {
     571           0 :     *normalp= 0.0;
     572           0 :     ai= rows[i] + i + 1;
     573           0 :     ak= normalp+1;
     574           0 :     for (j=i+1; j < numcol; j++)
     575           0 :       *normalp -= *ai++ * *ak++;
     576           0 :     diagonal= (rows[i])[i];
     577           0 :     if (fabs_(diagonal) > qh->MINdenom_2)
     578           0 :       *(normalp--) /= diagonal;
     579             :     else {
     580           0 :       waszero= False;
     581           0 :       *normalp= qh_divzero(*normalp, diagonal, qh->MINdenom_1_2, &waszero);
     582           0 :       if (waszero) {
     583           0 :         zerocol= i;
     584           0 :         *(normalp--)= (sign ? -1.0 : 1.0);
     585           0 :         for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
     586           0 :           *normal_tail= 0.0;
     587             :       }else
     588           0 :         normalp--;
     589             :     }
     590             :   }
     591           0 :   if (zerocol != -1) {
     592           0 :     *nearzero= True;
     593           0 :     trace4((qh, qh->ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i));
     594           0 :     zzinc_(Zback0);
     595           0 :     qh_joggle_restart(qh, "zero diagonal on back substitution");
     596             :   }
     597           0 : } /* backnormal */
     598             : 
     599             : /*-<a                             href="qh-geom_r.htm#TOC"
     600             :   >-------------------------------</a><a name="gausselim">-</a>
     601             : 
     602             :   qh_gausselim(qh, rows, numrow, numcol, sign )
     603             :     Gaussian elimination with partial pivoting
     604             : 
     605             :   returns:
     606             :     rows is upper triangular (includes row exchanges)
     607             :     flips sign for each row exchange
     608             :     sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
     609             : 
     610             :   notes:
     611             :     if nearzero, the determinant's sign may be incorrect.
     612             :     assumes numrow <= numcol
     613             : 
     614             :   design:
     615             :     for each row
     616             :       determine pivot and exchange rows if necessary
     617             :       test for near zero
     618             :       perform gaussian elimination step
     619             : */
     620           0 : void qh_gausselim(qhT *qh, realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
     621             :   realT *ai, *ak, *rowp, *pivotrow;
     622           0 :   realT n, pivot, pivot_abs= 0.0, temp;
     623           0 :   int i, j, k, pivoti, flip=0;
     624             : 
     625           0 :   *nearzero= False;
     626           0 :   for (k=0; k < numrow; k++) {
     627           0 :     pivot_abs= fabs_((rows[k])[k]);
     628           0 :     pivoti= k;
     629           0 :     for (i=k+1; i < numrow; i++) {
     630           0 :       if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
     631           0 :         pivot_abs= temp;
     632           0 :         pivoti= i;
     633             :       }
     634             :     }
     635           0 :     if (pivoti != k) {
     636           0 :       rowp= rows[pivoti];
     637           0 :       rows[pivoti]= rows[k];
     638           0 :       rows[k]= rowp;
     639           0 :       *sign ^= 1;
     640           0 :       flip ^= 1;
     641             :     }
     642           0 :     if (pivot_abs <= qh->NEARzero[k]) {
     643           0 :       *nearzero= True;
     644           0 :       if (pivot_abs == 0.0) {   /* remainder of column == 0 */
     645             : #ifndef qh_NOtrace
     646           0 :         if (qh->IStracing >= 4) {
     647           0 :           qh_fprintf(qh, qh->ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh->DISTround);
     648           0 :           qh_printmatrix(qh, qh->ferr, "Matrix:", rows, numrow, numcol);
     649             :         }
     650             : #endif
     651           0 :         zzinc_(Zgauss0);
     652           0 :         qh_joggle_restart(qh, "zero pivot for Gaussian elimination");
     653           0 :         goto LABELnextcol;
     654             :       }
     655             :     }
     656           0 :     pivotrow= rows[k] + k;
     657           0 :     pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
     658           0 :     for (i=k+1; i < numrow; i++) {
     659           0 :       ai= rows[i] + k;
     660           0 :       ak= pivotrow;
     661           0 :       n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
     662           0 :       for (j= numcol - (k+1); j--; )
     663           0 :         *ai++ -= n * *ak++;
     664             :     }
     665           0 :   LABELnextcol:
     666             :     ;
     667             :   }
     668           0 :   wmin_(Wmindenom, pivot_abs);  /* last pivot element */
     669           0 :   if (qh->IStracing >= 5)
     670           0 :     qh_printmatrix(qh, qh->ferr, "qh_gausselem: result", rows, numrow, numcol);
     671           0 : } /* gausselim */
     672             : 
     673             : 
     674             : /*-<a                             href="qh-geom_r.htm#TOC"
     675             :   >-------------------------------</a><a name="getangle">-</a>
     676             : 
     677             :   qh_getangle(qh, vect1, vect2 )
     678             :     returns the dot product of two vectors
     679             :     if qh.RANDOMdist, joggles result
     680             : 
     681             :   notes:
     682             :     the angle may be > 1.0 or < -1.0 because of roundoff errors
     683             : 
     684             : */
     685          36 : realT qh_getangle(qhT *qh, pointT *vect1, pointT *vect2) {
     686          36 :   realT angle= 0, randr;
     687             :   int k;
     688             : 
     689         144 :   for (k=qh->hull_dim; k--; )
     690         108 :     angle += *vect1++ * *vect2++;
     691          36 :   if (qh->RANDOMdist) {
     692           0 :     randr= qh_RANDOMint;
     693           0 :     angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
     694           0 :       qh->RANDOMfactor;
     695             :   }
     696          36 :   trace4((qh, qh->ferr, 4006, "qh_getangle: %4.4g\n", angle));
     697          36 :   return(angle);
     698             : } /* getangle */
     699             : 
     700             : 
     701             : /*-<a                             href="qh-geom_r.htm#TOC"
     702             :   >-------------------------------</a><a name="getcenter">-</a>
     703             : 
     704             :   qh_getcenter(qh, vertices )
     705             :     returns arithmetic center of a set of vertices as a new point
     706             : 
     707             :   notes:
     708             :     allocates point array for center
     709             : */
     710       65920 : pointT *qh_getcenter(qhT *qh, setT *vertices) {
     711             :   int k;
     712             :   pointT *center, *coord;
     713             :   vertexT *vertex, **vertexp;
     714       65920 :   int count= qh_setsize(qh, vertices);
     715             : 
     716       65920 :   if (count < 2) {
     717           0 :     qh_fprintf(qh, qh->ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
     718           0 :     qh_errexit(qh, qh_ERRqhull, NULL, NULL);
     719             :   }
     720       65920 :   center= (pointT *)qh_memalloc(qh, qh->normal_size);
     721      263680 :   for (k=0; k < qh->hull_dim; k++) {
     722      197760 :     coord= center+k;
     723      197760 :     *coord= 0.0;
     724      851778 :     FOREACHvertex_(vertices)
     725      654018 :       *coord += vertex->point[k];
     726      197760 :     *coord /= count;  /* count>=2 by QH6003 */
     727             :   }
     728       65920 :   return(center);
     729             : } /* getcenter */
     730             : 
     731             : 
     732             : /*-<a                             href="qh-geom_r.htm#TOC"
     733             :   >-------------------------------</a><a name="getcentrum">-</a>
     734             : 
     735             :   qh_getcentrum(qh, facet )
     736             :     returns the centrum for a facet as a new point
     737             : 
     738             :   notes:
     739             :     allocates the centrum
     740             : */
     741       65916 : pointT *qh_getcentrum(qhT *qh, facetT *facet) {
     742             :   realT dist;
     743             :   pointT *centrum, *point;
     744             : 
     745       65916 :   point= qh_getcenter(qh, facet->vertices);
     746       65916 :   zzinc_(Zcentrumtests);
     747       65916 :   qh_distplane(qh, point, facet, &dist);
     748       65916 :   centrum= qh_projectpoint(qh, point, facet, dist);
     749       65916 :   qh_memfree(qh, point, qh->normal_size);
     750       65916 :   trace4((qh, qh->ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
     751             :           facet->id, qh_setsize(qh, facet->vertices), dist));
     752       65916 :   return centrum;
     753             : } /* getcentrum */
     754             : 
     755             : 
     756             : /*-<a                             href="qh-geom_r.htm#TOC"
     757             :   >-------------------------------</a><a name="getdistance">-</a>
     758             : 
     759             :   qh_getdistance(qh, facet, neighbor, mindist, maxdist )
     760             :     returns the min and max distance to neighbor of non-neighbor vertices in facet
     761             : 
     762             :   returns:
     763             :     the max absolute value
     764             : 
     765             :   design:
     766             :     for each vertex of facet that is not in neighbor
     767             :       test the distance from vertex to neighbor
     768             : */
     769           6 : coordT qh_getdistance(qhT *qh, facetT *facet, facetT *neighbor, coordT *mindist, coordT *maxdist) {
     770             :   vertexT *vertex, **vertexp;
     771             :   coordT dist, maxd, mind;
     772             : 
     773          24 :   FOREACHvertex_(facet->vertices)
     774          18 :     vertex->seen= False;
     775          24 :   FOREACHvertex_(neighbor->vertices)
     776          18 :     vertex->seen= True;
     777           6 :   mind= 0.0;
     778           6 :   maxd= 0.0;
     779          24 :   FOREACHvertex_(facet->vertices) {
     780          18 :     if (!vertex->seen) {
     781           6 :       zzinc_(Zbestdist);
     782           6 :       qh_distplane(qh, vertex->point, neighbor, &dist);
     783           6 :       if (dist < mind)
     784           6 :         mind= dist;
     785           0 :       else if (dist > maxd)
     786           0 :         maxd= dist;
     787             :     }
     788             :   }
     789           6 :   *mindist= mind;
     790           6 :   *maxdist= maxd;
     791           6 :   mind= -mind;
     792           6 :   if (maxd > mind)
     793           0 :     return maxd;
     794             :   else
     795           6 :     return mind;
     796             : } /* getdistance */
     797             : 
     798             : 
     799             : /*-<a                             href="qh-geom_r.htm#TOC"
     800             :   >-------------------------------</a><a name="normalize">-</a>
     801             : 
     802             :   qh_normalize(qh, normal, dim, toporient )
     803             :     normalize a vector and report if too small
     804             :     does not use min norm
     805             : 
     806             :   see:
     807             :     qh_normalize2
     808             : */
     809           0 : void qh_normalize(qhT *qh, coordT *normal, int dim, boolT toporient) {
     810           0 :   qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
     811           0 : } /* normalize */
     812             : 
     813             : /*-<a                             href="qh-geom_r.htm#TOC"
     814             :   >-------------------------------</a><a name="normalize2">-</a>
     815             : 
     816             :   qh_normalize2(qh, normal, dim, toporient, minnorm, ismin )
     817             :     normalize a vector and report if too small
     818             :     qh.MINdenom/MINdenom1 are the upper limits for divide overflow
     819             : 
     820             :   returns:
     821             :     normalized vector
     822             :     flips sign if !toporient
     823             :     if minnorm non-NULL,
     824             :       sets ismin if normal < minnorm
     825             : 
     826             :   notes:
     827             :     if zero norm
     828             :        sets all elements to sqrt(1.0/dim)
     829             :     if divide by zero (divzero())
     830             :        sets largest element to   +/-1
     831             :        bumps Znearlysingular
     832             : 
     833             :   design:
     834             :     computes norm
     835             :     test for minnorm
     836             :     if not near zero
     837             :       normalizes normal
     838             :     else if zero norm
     839             :       sets normal to standard value
     840             :     else
     841             :       uses qh_divzero to normalize
     842             :       if nearzero
     843             :         sets norm to direction of maximum value
     844             : */
     845       53373 : void qh_normalize2(qhT *qh, coordT *normal, int dim, boolT toporient,
     846             :             realT *minnorm, boolT *ismin) {
     847             :   int k;
     848       53373 :   realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
     849             :   boolT zerodiv;
     850             : 
     851       53373 :   norm1= normal+1;
     852       53373 :   norm2= normal+2;
     853       53373 :   norm3= normal+3;
     854       53373 :   if (dim == 2)
     855           0 :     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
     856       53373 :   else if (dim == 3)
     857       53373 :     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
     858           0 :   else if (dim == 4) {
     859           0 :     norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
     860           0 :                + (*norm3)*(*norm3));
     861           0 :   }else if (dim > 4) {
     862           0 :     norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
     863           0 :                + (*norm3)*(*norm3);
     864           0 :     for (k=dim-4, colp=normal+4; k--; colp++)
     865           0 :       norm += (*colp) * (*colp);
     866           0 :     norm= sqrt(norm);
     867             :   }
     868       53373 :   if (minnorm) {
     869           0 :     if (norm < *minnorm)
     870           0 :       *ismin= True;
     871             :     else
     872           0 :       *ismin= False;
     873             :   }
     874       53373 :   wmin_(Wmindenom, norm);
     875       53373 :   if (norm > qh->MINdenom) {
     876       53373 :     if (!toporient)
     877       26649 :       norm= -norm;
     878       53373 :     *normal /= norm;
     879       53373 :     *norm1 /= norm;
     880       53373 :     if (dim == 2)
     881             :       ; /* all done */
     882       53373 :     else if (dim == 3)
     883       53373 :       *norm2 /= norm;
     884           0 :     else if (dim == 4) {
     885           0 :       *norm2 /= norm;
     886           0 :       *norm3 /= norm;
     887           0 :     }else if (dim >4) {
     888           0 :       *norm2 /= norm;
     889           0 :       *norm3 /= norm;
     890           0 :       for (k=dim-4, colp=normal+4; k--; )
     891           0 :         *colp++ /= norm;
     892             :     }
     893           0 :   }else if (norm == 0.0) {
     894           0 :     temp= sqrt(1.0/dim);
     895           0 :     for (k=dim, colp=normal; k--; )
     896           0 :       *colp++= temp;
     897             :   }else {
     898           0 :     if (!toporient)
     899           0 :       norm= -norm;
     900           0 :     for (k=dim, colp=normal; k--; colp++) { /* k used below */
     901           0 :       temp= qh_divzero(*colp, norm, qh->MINdenom_1, &zerodiv);
     902           0 :       if (!zerodiv)
     903           0 :         *colp= temp;
     904             :       else {
     905           0 :         maxp= qh_maxabsval(normal, dim);
     906           0 :         temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
     907           0 :         for (k=dim, colp=normal; k--; colp++)
     908           0 :           *colp= 0.0;
     909           0 :         *maxp= temp;
     910           0 :         zzinc_(Znearlysingular);
     911             :         /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
     912           0 :         trace0((qh, qh->ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n",
     913             :                norm, qh->furthest_id));
     914           0 :         return;
     915             :       }
     916             :     }
     917             :   }
     918             : } /* normalize */
     919             : 
     920             : 
     921             : /*-<a                             href="qh-geom_r.htm#TOC"
     922             :   >-------------------------------</a><a name="projectpoint">-</a>
     923             : 
     924             :   qh_projectpoint(qh, point, facet, dist )
     925             :     project point onto a facet by dist
     926             : 
     927             :   returns:
     928             :     returns a new point
     929             : 
     930             :   notes:
     931             :     if dist= distplane(point,facet)
     932             :       this projects point to hyperplane
     933             :     assumes qh_memfree_() is valid for normal_size
     934             : */
     935       65916 : pointT *qh_projectpoint(qhT *qh, pointT *point, facetT *facet, realT dist) {
     936             :   pointT *newpoint, *np, *normal;
     937       65916 :   int normsize= qh->normal_size;
     938             :   int k;
     939             :   void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
     940             : 
     941       65916 :   qh_memalloc_(qh, normsize, freelistp, newpoint, pointT);
     942       65916 :   np= newpoint;
     943       65916 :   normal= facet->normal;
     944      263664 :   for (k=qh->hull_dim; k--; )
     945      197748 :     *(np++)= *point++ - dist * *normal++;
     946       65916 :   return(newpoint);
     947             : } /* projectpoint */
     948             : 
     949             : 
     950             : /*-<a                             href="qh-geom_r.htm#TOC"
     951             :   >-------------------------------</a><a name="setfacetplane">-</a>
     952             : 
     953             :   qh_setfacetplane(qh, facet )
     954             :     sets the hyperplane for a facet
     955             :     if qh.RANDOMdist, joggles hyperplane
     956             : 
     957             :   notes:
     958             :     uses global buffers qh.gm_matrix and qh.gm_row
     959             :     overwrites facet->normal if already defined
     960             :     updates Wnewvertex if PRINTstatistics
     961             :     sets facet->upperdelaunay if upper envelope of Delaunay triangulation
     962             : 
     963             :   design:
     964             :     copy vertex coordinates to qh.gm_matrix/gm_row
     965             :     compute determinate
     966             :     if nearzero
     967             :       recompute determinate with gaussian elimination
     968             :       if nearzero
     969             :         force outside orientation by testing interior point
     970             : */
     971       53373 : void qh_setfacetplane(qhT *qh, facetT *facet) {
     972             :   pointT *point;
     973             :   vertexT *vertex, **vertexp;
     974       53373 :   int normsize= qh->normal_size;
     975       53373 :   int k,i, oldtrace= 0;
     976             :   realT dist;
     977             :   void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
     978             :   coordT *coord, *gmcoord;
     979       53373 :   pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
     980       53373 :   boolT nearzero= False;
     981             : 
     982       53373 :   zzinc_(Zsetplane);
     983       53373 :   if (!facet->normal)
     984       53373 :     qh_memalloc_(qh, normsize, freelistp, facet->normal, coordT);
     985             : #ifndef qh_NOtrace
     986       53373 :   if (facet == qh->tracefacet) {
     987           0 :     oldtrace= qh->IStracing;
     988           0 :     qh->IStracing= 5;
     989           0 :     qh_fprintf(qh, qh->ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id);
     990           0 :     qh_fprintf(qh, qh->ferr, 8013, "  Last point added to hull was p%d.", qh->furthest_id);
     991           0 :     if (zzval_(Ztotmerge))
     992           0 :       qh_fprintf(qh, qh->ferr, 8014, "  Last merge was #%d.", zzval_(Ztotmerge));
     993           0 :     qh_fprintf(qh, qh->ferr, 8015, "\n\nCurrent summary is:\n");
     994           0 :       qh_printsummary(qh, qh->ferr);
     995             :   }
     996             : #endif
     997       53373 :   if (qh->hull_dim <= 4) {
     998       53373 :     i= 0;
     999       53373 :     if (qh->RANDOMdist) {
    1000           0 :       gmcoord= qh->gm_matrix;
    1001           0 :       FOREACHvertex_(facet->vertices) {
    1002           0 :         qh->gm_row[i++]= gmcoord;
    1003           0 :         coord= vertex->point;
    1004           0 :         for (k=qh->hull_dim; k--; )
    1005           0 :           *(gmcoord++)= *coord++ * qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
    1006             :       }
    1007             :     }else {
    1008      213492 :       FOREACHvertex_(facet->vertices)
    1009      160119 :        qh->gm_row[i++]= vertex->point;
    1010             :     }
    1011       53373 :     qh_sethyperplane_det(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
    1012             :                 facet->normal, &facet->offset, &nearzero);
    1013             :   }
    1014       53373 :   if (qh->hull_dim > 4 || nearzero) {
    1015           0 :     i= 0;
    1016           0 :     gmcoord= qh->gm_matrix;
    1017           0 :     FOREACHvertex_(facet->vertices) {
    1018           0 :       if (vertex->point != point0) {
    1019           0 :         qh->gm_row[i++]= gmcoord;
    1020           0 :         coord= vertex->point;
    1021           0 :         point= point0;
    1022           0 :         for (k=qh->hull_dim; k--; )
    1023           0 :           *(gmcoord++)= *coord++ - *point++;
    1024             :       }
    1025             :     }
    1026           0 :     qh->gm_row[i]= gmcoord;  /* for areasimplex */
    1027           0 :     if (qh->RANDOMdist) {
    1028           0 :       gmcoord= qh->gm_matrix;
    1029           0 :       for (i=qh->hull_dim-1; i--; ) {
    1030           0 :         for (k=qh->hull_dim; k--; )
    1031           0 :           *(gmcoord++) *= qh_randomfactor(qh, qh->RANDOMa, qh->RANDOMb);
    1032             :       }
    1033             :     }
    1034           0 :     qh_sethyperplane_gauss(qh, qh->hull_dim, qh->gm_row, point0, facet->toporient,
    1035             :                 facet->normal, &facet->offset, &nearzero);
    1036           0 :     if (nearzero) {
    1037           0 :       if (qh_orientoutside(qh, facet)) {
    1038           0 :         trace0((qh, qh->ferr, 2, "qh_setfacetplane: flipped orientation due to nearzero gauss and interior_point test.  During p%d\n", qh->furthest_id));
    1039             :       /* this is part of using Gaussian Elimination.  For example in 5-d
    1040             :            1 1 1 1 0
    1041             :            1 1 1 1 1
    1042             :            0 0 0 1 0
    1043             :            0 1 0 0 0
    1044             :            1 0 0 0 0
    1045             :            norm= 0.38 0.38 -0.76 0.38 0
    1046             :          has a determinate of 1, but g.e. after subtracting pt. 0 has
    1047             :          0's in the diagonal, even with full pivoting.  It does work
    1048             :          if you subtract pt. 4 instead. */
    1049             :       }
    1050             :     }
    1051             :   }
    1052       53373 :   facet->upperdelaunay= False;
    1053       53373 :   if (qh->DELAUNAY) {
    1054       53373 :     if (qh->UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
    1055           0 :       if (facet->normal[qh->hull_dim -1] >= qh->ANGLEround * qh_ZEROdelaunay)
    1056           0 :         facet->upperdelaunay= True;
    1057             :     }else {
    1058       53373 :       if (facet->normal[qh->hull_dim -1] > -qh->ANGLEround * qh_ZEROdelaunay)
    1059          52 :         facet->upperdelaunay= True;
    1060             :     }
    1061             :   }
    1062       53373 :   if (qh->PRINTstatistics || qh->IStracing || qh->TRACElevel || qh->JOGGLEmax < REALmax) {
    1063           0 :     qh->old_randomdist= qh->RANDOMdist;
    1064           0 :     qh->RANDOMdist= False;
    1065           0 :     FOREACHvertex_(facet->vertices) {
    1066           0 :       if (vertex->point != point0) {
    1067           0 :         boolT istrace= False;
    1068           0 :         zinc_(Zdiststat);
    1069           0 :         qh_distplane(qh, vertex->point, facet, &dist);
    1070           0 :         dist= fabs_(dist);
    1071           0 :         zinc_(Znewvertex);
    1072           0 :         wadd_(Wnewvertex, dist);
    1073           0 :         if (dist > wwval_(Wnewvertexmax)) {
    1074           0 :           wwval_(Wnewvertexmax)= dist;
    1075           0 :           if (dist > qh->max_outside) {
    1076           0 :             qh->max_outside= dist;  /* used by qh_maxouter(qh) */
    1077           0 :             if (dist > qh->TRACEdist)
    1078           0 :               istrace= True;
    1079             :           }
    1080           0 :         }else if (-dist > qh->TRACEdist)
    1081           0 :           istrace= True;
    1082           0 :         if (istrace) {
    1083           0 :           qh_fprintf(qh, qh->ferr, 3060, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
    1084             :                 qh_pointid(qh, vertex->point), vertex->id, dist, facet->id, qh->furthest_id);
    1085           0 :           qh_errprint(qh, "DISTANT", facet, NULL, NULL, NULL);
    1086             :         }
    1087             :       }
    1088             :     }
    1089           0 :     qh->RANDOMdist= qh->old_randomdist;
    1090             :   }
    1091             : #ifndef qh_NOtrace
    1092       53373 :   if (qh->IStracing >= 4) {
    1093           0 :     qh_fprintf(qh, qh->ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ",
    1094             :              facet->id, facet->offset);
    1095           0 :     for (k=0; k < qh->hull_dim; k++)
    1096           0 :       qh_fprintf(qh, qh->ferr, 8018, "%2.2g ", facet->normal[k]);
    1097           0 :     qh_fprintf(qh, qh->ferr, 8019, "\n");
    1098             :   }
    1099             : #endif
    1100       53373 :   qh_checkflipped(qh, facet, NULL, qh_ALL);
    1101       53373 :   if (facet == qh->tracefacet) {
    1102           0 :     qh->IStracing= oldtrace;
    1103           0 :     qh_printfacet(qh, qh->ferr, facet);
    1104             :   }
    1105       53373 : } /* setfacetplane */
    1106             : 
    1107             : 
    1108             : /*-<a                             href="qh-geom_r.htm#TOC"
    1109             :   >-------------------------------</a><a name="sethyperplane_det">-</a>
    1110             : 
    1111             :   qh_sethyperplane_det(qh, dim, rows, point0, toporient, normal, offset, nearzero )
    1112             :     given dim X dim array indexed by rows[], one row per point,
    1113             :         toporient(flips all signs),
    1114             :         and point0 (any row)
    1115             :     set normalized hyperplane equation from oriented simplex
    1116             : 
    1117             :   returns:
    1118             :     normal (normalized)
    1119             :     offset (places point0 on the hyperplane)
    1120             :     sets nearzero if hyperplane not through points
    1121             : 
    1122             :   notes:
    1123             :     only defined for dim == 2..4
    1124             :     rows[] is not modified
    1125             :     solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
    1126             :     see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
    1127             : 
    1128             :   derivation of 3-d minnorm
    1129             :     Goal: all vertices V_i within qh.one_merge of hyperplane
    1130             :     Plan: exactly translate the facet so that V_0 is the origin
    1131             :           exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
    1132             :           exactly rotate the effective perturbation to only effect n_0
    1133             :              this introduces a factor of sqrt(3)
    1134             :     n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
    1135             :     Let M_d be the max coordinate difference
    1136             :     Let M_a be the greater of M_d and the max abs. coordinate
    1137             :     Let u be machine roundoff and distround be max error for distance computation
    1138             :     The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
    1139             :     The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
    1140             :     Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
    1141             :     Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
    1142             : 
    1143             :   derivation of 4-d minnorm
    1144             :     same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
    1145             :      [if two vertices fixed on x-axis, can rotate the other two in yzw.]
    1146             :     n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
    1147             :      [all other terms contain at least two factors nearly zero.]
    1148             :     The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
    1149             :     Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
    1150             :     Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
    1151             : */
    1152       53373 : void qh_sethyperplane_det(qhT *qh, int dim, coordT **rows, coordT *point0,
    1153             :           boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
    1154             :   realT maxround, dist;
    1155             :   int i;
    1156             :   pointT *point;
    1157             : 
    1158             : 
    1159       53373 :   if (dim == 2) {
    1160           0 :     normal[0]= dY(1,0);
    1161           0 :     normal[1]= dX(0,1);
    1162           0 :     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    1163           0 :     *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
    1164           0 :     *nearzero= False;  /* since nearzero norm => incident points */
    1165       53373 :   }else if (dim == 3) {
    1166       53373 :     normal[0]= det2_(dY(2,0), dZ(2,0),
    1167             :                      dY(1,0), dZ(1,0));
    1168       53373 :     normal[1]= det2_(dX(1,0), dZ(1,0),
    1169             :                      dX(2,0), dZ(2,0));
    1170       53373 :     normal[2]= det2_(dX(2,0), dY(2,0),
    1171             :                      dX(1,0), dY(1,0));
    1172       53373 :     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    1173       53373 :     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
    1174       53373 :                + point0[2]*normal[2]);
    1175       53373 :     maxround= qh->DISTround;
    1176      213492 :     for (i=dim; i--; ) {
    1177      160119 :       point= rows[i];
    1178      160119 :       if (point != point0) {
    1179      106746 :         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
    1180      106746 :                + point[2]*normal[2]);
    1181      106746 :         if (dist > maxround || dist < -maxround) {
    1182           0 :           *nearzero= True;
    1183           0 :           break;
    1184             :         }
    1185             :       }
    1186             :     }
    1187           0 :   }else if (dim == 4) {
    1188           0 :     normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
    1189             :                         dY(1,0), dZ(1,0), dW(1,0),
    1190             :                         dY(3,0), dZ(3,0), dW(3,0));
    1191           0 :     normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
    1192             :                         dX(1,0), dZ(1,0), dW(1,0),
    1193             :                         dX(3,0), dZ(3,0), dW(3,0));
    1194           0 :     normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
    1195             :                         dX(1,0), dY(1,0), dW(1,0),
    1196             :                         dX(3,0), dY(3,0), dW(3,0));
    1197           0 :     normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
    1198             :                         dX(1,0), dY(1,0), dZ(1,0),
    1199             :                         dX(3,0), dY(3,0), dZ(3,0));
    1200           0 :     qh_normalize2(qh, normal, dim, toporient, NULL, NULL);
    1201           0 :     *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
    1202           0 :                + point0[2]*normal[2] + point0[3]*normal[3]);
    1203           0 :     maxround= qh->DISTround;
    1204           0 :     for (i=dim; i--; ) {
    1205           0 :       point= rows[i];
    1206           0 :       if (point != point0) {
    1207           0 :         dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
    1208           0 :                + point[2]*normal[2] + point[3]*normal[3]);
    1209           0 :         if (dist > maxround || dist < -maxround) {
    1210           0 :           *nearzero= True;
    1211           0 :           break;
    1212             :         }
    1213             :       }
    1214             :     }
    1215             :   }
    1216       53373 :   if (*nearzero) {
    1217           0 :     zzinc_(Zminnorm);
    1218             :     /* qh_joggle_restart not needed, will call qh_sethyperplane_gauss instead */
    1219           0 :     trace0((qh, qh->ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d, use qh_sethyperplane_gauss instead.\n", qh->furthest_id));
    1220             :   }
    1221       53373 : } /* sethyperplane_det */
    1222             : 
    1223             : 
    1224             : /*-<a                             href="qh-geom_r.htm#TOC"
    1225             :   >-------------------------------</a><a name="sethyperplane_gauss">-</a>
    1226             : 
    1227             :   qh_sethyperplane_gauss(qh, dim, rows, point0, toporient, normal, offset, nearzero )
    1228             :     given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
    1229             :     set normalized hyperplane equation from oriented simplex
    1230             : 
    1231             :   returns:
    1232             :     normal (normalized)
    1233             :     offset (places point0 on the hyperplane)
    1234             : 
    1235             :   notes:
    1236             :     if nearzero
    1237             :       orientation may be incorrect because of incorrect sign flips in gausselim
    1238             :     solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
    1239             :         or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
    1240             :     i.e., N is normal to the hyperplane, and the unnormalized
    1241             :         distance to [0 .. 1] is either 1 or   0
    1242             : 
    1243             :   design:
    1244             :     perform gaussian elimination
    1245             :     flip sign for negative values
    1246             :     perform back substitution
    1247             :     normalize result
    1248             :     compute offset
    1249             : */
    1250           0 : void qh_sethyperplane_gauss(qhT *qh, int dim, coordT **rows, pointT *point0,
    1251             :                 boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
    1252             :   coordT *pointcoord, *normalcoef;
    1253             :   int k;
    1254           0 :   boolT sign= toporient, nearzero2= False;
    1255             : 
    1256           0 :   qh_gausselim(qh, rows, dim-1, dim, &sign, nearzero);
    1257           0 :   for (k=dim-1; k--; ) {
    1258           0 :     if ((rows[k])[k] < 0)
    1259           0 :       sign ^= 1;
    1260             :   }
    1261           0 :   if (*nearzero) {
    1262           0 :     zzinc_(Znearlysingular);
    1263             :     /* qh_joggle_restart ignored for Znearlysingular, normal part of qh_sethyperplane_gauss */
    1264           0 :     trace0((qh, qh->ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh->furthest_id));
    1265           0 :     qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
    1266             :   }else {
    1267           0 :     qh_backnormal(qh, rows, dim-1, dim, sign, normal, &nearzero2);
    1268           0 :     if (nearzero2) {
    1269           0 :       zzinc_(Znearlysingular);
    1270           0 :       trace0((qh, qh->ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh->furthest_id));
    1271             :     }
    1272             :   }
    1273           0 :   if (nearzero2)
    1274           0 :     *nearzero= True;
    1275           0 :   qh_normalize2(qh, normal, dim, True, NULL, NULL);
    1276           0 :   pointcoord= point0;
    1277           0 :   normalcoef= normal;
    1278           0 :   *offset= -(*pointcoord++ * *normalcoef++);
    1279           0 :   for (k=dim-1; k--; )
    1280           0 :     *offset -= *pointcoord++ * *normalcoef++;
    1281           0 : } /* sethyperplane_gauss */
    1282             : 
    1283             : 
    1284             : 

Generated by: LCOV version 1.14