poly2_r.c 155 KB

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