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

Generated by: LCOV version 1.14