geom_r.c 45 KB

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