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