merge_r.c 215 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590
  1. /*<html><pre> -<a href="qh-merge_r.htm#TOC"
  2. >-------------------------------</a><a name="TOP">-</a>
  3. merge_r.c
  4. merges non-convex facets
  5. see qh-merge_r.htm and merge_r.h
  6. other modules call qh_premerge() and qh_postmerge()
  7. the user may call qh_postmerge() to perform additional merges.
  8. To remove deleted facets and vertices (qhull() in libqhull_r.c):
  9. qh_partitionvisible(qh, !qh_ALL, &numoutside); // visible_list, newfacet_list
  10. qh_deletevisible(); // qh.visible_list
  11. qh_resetlists(qh, False, qh_RESETvisible); // qh.visible_list newvertex_list newfacet_list
  12. assumes qh.CENTERtype= centrum
  13. merges occur in qh_mergefacet and in qh_mergecycle
  14. vertex->neighbors not set until the first merge occurs
  15. Copyright (c) 1993-2020 C.B. Barber.
  16. $Id: //main/2019/qhull/src/libqhull_r/merge_r.c#14 $$Change: 2953 $
  17. $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
  18. */
  19. #include "qhull_ra.h"
  20. #ifndef qh_NOmerge
  21. /* MRGnone, etc. */
  22. const char *mergetypes[]= {
  23. "none",
  24. "coplanar",
  25. "anglecoplanar",
  26. "concave",
  27. "concavecoplanar",
  28. "twisted",
  29. "flip",
  30. "dupridge",
  31. "subridge",
  32. "vertices",
  33. "degen",
  34. "redundant",
  35. "mirror",
  36. "coplanarhorizon",
  37. };
  38. /*===== functions(alphabetical after premerge and postmerge) ======*/
  39. /*-<a href="qh-merge_r.htm#TOC"
  40. >-------------------------------</a><a name="premerge">-</a>
  41. qh_premerge(qh, apexpointid, maxcentrum )
  42. pre-merge nonconvex facets in qh.newfacet_list for apexpointid
  43. maxcentrum defines coplanar and concave (qh_test_appendmerge)
  44. returns:
  45. deleted facets added to qh.visible_list with facet->visible set
  46. notes:
  47. only called by qh_addpoint
  48. uses globals, qh.MERGEexact, qh.PREmerge
  49. design:
  50. mark dupridges in qh.newfacet_list
  51. merge facet cycles in qh.newfacet_list
  52. merge dupridges and concave facets in qh.newfacet_list
  53. check merged facet cycles for degenerate and redundant facets
  54. merge degenerate and redundant facets
  55. collect coplanar and concave facets
  56. merge concave, coplanar, degenerate, and redundant facets
  57. */
  58. void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle /* qh.newfacet_list */) {
  59. boolT othermerge= False;
  60. if (qh->ZEROcentrum && qh_checkzero(qh, !qh_ALL))
  61. return;
  62. trace2((qh, qh->ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %4.4g for apex p%d newfacet_list f%d\n",
  63. maxcentrum, maxangle, apexpointid, getid_(qh->newfacet_list)));
  64. if (qh->IStracing >= 4 && qh->num_facets < 100)
  65. qh_printlists(qh);
  66. qh->centrum_radius= maxcentrum;
  67. qh->cos_max= maxangle;
  68. if (qh->hull_dim >=3) {
  69. qh_mark_dupridges(qh, qh->newfacet_list, qh_ALL); /* facet_mergeset */
  70. qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
  71. qh_forcedmerges(qh, &othermerge /* qh.facet_mergeset */);
  72. }else /* qh.hull_dim == 2 */
  73. qh_mergecycle_all(qh, qh->newfacet_list, &othermerge);
  74. qh_flippedmerges(qh, qh->newfacet_list, &othermerge);
  75. if (!qh->MERGEexact || zzval_(Ztotmerge)) {
  76. zinc_(Zpremergetot);
  77. qh->POSTmerging= False;
  78. qh_getmergeset_initial(qh, qh->newfacet_list);
  79. qh_all_merges(qh, othermerge, False);
  80. }
  81. } /* premerge */
  82. /*-<a href="qh-merge_r.htm#TOC"
  83. >-------------------------------</a><a name="postmerge">-</a>
  84. qh_postmerge(qh, reason, maxcentrum, maxangle, vneighbors )
  85. post-merge nonconvex facets as defined by maxcentrum and maxangle
  86. 'reason' is for reporting progress
  87. if vneighbors ('Qv'),
  88. calls qh_test_vneighbors at end of qh_all_merge from qh_postmerge
  89. returns:
  90. if first call (qh.visible_list != qh.facet_list),
  91. builds qh.facet_newlist, qh.newvertex_list
  92. deleted facets added to qh.visible_list with facet->visible
  93. qh.visible_list == qh.facet_list
  94. notes:
  95. called by qh_qhull after qh_buildhull
  96. called if a merge may be needed due to
  97. qh.MERGEexact ('Qx'), qh_DIMreduceBuild, POSTmerge (e.g., 'Cn'), or TESTvneighbors ('Qv')
  98. if firstmerge,
  99. calls qh_reducevertices before qh_getmergeset
  100. design:
  101. if first call
  102. set qh.visible_list and qh.newfacet_list to qh.facet_list
  103. add all facets to qh.newfacet_list
  104. mark non-simplicial facets, facet->newmerge
  105. set qh.newvertext_list to qh.vertex_list
  106. add all vertices to qh.newvertex_list
  107. if a pre-merge occurred
  108. set vertex->delridge {will retest the ridge}
  109. if qh.MERGEexact
  110. call qh_reducevertices()
  111. if no pre-merging
  112. merge flipped facets
  113. determine non-convex facets
  114. merge all non-convex facets
  115. */
  116. void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
  117. boolT vneighbors) {
  118. facetT *newfacet;
  119. boolT othermerges= False;
  120. vertexT *vertex;
  121. if (qh->REPORTfreq || qh->IStracing) {
  122. qh_buildtracing(qh, NULL, NULL);
  123. qh_printsummary(qh, qh->ferr);
  124. if (qh->PRINTstatistics)
  125. qh_printallstatistics(qh, qh->ferr, "reason");
  126. qh_fprintf(qh, qh->ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n",
  127. reason, maxcentrum, maxangle);
  128. }
  129. trace2((qh, qh->ferr, 2009, "qh_postmerge: postmerge. test vneighbors? %d\n",
  130. vneighbors));
  131. qh->centrum_radius= maxcentrum;
  132. qh->cos_max= maxangle;
  133. qh->POSTmerging= True;
  134. if (qh->visible_list != qh->facet_list) { /* first call due to qh_buildhull, multiple calls if qh.POSTmerge */
  135. qh->NEWfacets= True;
  136. qh->visible_list= qh->newfacet_list= qh->facet_list;
  137. FORALLnew_facets { /* all facets are new facets for qh_postmerge */
  138. newfacet->newfacet= True;
  139. if (!newfacet->simplicial)
  140. newfacet->newmerge= True; /* test f.vertices for 'delridge'. 'newmerge' was cleared at end of qh_all_merges */
  141. zinc_(Zpostfacets);
  142. }
  143. qh->newvertex_list= qh->vertex_list;
  144. FORALLvertices
  145. vertex->newfacet= True;
  146. if (qh->VERTEXneighbors) { /* a merge has occurred */
  147. if (qh->MERGEexact && qh->hull_dim <= qh_DIMreduceBuild)
  148. qh_reducevertices(qh); /* qh_all_merges did not call qh_reducevertices for v.delridge */
  149. }
  150. if (!qh->PREmerge && !qh->MERGEexact)
  151. qh_flippedmerges(qh, qh->newfacet_list, &othermerges);
  152. }
  153. qh_getmergeset_initial(qh, qh->newfacet_list);
  154. qh_all_merges(qh, False, vneighbors); /* calls qh_reducevertices before exiting */
  155. FORALLnew_facets
  156. newfacet->newmerge= False; /* Was True if no vertex in f.vertices was 'delridge' */
  157. } /* post_merge */
  158. /*-<a href="qh-merge_r.htm#TOC"
  159. >-------------------------------</a><a name="all_merges">-</a>
  160. qh_all_merges(qh, othermerge, vneighbors )
  161. merge all non-convex facets
  162. set othermerge if already merged facets (calls qh_reducevertices)
  163. if vneighbors ('Qv' at qh.POSTmerge)
  164. tests vertex neighbors for convexity at end (qh_test_vneighbors)
  165. qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
  166. qh.degen_mergeset is defined
  167. if qh.MERGEexact && !qh.POSTmerging,
  168. does not merge coplanar facets
  169. returns:
  170. deleted facets added to qh.visible_list with facet->visible
  171. deleted vertices added qh.delvertex_list with vertex->delvertex
  172. notes:
  173. unless !qh.MERGEindependent,
  174. merges facets in independent sets
  175. uses qh.newfacet_list as implicit argument since merges call qh_removefacet()
  176. [apr'19] restored qh_setdellast in place of qh_next_facetmerge. Much faster for post-merge
  177. design:
  178. while merges occur
  179. for each merge in qh.facet_mergeset
  180. unless one of the facets was already merged in this pass
  181. merge the facets
  182. test merged facets for additional merges
  183. add merges to qh.facet_mergeset
  184. if qh.POSTmerging
  185. periodically call qh_reducevertices to reduce extra vertices and redundant vertices
  186. after each pass, if qh.VERTEXneighbors
  187. if qh.POSTmerging or was a merge with qh.hull_dim<=5
  188. call qh_reducevertices
  189. update qh.facet_mergeset if degenredundant merges
  190. if 'Qv' and qh.POSTmerging
  191. test vertex neighbors for convexity
  192. */
  193. void qh_all_merges(qhT *qh, boolT othermerge, boolT vneighbors) {
  194. facetT *facet1, *facet2, *newfacet;
  195. mergeT *merge;
  196. boolT wasmerge= False, isreduce;
  197. void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
  198. vertexT *vertex;
  199. realT angle, distance;
  200. mergeType mergetype;
  201. int numcoplanar=0, numconcave=0, numconcavecoplanar= 0, numdegenredun= 0, numnewmerges= 0, numtwisted= 0;
  202. trace2((qh, qh->ferr, 2010, "qh_all_merges: starting to merge %d facet and %d degenerate merges for new facets f%d, othermerge? %d\n",
  203. qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), getid_(qh->newfacet_list), othermerge));
  204. while (True) {
  205. wasmerge= False;
  206. while (qh_setsize(qh, qh->facet_mergeset) > 0 || qh_setsize(qh, qh->degen_mergeset) > 0) {
  207. if (qh_setsize(qh, qh->degen_mergeset) > 0) {
  208. numdegenredun += qh_merge_degenredundant(qh);
  209. wasmerge= True;
  210. }
  211. while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset))) {
  212. facet1= merge->facet1;
  213. facet2= merge->facet2;
  214. vertex= merge->vertex1; /* not used for qh.facet_mergeset*/
  215. mergetype= merge->mergetype;
  216. angle= merge->angle;
  217. distance= merge->distance;
  218. qh_memfree_(qh, merge, (int)sizeof(mergeT), freelistp); /* 'merge' is invalid */
  219. if (facet1->visible || facet2->visible) {
  220. trace3((qh, qh->ferr, 3045, "qh_all_merges: drop merge of f%d (del? %d) into f%d (del? %d) mergetype %d, dist %4.4g, angle %4.4g. One or both facets is deleted\n",
  221. facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
  222. continue;
  223. }else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar) {
  224. if (qh->MERGEindependent) {
  225. if ((!facet1->tested && facet1->newfacet)
  226. || (!facet2->tested && facet2->newfacet)) {
  227. trace3((qh, qh->ferr, 3064, "qh_all_merges: drop merge of f%d (tested? %d) into f%d (tested? %d) mergetype %d, dist %2.2g, angle %4.4g. Merge independent sets of coplanar merges\n",
  228. facet1->id, facet1->visible, facet2->id, facet2->visible, mergetype, distance, angle));
  229. continue;
  230. }
  231. }
  232. }
  233. trace3((qh, qh->ferr, 3047, "qh_all_merges: merge f%d and f%d type %d dist %2.2g angle %4.4g\n",
  234. facet1->id, facet2->id, mergetype, distance, angle));
  235. if (mergetype == MRGtwisted)
  236. qh_merge_twisted(qh, facet1, facet2);
  237. else
  238. qh_merge_nonconvex(qh, facet1, facet2, mergetype);
  239. numnewmerges++;
  240. numdegenredun += qh_merge_degenredundant(qh);
  241. wasmerge= True;
  242. if (mergetype == MRGconcave)
  243. numconcave++;
  244. else if (mergetype == MRGconcavecoplanar)
  245. numconcavecoplanar++;
  246. else if (mergetype == MRGtwisted)
  247. numtwisted++;
  248. else if (mergetype == MRGcoplanar || mergetype == MRGanglecoplanar)
  249. numcoplanar++;
  250. else {
  251. qh_fprintf(qh, qh->ferr, 6394, "qhull internal error (qh_all_merges): expecting concave, coplanar, or twisted merge. Got merge f%d f%d v%d mergetype %d\n",
  252. getid_(facet1), getid_(facet2), getid_(vertex), mergetype);
  253. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  254. }
  255. } /* while qh_setdellast */
  256. if (qh->POSTmerging && qh->hull_dim <= qh_DIMreduceBuild
  257. && numnewmerges > qh_MAXnewmerges) {
  258. numnewmerges= 0;
  259. wasmerge= othermerge= False;
  260. qh_reducevertices(qh); /* otherwise large post merges too slow */
  261. }
  262. qh_getmergeset(qh, qh->newfacet_list); /* qh.facet_mergeset */
  263. } /* while facet_mergeset or degen_mergeset */
  264. if (qh->VERTEXneighbors) { /* at least one merge */
  265. isreduce= False;
  266. if (qh->POSTmerging && qh->hull_dim >= 4) {
  267. isreduce= True;
  268. }else if (qh->POSTmerging || !qh->MERGEexact) {
  269. if ((wasmerge || othermerge) && qh->hull_dim > 2 && qh->hull_dim <= qh_DIMreduceBuild)
  270. isreduce= True;
  271. }
  272. if (isreduce) {
  273. wasmerge= othermerge= False;
  274. if (qh_reducevertices(qh)) {
  275. qh_getmergeset(qh, qh->newfacet_list); /* facet_mergeset */
  276. continue;
  277. }
  278. }
  279. }
  280. if (vneighbors && qh_test_vneighbors(qh /* qh.newfacet_list */))
  281. continue;
  282. break;
  283. } /* while (True) */
  284. if (wasmerge || othermerge) {
  285. trace3((qh, qh->ferr, 3033, "qh_all_merges: skip qh_reducevertices due to post-merging, no qh.VERTEXneighbors (%d), or hull_dim %d ==2 or >%d\n", qh->VERTEXneighbors, qh->hull_dim, qh_DIMreduceBuild))
  286. FORALLnew_facets {
  287. newfacet->newmerge= False;
  288. }
  289. }
  290. if (qh->CHECKfrequently && !qh->MERGEexact) {
  291. qh->old_randomdist= qh->RANDOMdist;
  292. qh->RANDOMdist= False;
  293. qh_checkconvex(qh, qh->newfacet_list, qh_ALGORITHMfault);
  294. /* qh_checkconnect(qh); [this is slow and it changes the facet order] */
  295. qh->RANDOMdist= qh->old_randomdist;
  296. }
  297. trace1((qh, qh->ferr, 1009, "qh_all_merges: merged %d coplanar %d concave %d concavecoplanar %d twisted facets and %d degen or redundant facets.\n",
  298. numcoplanar, numconcave, numconcavecoplanar, numtwisted, numdegenredun));
  299. if (qh->IStracing >= 4 && qh->num_facets < 500)
  300. qh_printlists(qh);
  301. } /* all_merges */
  302. /*-<a href="qh-merge_r.htm#TOC"
  303. >-------------------------------</a><a name="all_vertexmerges">-</a>
  304. qh_all_vertexmerges(qh, apexpointid, facet, &retryfacet )
  305. merge vertices in qh.vertex_mergeset and subsequent merges
  306. returns:
  307. returns retryfacet for facet (if defined)
  308. updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
  309. mergesets are empty
  310. if merges, resets facet lists
  311. notes:
  312. called from qh_qhull, qh_addpoint, and qh_buildcone_mergepinched
  313. vertex merges occur after facet merges and qh_resetlists
  314. design:
  315. while merges in vertex_mergeset (MRGvertices)
  316. merge a pair of pinched vertices
  317. update vertex neighbors
  318. merge non-convex and degenerate facets and check for ridges with duplicate vertices
  319. partition outside points of deleted, "visible" facets
  320. */
  321. void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
  322. int numpoints; /* ignore count of partitioned points. Used by qh_addpoint for Zpbalance */
  323. if (retryfacet)
  324. *retryfacet= facet;
  325. while (qh_setsize(qh, qh->vertex_mergeset) > 0) {
  326. trace1((qh, qh->ferr, 1057, "qh_all_vertexmerges: starting to merge %d vertex merges for apex p%d facet f%d\n",
  327. qh_setsize(qh, qh->vertex_mergeset), apexpointid, getid_(facet)));
  328. if (qh->IStracing >= 4 && qh->num_facets < 1000)
  329. qh_printlists(qh);
  330. qh_merge_pinchedvertices(qh, apexpointid /* qh.vertex_mergeset, visible_list, newvertex_list, newfacet_list */);
  331. qh_update_vertexneighbors(qh); /* update neighbors of qh.newvertex_list from qh_newvertices for deleted facets on qh.visible_list */
  332. /* test ridges and merge non-convex facets */
  333. qh_getmergeset(qh, qh->newfacet_list);
  334. qh_all_merges(qh, True, False); /* calls qh_reducevertices */
  335. if (qh->CHECKfrequently)
  336. qh_checkpolygon(qh, qh->facet_list);
  337. qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list qh.del_vertices*/);
  338. if (retryfacet)
  339. *retryfacet= qh_getreplacement(qh, *retryfacet);
  340. qh_deletevisible(qh /* qh.visible_list qh.del_vertices*/);
  341. qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
  342. if (qh->IStracing >= 4 && qh->num_facets < 1000) {
  343. qh_printlists(qh);
  344. qh_checkpolygon(qh, qh->facet_list);
  345. }
  346. }
  347. } /* all_vertexmerges */
  348. /*-<a href="qh-merge_r.htm#TOC"
  349. >-------------------------------</a><a name="appendmergeset">-</a>
  350. qh_appendmergeset(qh, facet, vertex, neighbor, mergetype, dist, angle )
  351. appends an entry to qh.facet_mergeset or qh.degen_mergeset
  352. if 'dist' is unknown, set it to 0.0
  353. if 'angle' is unknown, set it to 1.0 (coplanar)
  354. returns:
  355. merge appended to facet_mergeset or degen_mergeset
  356. sets ->degenerate or ->redundant if degen_mergeset
  357. notes:
  358. caller collects statistics and/or caller of qh_mergefacet
  359. see: qh_test_appendmerge()
  360. design:
  361. allocate merge entry
  362. if regular merge
  363. append to qh.facet_mergeset
  364. else if degenerate merge and qh.facet_mergeset is all degenerate
  365. append to qh.degen_mergeset
  366. else if degenerate merge
  367. prepend to qh.degen_mergeset (merged last)
  368. else if redundant merge
  369. append to qh.degen_mergeset
  370. */
  371. void qh_appendmergeset(qhT *qh, facetT *facet, facetT *neighbor, mergeType mergetype, coordT dist, realT angle) {
  372. mergeT *merge, *lastmerge;
  373. void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  374. const char *mergename;
  375. if ((facet->redundant && mergetype != MRGmirror) || neighbor->redundant) {
  376. trace3((qh, qh->ferr, 3051, "qh_appendmergeset: f%d is already redundant (%d) or f%d is already redundant (%d). Ignore merge f%d and f%d type %d\n",
  377. facet->id, facet->redundant, neighbor->id, neighbor->redundant, facet->id, neighbor->id, mergetype));
  378. return;
  379. }
  380. if (facet->degenerate && mergetype == MRGdegen) {
  381. trace3((qh, qh->ferr, 3077, "qh_appendmergeset: f%d is already degenerate. Ignore merge f%d type %d (MRGdegen)\n",
  382. facet->id, facet->id, mergetype));
  383. return;
  384. }
  385. if (!qh->facet_mergeset || !qh->degen_mergeset) {
  386. qh_fprintf(qh, qh->ferr, 6403, "qhull internal error (qh_appendmergeset): expecting temp set defined for qh.facet_mergeset (0x%x) and qh.degen_mergeset (0x%x). Got NULL\n",
  387. qh->facet_mergeset, qh->degen_mergeset);
  388. /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
  389. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  390. }
  391. if (neighbor->flipped && !facet->flipped) {
  392. if (mergetype != MRGdupridge) {
  393. qh_fprintf(qh, qh->ferr, 6355, "qhull internal error (qh_appendmergeset): except for MRGdupridge, cannot merge a non-flipped facet f%d into flipped f%d, mergetype %d, dist %4.4g\n",
  394. facet->id, neighbor->id, mergetype, dist);
  395. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  396. }else {
  397. trace2((qh, qh->ferr, 2106, "qh_appendmergeset: dupridge will merge a non-flipped facet f%d into flipped f%d, dist %4.4g\n",
  398. facet->id, neighbor->id, dist));
  399. }
  400. }
  401. qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
  402. merge->angle= angle;
  403. merge->distance= dist;
  404. merge->facet1= facet;
  405. merge->facet2= neighbor;
  406. merge->vertex1= NULL;
  407. merge->vertex2= NULL;
  408. merge->ridge1= NULL;
  409. merge->ridge2= NULL;
  410. merge->mergetype= mergetype;
  411. if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
  412. mergename= mergetypes[mergetype];
  413. else
  414. mergename= mergetypes[MRGnone];
  415. if (mergetype < MRGdegen)
  416. qh_setappend(qh, &(qh->facet_mergeset), merge);
  417. else if (mergetype == MRGdegen) {
  418. facet->degenerate= True;
  419. if (!(lastmerge= (mergeT *)qh_setlast(qh->degen_mergeset))
  420. || lastmerge->mergetype == MRGdegen)
  421. qh_setappend(qh, &(qh->degen_mergeset), merge);
  422. else
  423. qh_setaddnth(qh, &(qh->degen_mergeset), 0, merge); /* merged last */
  424. }else if (mergetype == MRGredundant) {
  425. facet->redundant= True;
  426. qh_setappend(qh, &(qh->degen_mergeset), merge);
  427. }else /* mergetype == MRGmirror */ {
  428. if (facet->redundant || neighbor->redundant) {
  429. qh_fprintf(qh, qh->ferr, 6092, "qhull internal error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet (i.e., 'redundant')\n",
  430. facet->id, neighbor->id);
  431. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  432. }
  433. if (!qh_setequal(facet->vertices, neighbor->vertices)) {
  434. qh_fprintf(qh, qh->ferr, 6093, "qhull internal error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
  435. facet->id, neighbor->id);
  436. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  437. }
  438. facet->redundant= True;
  439. neighbor->redundant= True;
  440. qh_setappend(qh, &(qh->degen_mergeset), merge);
  441. }
  442. if (merge->mergetype >= MRGdegen) {
  443. trace3((qh, qh->ferr, 3044, "qh_appendmergeset: append merge f%d and f%d type %d (%s) to qh.degen_mergeset (size %d)\n",
  444. merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, qh_setsize(qh, qh->degen_mergeset)));
  445. }else {
  446. trace3((qh, qh->ferr, 3027, "qh_appendmergeset: append merge f%d and f%d type %d (%s) dist %2.2g angle %4.4g to qh.facet_mergeset (size %d)\n",
  447. merge->facet1->id, merge->facet2->id, merge->mergetype, mergename, merge->distance, merge->angle, qh_setsize(qh, qh->facet_mergeset)));
  448. }
  449. } /* appendmergeset */
  450. /*-<a href="qh-merge_r.htm#TOC"
  451. >-------------------------------</a><a name="appendvertexmerge">-</a>
  452. qh_appendvertexmerge(qh, vertex, vertex2, mergetype, distance, ridge1, ridge2 )
  453. appends a vertex merge to qh.vertex_mergeset
  454. MRGsubridge includes two ridges (from MRGdupridge)
  455. MRGvertices includes two ridges
  456. notes:
  457. called by qh_getpinchedmerges for MRGsubridge
  458. called by qh_maybe_duplicateridge and qh_maybe_duplicateridges for MRGvertices
  459. only way to add a vertex merge to qh.vertex_mergeset
  460. checked by qh_next_vertexmerge
  461. */
  462. void qh_appendvertexmerge(qhT *qh, vertexT *vertex, vertexT *destination, mergeType mergetype, realT distance, ridgeT *ridge1, ridgeT *ridge2) {
  463. mergeT *merge;
  464. void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
  465. const char *mergename;
  466. if (!qh->vertex_mergeset) {
  467. qh_fprintf(qh, qh->ferr, 6387, "qhull internal error (qh_appendvertexmerge): expecting temp set defined for qh.vertex_mergeset (0x%x). Got NULL\n",
  468. qh->vertex_mergeset);
  469. /* otherwise qh_setappend creates a new set that is not freed by qh_freebuild() */
  470. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  471. }
  472. qh_memalloc_(qh, (int)sizeof(mergeT), freelistp, merge, mergeT);
  473. merge->angle= qh_ANGLEnone;
  474. merge->distance= distance;
  475. merge->facet1= NULL;
  476. merge->facet2= NULL;
  477. merge->vertex1= vertex;
  478. merge->vertex2= destination;
  479. merge->ridge1= ridge1;
  480. merge->ridge2= ridge2;
  481. merge->mergetype= mergetype;
  482. if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
  483. mergename= mergetypes[mergetype];
  484. else
  485. mergename= mergetypes[MRGnone];
  486. if (mergetype == MRGvertices) {
  487. if (!ridge1 || !ridge2 || ridge1 == ridge2) {
  488. qh_fprintf(qh, qh->ferr, 6106, "qhull internal error (qh_appendvertexmerge): expecting two distinct ridges for MRGvertices. Got r%d r%d\n",
  489. getid_(ridge1), getid_(ridge2));
  490. qh_errexit(qh, qh_ERRqhull, NULL, ridge1);
  491. }
  492. }
  493. qh_setappend(qh, &(qh->vertex_mergeset), merge);
  494. trace3((qh, qh->ferr, 3034, "qh_appendvertexmerge: append merge v%d into v%d r%d r%d dist %2.2g type %d (%s)\n",
  495. vertex->id, destination->id, getid_(ridge1), getid_(ridge2), distance, merge->mergetype, mergename));
  496. } /* appendvertexmerge */
  497. /*-<a href="qh-merge_r.htm#TOC"
  498. >-------------------------------</a><a name="basevertices">-</a>
  499. qh_basevertices(qh, samecycle )
  500. return temporary set of base vertices for samecycle
  501. samecycle is first facet in the cycle
  502. assumes apex is SETfirst_( samecycle->vertices )
  503. returns:
  504. vertices(settemp)
  505. all ->seen are cleared
  506. notes:
  507. uses qh_vertex_visit;
  508. design:
  509. for each facet in samecycle
  510. for each unseen vertex in facet->vertices
  511. append to result
  512. */
  513. setT *qh_basevertices(qhT *qh, facetT *samecycle) {
  514. facetT *same;
  515. vertexT *apex, *vertex, **vertexp;
  516. setT *vertices= qh_settemp(qh, qh->TEMPsize);
  517. apex= SETfirstt_(samecycle->vertices, vertexT);
  518. apex->visitid= ++qh->vertex_visit;
  519. FORALLsame_cycle_(samecycle) {
  520. if (same->mergeridge)
  521. continue;
  522. FOREACHvertex_(same->vertices) {
  523. if (vertex->visitid != qh->vertex_visit) {
  524. qh_setappend(qh, &vertices, vertex);
  525. vertex->visitid= qh->vertex_visit;
  526. vertex->seen= False;
  527. }
  528. }
  529. }
  530. trace4((qh, qh->ferr, 4019, "qh_basevertices: found %d vertices\n",
  531. qh_setsize(qh, vertices)));
  532. return vertices;
  533. } /* basevertices */
  534. /*-<a href="qh-merge_r.htm#TOC"
  535. >-------------------------------</a><a name="check_dupridge">-</a>
  536. qh_check_dupridge(qh, facet1, dist1, facet2, dist2 )
  537. Check dupridge between facet1 and facet2 for wide merge
  538. dist1 is the maximum distance of facet1's vertices to facet2
  539. dist2 is the maximum distance of facet2's vertices to facet1
  540. returns
  541. Level 1 log of the dupridge with the minimum distance between vertices
  542. Throws error if the merge will increase the maximum facet width by qh_WIDEduplicate (100x)
  543. notes:
  544. only called from qh_forcedmerges
  545. */
  546. void qh_check_dupridge(qhT *qh, facetT *facet1, realT dist1, facetT *facet2, realT dist2) {
  547. vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  548. realT dist, innerplane, mergedist, outerplane, prevdist, ratio, vertexratio;
  549. realT minvertex= REALmax;
  550. mergedist= fmin_(dist1, dist2);
  551. qh_outerinner(qh, NULL, &outerplane, &innerplane); /* ratio from qh_printsummary */
  552. FOREACHvertex_(facet1->vertices) { /* The dupridge is between facet1 and facet2, so either facet can be tested */
  553. FOREACHvertexA_(facet1->vertices) {
  554. if (vertex > vertexA){ /* Test each pair once */
  555. dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
  556. minimize_(minvertex, dist);
  557. /* Not quite correct. A facet may have a dupridge and another pair of nearly adjacent vertices. */
  558. }
  559. }
  560. }
  561. prevdist= fmax_(outerplane, innerplane);
  562. maximize_(prevdist, qh->ONEmerge + qh->DISTround);
  563. maximize_(prevdist, qh->MINoutside + qh->DISTround);
  564. ratio= mergedist/prevdist;
  565. vertexratio= minvertex/prevdist;
  566. trace0((qh, qh->ferr, 16, "qh_check_dupridge: dupridge between f%d and f%d (vertex dist %2.2g), dist %2.2g, reverse dist %2.2g, ratio %2.2g while processing p%d\n",
  567. facet1->id, facet2->id, minvertex, dist1, dist2, ratio, qh->furthest_id));
  568. if (ratio > qh_WIDEduplicate) {
  569. qh_fprintf(qh, qh->ferr, 6271, "qhull topology error (qh_check_dupridge): wide merge (%.1fx wider) due to dupridge between f%d and f%d (vertex dist %2.2g), merge dist %2.2g, while processing p%d\n- Allow error with option 'Q12'\n",
  570. ratio, facet1->id, facet2->id, minvertex, mergedist, qh->furthest_id);
  571. if (vertexratio < qh_WIDEpinched)
  572. qh_fprintf(qh, qh->ferr, 8145, "- Experimental option merge-pinched-vertices ('Q14') may avoid this error. It merges nearly adjacent vertices.\n");
  573. if (qh->DELAUNAY)
  574. qh_fprintf(qh, qh->ferr, 8145, "- A bounding box for the input sites may alleviate this error.\n");
  575. if (!qh->ALLOWwide)
  576. qh_errexit2(qh, qh_ERRwide, facet1, facet2);
  577. }
  578. } /* check_dupridge */
  579. /*-<a href="qh-merge_r.htm#TOC"
  580. >-------------------------------</a><a name="checkconnect">-</a>
  581. qh_checkconnect(qh)
  582. check that new facets are connected
  583. new facets are on qh.newfacet_list
  584. notes:
  585. this is slow and it changes the order of the facets
  586. uses qh.visit_id
  587. design:
  588. move first new facet to end of qh.facet_list
  589. for all newly appended facets
  590. append unvisited neighbors to end of qh.facet_list
  591. for all new facets
  592. report error if unvisited
  593. */
  594. void qh_checkconnect(qhT *qh /* qh.newfacet_list */) {
  595. facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
  596. facet= qh->newfacet_list;
  597. qh_removefacet(qh, facet);
  598. qh_appendfacet(qh, facet);
  599. facet->visitid= ++qh->visit_id;
  600. FORALLfacet_(facet) {
  601. FOREACHneighbor_(facet) {
  602. if (neighbor->visitid != qh->visit_id) {
  603. qh_removefacet(qh, neighbor);
  604. qh_appendfacet(qh, neighbor);
  605. neighbor->visitid= qh->visit_id;
  606. }
  607. }
  608. }
  609. FORALLnew_facets {
  610. if (newfacet->visitid == qh->visit_id)
  611. break;
  612. qh_fprintf(qh, qh->ferr, 6094, "qhull internal error (qh_checkconnect): f%d is not attached to the new facets\n",
  613. newfacet->id);
  614. errfacet= newfacet;
  615. }
  616. if (errfacet)
  617. qh_errexit(qh, qh_ERRqhull, errfacet, NULL);
  618. } /* checkconnect */
  619. /*-<a href="qh-merge_r.htm#TOC"
  620. >-------------------------------</a><a name="checkdelfacet">-</a>
  621. qh_checkdelfacet(qh, facet, mergeset )
  622. check that mergeset does not reference facet
  623. */
  624. void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
  625. mergeT *merge, **mergep;
  626. FOREACHmerge_(mergeset) {
  627. if (merge->facet1 == facet || merge->facet2 == facet) {
  628. qh_fprintf(qh, qh->ferr, 6390, "qhull internal error (qh_checkdelfacet): cannot delete f%d. It is referenced by merge f%d f%d mergetype %d\n",
  629. facet->id, merge->facet1->id, getid_(merge->facet2), merge->mergetype);
  630. qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  631. }
  632. }
  633. } /* checkdelfacet */
  634. /*-<a href="qh-merge_r.htm#TOC"
  635. >-------------------------------</a><a name="checkdelridge">-</a>
  636. qh_checkdelridge(qh)
  637. check that qh_delridge_merge is not needed for deleted ridges
  638. notes:
  639. called from qh_mergecycle, qh_makenewfacets, qh_attachnewfacets
  640. errors if qh.vertex_mergeset is non-empty
  641. errors if any visible or new facet has a ridge with r.nonconvex set
  642. assumes that vertex.delfacet is not needed
  643. */
  644. void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
  645. facetT *newfacet, *visible;
  646. ridgeT *ridge, **ridgep;
  647. if (!SETempty_(qh->vertex_mergeset)) {
  648. qh_fprintf(qh, qh->ferr, 6382, "qhull internal error (qh_checkdelridge): expecting empty qh.vertex_mergeset in order to avoid calling qh_delridge_merge. Got %d merges\n", qh_setsize(qh, qh->vertex_mergeset));
  649. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  650. }
  651. FORALLnew_facets {
  652. FOREACHridge_(newfacet->ridges) {
  653. if (ridge->nonconvex) {
  654. qh_fprintf(qh, qh->ferr, 6313, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in newfacet f%d. Otherwise need to call qh_delridge_merge\n",
  655. ridge->id, newfacet->id);
  656. qh_errexit(qh, qh_ERRqhull, newfacet, ridge);
  657. }
  658. }
  659. }
  660. FORALLvisible_facets {
  661. FOREACHridge_(visible->ridges) {
  662. if (ridge->nonconvex) {
  663. qh_fprintf(qh, qh->ferr, 6385, "qhull internal error (qh_checkdelridge): unexpected 'nonconvex' flag for ridge r%d in visible facet f%d. Otherwise need to call qh_delridge_merge\n",
  664. ridge->id, visible->id);
  665. qh_errexit(qh, qh_ERRqhull, visible, ridge);
  666. }
  667. }
  668. }
  669. } /* checkdelridge */
  670. /*-<a href="qh-merge_r.htm#TOC"
  671. >-------------------------------</a><a name="checkzero">-</a>
  672. qh_checkzero(qh, testall )
  673. check that facets are clearly convex for qh.DISTround with qh.MERGEexact
  674. if testall,
  675. test all facets for qh.MERGEexact post-merging
  676. else
  677. test qh.newfacet_list
  678. if qh.MERGEexact,
  679. allows coplanar ridges
  680. skips convexity test while qh.ZEROall_ok
  681. returns:
  682. True if all facets !flipped, !dupridge, normal
  683. if all horizon facets are simplicial
  684. if all vertices are clearly below neighbor
  685. if all opposite vertices of horizon are below
  686. clears qh.ZEROall_ok if any problems or coplanar facets
  687. notes:
  688. called by qh_premerge (qh.CHECKzero, 'C-0') and qh_qhull ('Qx')
  689. uses qh.vertex_visit
  690. horizon facets may define multiple new facets
  691. design:
  692. for all facets in qh.newfacet_list or qh.facet_list
  693. check for flagged faults (flipped, etc.)
  694. for all facets in qh.newfacet_list or qh.facet_list
  695. for each neighbor of facet
  696. skip horizon facets for qh.newfacet_list
  697. test the opposite vertex
  698. if qh.newfacet_list
  699. test the other vertices in the facet's horizon facet
  700. */
  701. boolT qh_checkzero(qhT *qh, boolT testall) {
  702. facetT *facet, *neighbor;
  703. facetT *horizon, *facetlist;
  704. int neighbor_i, neighbor_n;
  705. vertexT *vertex, **vertexp;
  706. realT dist;
  707. if (testall)
  708. facetlist= qh->facet_list;
  709. else {
  710. facetlist= qh->newfacet_list;
  711. FORALLfacet_(facetlist) {
  712. horizon= SETfirstt_(facet->neighbors, facetT);
  713. if (!horizon->simplicial)
  714. goto LABELproblem;
  715. if (facet->flipped || facet->dupridge || !facet->normal)
  716. goto LABELproblem;
  717. }
  718. if (qh->MERGEexact && qh->ZEROall_ok) {
  719. trace2((qh, qh->ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n"));
  720. return True;
  721. }
  722. }
  723. FORALLfacet_(facetlist) {
  724. qh->vertex_visit++;
  725. horizon= NULL;
  726. FOREACHneighbor_i_(qh, facet) {
  727. if (!neighbor_i && !testall) {
  728. horizon= neighbor;
  729. continue; /* horizon facet tested in qh_findhorizon */
  730. }
  731. vertex= SETelemt_(facet->vertices, neighbor_i, vertexT);
  732. vertex->visitid= qh->vertex_visit;
  733. zzinc_(Zdistzero);
  734. qh_distplane(qh, vertex->point, neighbor, &dist);
  735. if (dist >= -2 * qh->DISTround) { /* need 2x for qh_distround and 'Rn' for qh_checkconvex, same as qh.premerge_centrum */
  736. qh->ZEROall_ok= False;
  737. if (!qh->MERGEexact || testall || dist > qh->DISTround)
  738. goto LABELnonconvex;
  739. }
  740. }
  741. if (!testall && horizon) {
  742. FOREACHvertex_(horizon->vertices) {
  743. if (vertex->visitid != qh->vertex_visit) {
  744. zzinc_(Zdistzero);
  745. qh_distplane(qh, vertex->point, facet, &dist);
  746. if (dist >= -2 * qh->DISTround) {
  747. qh->ZEROall_ok= False;
  748. if (!qh->MERGEexact || dist > qh->DISTround)
  749. goto LABELnonconvexhorizon;
  750. }
  751. break;
  752. }
  753. }
  754. }
  755. }
  756. trace2((qh, qh->ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall,
  757. (qh->MERGEexact && !testall) ?
  758. "not concave, flipped, or dupridge" : "clearly convex"));
  759. return True;
  760. LABELproblem:
  761. qh->ZEROall_ok= False;
  762. trace2((qh, qh->ferr, 2013, "qh_checkzero: qh_premerge is needed. New facet f%d or its horizon f%d is non-simplicial, flipped, dupridge, or mergehorizon\n",
  763. facet->id, horizon->id));
  764. return False;
  765. LABELnonconvex:
  766. trace2((qh, qh->ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex. v%d dist %.2g\n",
  767. facet->id, neighbor->id, vertex->id, dist));
  768. return False;
  769. LABELnonconvexhorizon:
  770. trace2((qh, qh->ferr, 2060, "qh_checkzero: facet f%d and horizon f%d are not clearly convex. v%d dist %.2g\n",
  771. facet->id, horizon->id, vertex->id, dist));
  772. return False;
  773. } /* checkzero */
  774. /*-<a href="qh-merge_r.htm#TOC"
  775. >-------------------------------</a><a name="compare_anglemerge">-</a>
  776. qh_compare_anglemerge( mergeA, mergeB )
  777. used by qsort() to order qh.facet_mergeset by mergetype and angle (qh.ANGLEmerge, 'Q1')
  778. lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
  779. notes:
  780. qh_all_merges processes qh.facet_mergeset by qh_setdellast
  781. [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
  782. */
  783. int qh_compare_anglemerge(const void *p1, const void *p2) {
  784. const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
  785. if (a->mergetype != b->mergetype)
  786. return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  787. else
  788. return (a->angle > b->angle ? 1 : -1); /* select coplanar merge (1.0) before sharp merge (-0.5) */
  789. } /* compare_anglemerge */
  790. /*-<a href="qh-merge_r.htm#TOC"
  791. >-------------------------------</a><a name="compare_facetmerge">-</a>
  792. qh_compare_facetmerge( mergeA, mergeB )
  793. used by qsort() to order merges by mergetype, first merge, first
  794. lower numbered mergetypes done first (MRGcoplanar before MRGconcave)
  795. if same merge type, flat merges are first
  796. notes:
  797. qh_all_merges processes qh.facet_mergeset by qh_setdellast
  798. [mar'19] evaluated various options with eg/q_benchmark and merging of pinched vertices (Q14)
  799. */
  800. int qh_compare_facetmerge(const void *p1, const void *p2) {
  801. const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2);
  802. if (a->mergetype != b->mergetype)
  803. return (a->mergetype < b->mergetype ? 1 : -1); /* select MRGcoplanar (1) before MRGconcave (3) */
  804. else if (a->mergetype == MRGanglecoplanar)
  805. return (a->angle > b->angle ? 1 : -1); /* if MRGanglecoplanar, select coplanar merge (1.0) before sharp merge (-0.5) */
  806. else
  807. return (a->distance < b->distance ? 1 : -1); /* select flat (0.0) merge before wide (1e-10) merge */
  808. } /* compare_facetmerge */
  809. /*-<a href="qh-merge_r.htm#TOC"
  810. >-------------------------------</a><a name="comparevisit">-</a>
  811. qh_comparevisit( vertexA, vertexB )
  812. used by qsort() to order vertices by their visitid
  813. notes:
  814. only called by qh_find_newvertex
  815. */
  816. int qh_comparevisit(const void *p1, const void *p2) {
  817. const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2);
  818. if (a->visitid > b->visitid)
  819. return 1;
  820. return -1;
  821. } /* comparevisit */
  822. /*-<a href="qh-merge_r.htm#TOC"
  823. >-------------------------------</a><a name="copynonconvex">-</a>
  824. qh_copynonconvex(qh, atridge )
  825. set non-convex flag on other ridges (if any) between same neighbors
  826. notes:
  827. may be faster if use smaller ridge set
  828. design:
  829. for each ridge of atridge's top facet
  830. if ridge shares the same neighbor
  831. set nonconvex flag
  832. */
  833. void qh_copynonconvex(qhT *qh, ridgeT *atridge) {
  834. facetT *facet, *otherfacet;
  835. ridgeT *ridge, **ridgep;
  836. facet= atridge->top;
  837. otherfacet= atridge->bottom;
  838. atridge->nonconvex= False;
  839. FOREACHridge_(facet->ridges) {
  840. if (otherfacet == ridge->top || otherfacet == ridge->bottom) {
  841. if (ridge != atridge) {
  842. ridge->nonconvex= True;
  843. trace4((qh, qh->ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d between f%d and f%d\n",
  844. atridge->id, ridge->id, facet->id, otherfacet->id));
  845. break;
  846. }
  847. }
  848. }
  849. } /* copynonconvex */
  850. /*-<a href="qh-merge_r.htm#TOC"
  851. >-------------------------------</a><a name="degen_redundant_facet">-</a>
  852. qh_degen_redundant_facet(qh, facet )
  853. check for a degenerate (too few neighbors) or redundant (subset of vertices) facet
  854. notes:
  855. called at end of qh_mergefacet, qh_renamevertex, and qh_reducevertices
  856. bumps vertex_visit
  857. called if a facet was redundant but no longer is (qh_merge_degenredundant)
  858. qh_appendmergeset() only appends first reference to facet (i.e., redundant)
  859. see: qh_test_redundant_neighbors, qh_maydropneighbor
  860. design:
  861. test for redundant neighbor
  862. test for degenerate facet
  863. */
  864. void qh_degen_redundant_facet(qhT *qh, facetT *facet) {
  865. vertexT *vertex, **vertexp;
  866. facetT *neighbor, **neighborp;
  867. trace3((qh, qh->ferr, 3028, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
  868. facet->id));
  869. if (facet->flipped) {
  870. trace2((qh, qh->ferr, 3074, "qh_degen_redundant_facet: f%d is flipped, will merge later\n", facet->id));
  871. return;
  872. }
  873. FOREACHneighbor_(facet) {
  874. if (neighbor->flipped) /* disallow merge of non-flipped into flipped, neighbor will be merged later */
  875. continue;
  876. if (neighbor->visible) {
  877. qh_fprintf(qh, qh->ferr, 6357, "qhull internal error (qh_degen_redundant_facet): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
  878. facet->id, neighbor->id);
  879. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  880. }
  881. qh->vertex_visit++;
  882. FOREACHvertex_(neighbor->vertices)
  883. vertex->visitid= qh->vertex_visit;
  884. FOREACHvertex_(facet->vertices) {
  885. if (vertex->visitid != qh->vertex_visit)
  886. break;
  887. }
  888. if (!vertex) {
  889. trace2((qh, qh->ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d. merge\n", facet->id, neighbor->id));
  890. qh_appendmergeset(qh, facet, neighbor, MRGredundant, 0.0, 1.0);
  891. return;
  892. }
  893. }
  894. if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
  895. qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
  896. trace2((qh, qh->ferr, 2016, "qh_degen_redundant_facet: f%d is degenerate.\n", facet->id));
  897. }
  898. } /* degen_redundant_facet */
  899. /*-<a href="qh-merge_r.htm#TOC"
  900. >-------------------------------</a><a name="delridge_merge">-</a>
  901. qh_delridge_merge(qh, ridge )
  902. delete ridge due to a merge
  903. notes:
  904. only called by merge_r.c (qh_mergeridges, qh_renameridgevertex)
  905. ridges also freed in qh_freeqhull and qh_mergecycle_ridges
  906. design:
  907. if needed, moves ridge.nonconvex to another ridge
  908. sets vertex.delridge for qh_reducevertices
  909. deletes ridge from qh.vertex_mergeset
  910. deletes ridge from its neighboring facets
  911. frees up its memory
  912. */
  913. void qh_delridge_merge(qhT *qh, ridgeT *ridge) {
  914. vertexT *vertex, **vertexp;
  915. mergeT *merge;
  916. int merge_i, merge_n;
  917. trace3((qh, qh->ferr, 3036, "qh_delridge_merge: delete ridge r%d between f%d and f%d\n",
  918. ridge->id, ridge->top->id, ridge->bottom->id));
  919. if (ridge->nonconvex)
  920. qh_copynonconvex(qh, ridge);
  921. FOREACHvertex_(ridge->vertices)
  922. vertex->delridge= True;
  923. FOREACHmerge_i_(qh, qh->vertex_mergeset) {
  924. if (merge->ridge1 == ridge || merge->ridge2 == ridge) {
  925. trace3((qh, qh->ferr, 3029, "qh_delridge_merge: drop merge of v%d into v%d (dist %2.2g r%d r%d) due to deleted, duplicated ridge r%d\n",
  926. merge->vertex1->id, merge->vertex2->id, merge->distance, merge->ridge1->id, merge->ridge2->id, ridge->id));
  927. if (merge->ridge1 == ridge)
  928. merge->ridge2->mergevertex= False;
  929. else
  930. merge->ridge1->mergevertex= False;
  931. qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
  932. merge_i--; merge_n--; /* next merge after deleted */
  933. }
  934. }
  935. qh_setdel(ridge->top->ridges, ridge);
  936. qh_setdel(ridge->bottom->ridges, ridge);
  937. qh_delridge(qh, ridge);
  938. } /* delridge_merge */
  939. /*-<a href="qh-merge_r.htm#TOC"
  940. >-------------------------------</a><a name="drop_mergevertex">-</a>
  941. qh_drop_mergevertex(qh, merge )
  942. clear mergevertex flags for ridges of a vertex merge
  943. */
  944. void qh_drop_mergevertex(qhT *qh, mergeT *merge)
  945. {
  946. if (merge->mergetype == MRGvertices) {
  947. merge->ridge1->mergevertex= False;
  948. merge->ridge1->mergevertex2= True;
  949. merge->ridge2->mergevertex= False;
  950. merge->ridge2->mergevertex2= True;
  951. trace3((qh, qh->ferr, 3032, "qh_drop_mergevertex: unset mergevertex for r%d and r%d due to dropped vertex merge v%d to v%d. Sets mergevertex2\n",
  952. merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id));
  953. }
  954. } /* drop_mergevertex */
  955. /*-<a href="qh-merge_r.htm#TOC"
  956. >-------------------------------</a><a name="find_newvertex">-</a>
  957. qh_find_newvertex(qh, oldvertex, vertices, ridges )
  958. locate new vertex for renaming old vertex
  959. vertices is a set of possible new vertices
  960. vertices sorted by number of deleted ridges
  961. returns:
  962. newvertex or NULL
  963. each ridge includes both newvertex and oldvertex
  964. vertices without oldvertex sorted by number of deleted ridges
  965. qh.vertex_visit updated
  966. sets v.seen
  967. notes:
  968. called by qh_redundant_vertex due to vertex->delridge and qh_rename_sharedvertex
  969. sets vertex->visitid to 0..setsize() for vertices
  970. new vertex is in one of the ridges
  971. renaming will not cause a duplicate ridge
  972. renaming will minimize the number of deleted ridges
  973. newvertex may not be adjacent in the dual (though unlikely)
  974. design:
  975. for each vertex in vertices
  976. set vertex->visitid to number of ridges
  977. remove unvisited vertices
  978. set qh.vertex_visit above all possible values
  979. sort vertices by number of ridges (minimize ridges that need renaming
  980. add each ridge to qh.hash_table
  981. for each vertex in vertices
  982. find the first vertex that would not cause a duplicate ridge after a rename
  983. */
  984. vertexT *qh_find_newvertex(qhT *qh, vertexT *oldvertex, setT *vertices, setT *ridges) {
  985. vertexT *vertex, **vertexp;
  986. setT *newridges;
  987. ridgeT *ridge, **ridgep;
  988. int size, hashsize;
  989. int hash;
  990. unsigned int maxvisit;
  991. #ifndef qh_NOtrace
  992. if (qh->IStracing >= 4) {
  993. qh_fprintf(qh, qh->ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ",
  994. oldvertex->id);
  995. FOREACHvertex_(vertices)
  996. qh_fprintf(qh, qh->ferr, 8064, "v%d ", vertex->id);
  997. FOREACHridge_(ridges)
  998. qh_fprintf(qh, qh->ferr, 8065, "r%d ", ridge->id);
  999. qh_fprintf(qh, qh->ferr, 8066, "\n");
  1000. }
  1001. #endif
  1002. FOREACHridge_(ridges) {
  1003. FOREACHvertex_(ridge->vertices)
  1004. vertex->seen= False;
  1005. }
  1006. FOREACHvertex_(vertices) {
  1007. vertex->visitid= 0; /* v.visitid will be number of ridges */
  1008. vertex->seen= True;
  1009. }
  1010. FOREACHridge_(ridges) {
  1011. FOREACHvertex_(ridge->vertices) {
  1012. if (vertex->seen)
  1013. vertex->visitid++;
  1014. }
  1015. }
  1016. FOREACHvertex_(vertices) {
  1017. if (!vertex->visitid) {
  1018. qh_setdelnth(qh, vertices, SETindex_(vertices,vertex));
  1019. vertexp--; /* repeat since deleted this vertex */
  1020. }
  1021. }
  1022. maxvisit= (unsigned int)qh_setsize(qh, ridges);
  1023. maximize_(qh->vertex_visit, maxvisit);
  1024. if (!qh_setsize(qh, vertices)) {
  1025. trace4((qh, qh->ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n",
  1026. oldvertex->id));
  1027. return NULL;
  1028. }
  1029. qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(qh, vertices),
  1030. sizeof(vertexT *), qh_comparevisit);
  1031. /* can now use qh->vertex_visit */
  1032. if (qh->PRINTstatistics) {
  1033. size= qh_setsize(qh, vertices);
  1034. zinc_(Zintersect);
  1035. zadd_(Zintersecttot, size);
  1036. zmax_(Zintersectmax, size);
  1037. }
  1038. hashsize= qh_newhashtable(qh, qh_setsize(qh, ridges));
  1039. FOREACHridge_(ridges)
  1040. qh_hashridge(qh, qh->hash_table, hashsize, ridge, oldvertex);
  1041. FOREACHvertex_(vertices) {
  1042. newridges= qh_vertexridges(qh, vertex, !qh_ALL);
  1043. FOREACHridge_(newridges) {
  1044. if (qh_hashridge_find(qh, qh->hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
  1045. zinc_(Zvertexridge);
  1046. break;
  1047. }
  1048. }
  1049. qh_settempfree(qh, &newridges);
  1050. if (!ridge)
  1051. break; /* found a rename */
  1052. }
  1053. if (vertex) {
  1054. /* counted in qh_renamevertex */
  1055. trace2((qh, qh->ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
  1056. vertex->id, oldvertex->id, qh_setsize(qh, vertices), qh_setsize(qh, ridges)));
  1057. }else {
  1058. zinc_(Zfindfail);
  1059. trace0((qh, qh->ferr, 14, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
  1060. oldvertex->id, qh->furthest_id));
  1061. }
  1062. qh_setfree(qh, &qh->hash_table);
  1063. return vertex;
  1064. } /* find_newvertex */
  1065. /*-<a href="qh-geom2_r.htm#TOC"
  1066. >-------------------------------</a><a name="findbest_pinchedvertex">-</a>
  1067. qh_findbest_pinchedvertex(qh, merge, apex, nearestp, distp )
  1068. Determine the best pinched vertex to rename as its nearest neighboring vertex
  1069. Renaming will remove a duplicate MRGdupridge in newfacet_list
  1070. returns:
  1071. pinched vertex (either apex or subridge), nearest vertex (subridge or neighbor vertex), and the distance between them
  1072. notes:
  1073. only called by qh_getpinchedmerges
  1074. assumes qh.VERTEXneighbors
  1075. see qh_findbest_ridgevertex
  1076. design:
  1077. if the facets have the same vertices
  1078. return the nearest vertex pair
  1079. else
  1080. the subridge is the intersection of the two new facets minus the apex
  1081. the subridge consists of qh.hull_dim-2 horizon vertices
  1082. the subridge is also a matched ridge for the new facets (its duplicate)
  1083. determine the nearest vertex to the apex
  1084. determine the nearest pair of subridge vertices
  1085. for each vertex in the subridge
  1086. determine the nearest neighbor vertex (not in the subridge)
  1087. */
  1088. vertexT *qh_findbest_pinchedvertex(qhT *qh, mergeT *merge, vertexT *apex, vertexT **nearestp, coordT *distp /* qh.newfacet_list */) {
  1089. vertexT *vertex, **vertexp, *vertexA, **vertexAp;
  1090. vertexT *bestvertex= NULL, *bestpinched= NULL;
  1091. setT *subridge, *maybepinched;
  1092. coordT dist, bestdist= REALmax;
  1093. coordT pincheddist= (qh->ONEmerge+qh->DISTround)*qh_RATIOpinchedsubridge;
  1094. if (!merge->facet1->simplicial || !merge->facet2->simplicial) {
  1095. qh_fprintf(qh, qh->ferr, 6351, "qhull internal error (qh_findbest_pinchedvertex): expecting merge of adjacent, simplicial new facets. f%d or f%d is not simplicial\n",
  1096. merge->facet1->id, merge->facet2->id);
  1097. qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  1098. }
  1099. subridge= qh_vertexintersect_new(qh, merge->facet1->vertices, merge->facet2->vertices); /* new setT. No error_exit() */
  1100. if (qh_setsize(qh, subridge) == qh->hull_dim) { /* duplicate vertices */
  1101. bestdist= qh_vertex_bestdist2(qh, subridge, &bestvertex, &bestpinched);
  1102. if(bestvertex == apex) {
  1103. bestvertex= bestpinched;
  1104. bestpinched= apex;
  1105. }
  1106. }else {
  1107. qh_setdel(subridge, apex);
  1108. if (qh_setsize(qh, subridge) != qh->hull_dim - 2) {
  1109. qh_fprintf(qh, qh->ferr, 6409, "qhull internal error (qh_findbest_pinchedvertex): expecting subridge of qh.hull_dim-2 vertices for the intersection of new facets f%d and f%d minus their apex. Got %d vertices\n",
  1110. merge->facet1->id, merge->facet2->id, qh_setsize(qh, subridge));
  1111. qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  1112. }
  1113. FOREACHvertex_(subridge) {
  1114. dist= qh_pointdist(vertex->point, apex->point, qh->hull_dim);
  1115. if (dist < bestdist) {
  1116. bestpinched= apex;
  1117. bestvertex= vertex;
  1118. bestdist= dist;
  1119. }
  1120. }
  1121. if (bestdist > pincheddist) {
  1122. FOREACHvertex_(subridge) {
  1123. FOREACHvertexA_(subridge) {
  1124. if (vertexA->id > vertex->id) { /* once per vertex pair, do not compare addresses */
  1125. dist= qh_pointdist(vertexA->point, vertex->point, qh->hull_dim);
  1126. if (dist < bestdist) {
  1127. bestpinched= vertexA;
  1128. bestvertex= vertex;
  1129. bestdist= dist;
  1130. }
  1131. }
  1132. }
  1133. }
  1134. }
  1135. if (bestdist > pincheddist) {
  1136. FOREACHvertexA_(subridge) {
  1137. maybepinched= qh_neighbor_vertices(qh, vertexA, subridge); /* subridge and apex tested above */
  1138. FOREACHvertex_(maybepinched) {
  1139. dist= qh_pointdist(vertex->point, vertexA->point, qh->hull_dim);
  1140. if (dist < bestdist) {
  1141. bestvertex= vertex;
  1142. bestpinched= vertexA;
  1143. bestdist= dist;
  1144. }
  1145. }
  1146. qh_settempfree(qh, &maybepinched);
  1147. }
  1148. }
  1149. }
  1150. *distp= bestdist;
  1151. qh_setfree(qh, &subridge); /* qh_err_exit not called since allocated */
  1152. if (!bestvertex) { /* should never happen if qh.hull_dim > 2 */
  1153. qh_fprintf(qh, qh->ferr, 6274, "qhull internal error (qh_findbest_pinchedvertex): did not find best vertex for subridge of dupridge between f%d and f%d, while processing p%d\n", merge->facet1->id, merge->facet2->id, qh->furthest_id);
  1154. qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  1155. }
  1156. *nearestp= bestvertex;
  1157. trace2((qh, qh->ferr, 2061, "qh_findbest_pinchedvertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicate subridge between f%d and f%d\n",
  1158. qh_pointid(qh, bestpinched->point), bestpinched->id, qh_pointid(qh, bestvertex->point), bestvertex->id, bestdist, merge->facet1->id, merge->facet2->id));
  1159. return bestpinched;
  1160. } /* findbest_pinchedvertex */
  1161. /*-<a href="qh-geom2_r.htm#TOC"
  1162. >-------------------------------</a><a name="findbest_ridgevertex">-</a>
  1163. qh_findbest_ridgevertex(qh, ridge, pinchedp, distp )
  1164. Determine the best vertex/pinched-vertex to merge for ridges with the same vertices
  1165. returns:
  1166. vertex, pinched vertex, and the distance between them
  1167. notes:
  1168. assumes qh.hull_dim>=3
  1169. see qh_findbest_pinchedvertex
  1170. */
  1171. vertexT *qh_findbest_ridgevertex(qhT *qh, ridgeT *ridge, vertexT **pinchedp, coordT *distp) {
  1172. vertexT *bestvertex;
  1173. *distp= qh_vertex_bestdist2(qh, ridge->vertices, &bestvertex, pinchedp);
  1174. trace4((qh, qh->ferr, 4069, "qh_findbest_ridgevertex: best pinched p%d(v%d) and vertex p%d(v%d) are closest (%2.2g) for duplicated ridge r%d (same vertices) between f%d and f%d\n",
  1175. qh_pointid(qh, (*pinchedp)->point), (*pinchedp)->id, qh_pointid(qh, bestvertex->point), bestvertex->id, *distp, ridge->id, ridge->top->id, ridge->bottom->id));
  1176. return bestvertex;
  1177. } /* findbest_ridgevertex */
  1178. /*-<a href="qh-merge_r.htm#TOC"
  1179. >-------------------------------</a><a name="findbest_test">-</a>
  1180. qh_findbest_test(qh, testcentrum, facet, neighbor, &bestfacet, &dist, &mindist, &maxdist )
  1181. test neighbor of facet for qh_findbestneighbor()
  1182. if testcentrum,
  1183. tests centrum (assumes it is defined)
  1184. else
  1185. tests vertices
  1186. initially *bestfacet==NULL and *dist==REALmax
  1187. returns:
  1188. if a better facet (i.e., vertices/centrum of facet closer to neighbor)
  1189. updates bestfacet, dist, mindist, and maxdist
  1190. notes:
  1191. called by qh_findbestneighbor
  1192. ignores pairs of flipped facets, unless that's all there is
  1193. */
  1194. void qh_findbest_test(qhT *qh, boolT testcentrum, facetT *facet, facetT *neighbor,
  1195. facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
  1196. realT dist, mindist, maxdist;
  1197. if (facet->flipped && neighbor->flipped && *bestfacet && !(*bestfacet)->flipped)
  1198. return; /* do not merge flipped into flipped facets */
  1199. if (testcentrum) {
  1200. zzinc_(Zbestdist);
  1201. qh_distplane(qh, facet->center, neighbor, &dist);
  1202. dist *= qh->hull_dim; /* estimate furthest vertex */
  1203. if (dist < 0) {
  1204. maxdist= 0;
  1205. mindist= dist;
  1206. dist= -dist;
  1207. }else {
  1208. mindist= 0;
  1209. maxdist= dist;
  1210. }
  1211. }else
  1212. dist= qh_getdistance(qh, facet, neighbor, &mindist, &maxdist);
  1213. if (dist < *distp) {
  1214. *bestfacet= neighbor;
  1215. *mindistp= mindist;
  1216. *maxdistp= maxdist;
  1217. *distp= dist;
  1218. }
  1219. } /* findbest_test */
  1220. /*-<a href="qh-merge_r.htm#TOC"
  1221. >-------------------------------</a><a name="findbestneighbor">-</a>
  1222. qh_findbestneighbor(qh, facet, dist, mindist, maxdist )
  1223. finds best neighbor (least dist) of a facet for merging
  1224. returns:
  1225. returns min and max distances and their max absolute value
  1226. notes:
  1227. error if qh_ASvoronoi
  1228. avoids merging old into new
  1229. assumes ridge->nonconvex only set on one ridge between a pair of facets
  1230. could use an early out predicate but not worth it
  1231. design:
  1232. if a large facet
  1233. will test centrum
  1234. else
  1235. will test vertices
  1236. if a large facet
  1237. test nonconvex neighbors for best merge
  1238. else
  1239. test all neighbors for the best merge
  1240. if testing centrum
  1241. get distance information
  1242. */
  1243. facetT *qh_findbestneighbor(qhT *qh, facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
  1244. facetT *neighbor, **neighborp, *bestfacet= NULL;
  1245. ridgeT *ridge, **ridgep;
  1246. boolT nonconvex= True, testcentrum= False;
  1247. int size= qh_setsize(qh, facet->vertices);
  1248. if(qh->CENTERtype==qh_ASvoronoi){
  1249. qh_fprintf(qh, qh->ferr, 6272, "qhull internal error: cannot call qh_findbestneighor for f%d while qh.CENTERtype is qh_ASvoronoi\n", facet->id);
  1250. qh_errexit(qh, qh_ERRqhull, facet, NULL);
  1251. }
  1252. *distp= REALmax;
  1253. if (size > qh_BESTcentrum2 * qh->hull_dim + qh_BESTcentrum) {
  1254. testcentrum= True;
  1255. zinc_(Zbestcentrum);
  1256. if (!facet->center)
  1257. facet->center= qh_getcentrum(qh, facet);
  1258. }
  1259. if (size > qh->hull_dim + qh_BESTnonconvex) {
  1260. FOREACHridge_(facet->ridges) {
  1261. if (ridge->nonconvex) {
  1262. neighbor= otherfacet_(ridge, facet);
  1263. qh_findbest_test(qh, testcentrum, facet, neighbor,
  1264. &bestfacet, distp, mindistp, maxdistp);
  1265. }
  1266. }
  1267. }
  1268. if (!bestfacet) {
  1269. nonconvex= False;
  1270. FOREACHneighbor_(facet)
  1271. qh_findbest_test(qh, testcentrum, facet, neighbor,
  1272. &bestfacet, distp, mindistp, maxdistp);
  1273. }
  1274. if (!bestfacet) {
  1275. qh_fprintf(qh, qh->ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
  1276. qh_errexit(qh, qh_ERRqhull, facet, NULL);
  1277. }
  1278. if (testcentrum)
  1279. qh_getdistance(qh, facet, bestfacet, mindistp, maxdistp);
  1280. trace3((qh, qh->ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
  1281. bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
  1282. return(bestfacet);
  1283. } /* findbestneighbor */
  1284. /*-<a href="qh-merge_r.htm#TOC"
  1285. >-------------------------------</a><a name="flippedmerges">-</a>
  1286. qh_flippedmerges(qh, facetlist, wasmerge )
  1287. merge flipped facets into best neighbor
  1288. assumes qh.facet_mergeset at top of temporary stack
  1289. returns:
  1290. no flipped facets on facetlist
  1291. sets wasmerge if merge occurred
  1292. degen/redundant merges passed through
  1293. notes:
  1294. othermerges not needed since qh.facet_mergeset is empty before & after
  1295. keep it in case of change
  1296. design:
  1297. append flipped facets to qh.facetmergeset
  1298. for each flipped merge
  1299. find best neighbor
  1300. merge facet into neighbor
  1301. merge degenerate and redundant facets
  1302. remove flipped merges from qh.facet_mergeset
  1303. */
  1304. void qh_flippedmerges(qhT *qh, facetT *facetlist, boolT *wasmerge) {
  1305. facetT *facet, *neighbor, *facet1;
  1306. realT dist, mindist, maxdist;
  1307. mergeT *merge, **mergep;
  1308. setT *othermerges;
  1309. int nummerge= 0, numdegen= 0;
  1310. trace4((qh, qh->ferr, 4024, "qh_flippedmerges: begin\n"));
  1311. FORALLfacet_(facetlist) {
  1312. if (facet->flipped && !facet->visible)
  1313. qh_appendmergeset(qh, facet, facet, MRGflip, 0.0, 1.0);
  1314. }
  1315. othermerges= qh_settemppop(qh);
  1316. if(othermerges != qh->facet_mergeset) {
  1317. qh_fprintf(qh, qh->ferr, 6392, "qhull internal error (qh_flippedmerges): facet_mergeset (%d merges) not at top of tempstack (%d merges)\n",
  1318. qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, othermerges));
  1319. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1320. }
  1321. qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
  1322. qh_settemppush(qh, othermerges);
  1323. FOREACHmerge_(othermerges) {
  1324. facet1= merge->facet1;
  1325. if (merge->mergetype != MRGflip || facet1->visible)
  1326. continue;
  1327. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  1328. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  1329. neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
  1330. trace0((qh, qh->ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
  1331. facet1->id, neighbor->id, dist, qh->furthest_id));
  1332. qh_mergefacet(qh, facet1, neighbor, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
  1333. nummerge++;
  1334. if (qh->PRINTstatistics) {
  1335. zinc_(Zflipped);
  1336. wadd_(Wflippedtot, dist);
  1337. wmax_(Wflippedmax, dist);
  1338. }
  1339. }
  1340. FOREACHmerge_(othermerges) {
  1341. if (merge->facet1->visible || merge->facet2->visible)
  1342. qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
  1343. else
  1344. qh_setappend(qh, &qh->facet_mergeset, merge);
  1345. }
  1346. qh_settempfree(qh, &othermerges);
  1347. numdegen += qh_merge_degenredundant(qh); /* somewhat better here than after each flipped merge -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
  1348. if (nummerge)
  1349. *wasmerge= True;
  1350. trace1((qh, qh->ferr, 1010, "qh_flippedmerges: merged %d flipped and %d degenredundant facets into a good neighbor\n",
  1351. nummerge, numdegen));
  1352. } /* flippedmerges */
  1353. /*-<a href="qh-merge_r.htm#TOC"
  1354. >-------------------------------</a><a name="forcedmerges">-</a>
  1355. qh_forcedmerges(qh, wasmerge )
  1356. merge dupridges
  1357. calls qh_check_dupridge to report an error on wide merges
  1358. assumes qh_settemppop is qh.facet_mergeset
  1359. returns:
  1360. removes all dupridges on facet_mergeset
  1361. wasmerge set if merge
  1362. qh.facet_mergeset may include non-forced merges(none for now)
  1363. qh.degen_mergeset includes degen/redun merges
  1364. notes:
  1365. called by qh_premerge
  1366. dupridges occur when the horizon is pinched,
  1367. i.e. a subridge occurs in more than two horizon ridges.
  1368. could rename vertices that pinch the horizon
  1369. assumes qh_merge_degenredundant() has not be called
  1370. othermerges isn't needed since facet_mergeset is empty afterwards
  1371. keep it in case of change
  1372. design:
  1373. for each dupridge
  1374. find current facets by chasing f.replace links
  1375. check for wide merge due to dupridge
  1376. determine best direction for facet
  1377. merge one facet into the other
  1378. remove dupridges from qh.facet_mergeset
  1379. */
  1380. void qh_forcedmerges(qhT *qh, boolT *wasmerge) {
  1381. facetT *facet1, *facet2, *merging, *merged, *newfacet;
  1382. mergeT *merge, **mergep;
  1383. realT dist, mindist, maxdist, dist2, mindist2, maxdist2;
  1384. setT *othermerges;
  1385. int nummerge=0, numflip=0, numdegen= 0;
  1386. boolT wasdupridge= False;
  1387. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  1388. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  1389. trace3((qh, qh->ferr, 3054, "qh_forcedmerges: merge dupridges\n"));
  1390. othermerges= qh_settemppop(qh); /* was facet_mergeset */
  1391. if (qh->facet_mergeset != othermerges ) {
  1392. qh_fprintf(qh, qh->ferr, 6279, "qhull internal error (qh_forcedmerges): qh_settemppop (size %d) is not qh->facet_mergeset (size %d)\n",
  1393. qh_setsize(qh, othermerges), qh_setsize(qh, qh->facet_mergeset));
  1394. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1395. }
  1396. qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize);
  1397. qh_settemppush(qh, othermerges);
  1398. FOREACHmerge_(othermerges) {
  1399. if (merge->mergetype != MRGdupridge)
  1400. continue;
  1401. wasdupridge= True;
  1402. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  1403. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  1404. facet1= qh_getreplacement(qh, merge->facet1); /* must exist, no qh_merge_degenredunant */
  1405. facet2= qh_getreplacement(qh, merge->facet2); /* previously merged facet, if any */
  1406. if (facet1 == facet2)
  1407. continue;
  1408. if (!qh_setin(facet2->neighbors, facet1)) {
  1409. qh_fprintf(qh, qh->ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a dupridge but as f%d and f%d they are no longer neighbors\n",
  1410. merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
  1411. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  1412. }
  1413. dist= qh_getdistance(qh, facet1, facet2, &mindist, &maxdist);
  1414. dist2= qh_getdistance(qh, facet2, facet1, &mindist2, &maxdist2);
  1415. qh_check_dupridge(qh, facet1, dist, facet2, dist2);
  1416. if (dist < dist2) {
  1417. if (facet2->flipped && !facet1->flipped && dist2 < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
  1418. merging= facet2;
  1419. merged= facet1;
  1420. dist= dist2;
  1421. mindist= mindist2;
  1422. maxdist= maxdist2;
  1423. }else {
  1424. merging= facet1;
  1425. merged= facet2;
  1426. }
  1427. }else {
  1428. if (facet1->flipped && !facet2->flipped && dist < qh_WIDEdupridge*(qh->ONEmerge+qh->DISTround)) { /* prefer merge of flipped facet */
  1429. merging= facet1;
  1430. merged= facet2;
  1431. }else {
  1432. merging= facet2;
  1433. merged= facet1;
  1434. dist= dist2;
  1435. mindist= mindist2;
  1436. maxdist= maxdist2;
  1437. }
  1438. }
  1439. qh_mergefacet(qh, merging, merged, merge->mergetype, &mindist, &maxdist, !qh_MERGEapex);
  1440. numdegen += qh_merge_degenredundant(qh); /* better here than at end -- qtest.sh 10 '500 C1,2e-13 D4' 'd Qbb' */
  1441. if (facet1->flipped) {
  1442. zinc_(Zmergeflipdup);
  1443. numflip++;
  1444. }else
  1445. nummerge++;
  1446. if (qh->PRINTstatistics) {
  1447. zinc_(Zduplicate);
  1448. wadd_(Wduplicatetot, dist);
  1449. wmax_(Wduplicatemax, dist);
  1450. }
  1451. }
  1452. FOREACHmerge_(othermerges) {
  1453. if (merge->mergetype == MRGdupridge)
  1454. qh_memfree(qh, merge, (int)sizeof(mergeT)); /* invalidates merge and othermerges */
  1455. else
  1456. qh_setappend(qh, &qh->facet_mergeset, merge);
  1457. }
  1458. qh_settempfree(qh, &othermerges);
  1459. if (wasdupridge) {
  1460. FORALLnew_facets {
  1461. if (newfacet->dupridge) {
  1462. newfacet->dupridge= False;
  1463. newfacet->mergeridge= False;
  1464. newfacet->mergeridge2= False;
  1465. if (qh_setsize(qh, newfacet->neighbors) < qh->hull_dim) { /* not tested for MRGdupridge */
  1466. qh_appendmergeset(qh, newfacet, newfacet, MRGdegen, 0.0, 1.0);
  1467. trace2((qh, qh->ferr, 2107, "qh_forcedmerges: dupridge f%d is degenerate with fewer than %d neighbors\n",
  1468. newfacet->id, qh->hull_dim));
  1469. }
  1470. }
  1471. }
  1472. numdegen += qh_merge_degenredundant(qh);
  1473. }
  1474. if (nummerge || numflip) {
  1475. *wasmerge= True;
  1476. trace1((qh, qh->ferr, 1011, "qh_forcedmerges: merged %d facets, %d flipped facets, and %d degenredundant facets across dupridges\n",
  1477. nummerge, numflip, numdegen));
  1478. }
  1479. } /* forcedmerges */
  1480. /*-<a href="qh-merge_r.htm#TOC"
  1481. >-------------------------------</a><a name="freemergesets">-</a>
  1482. qh_freemergesets(qh )
  1483. free the merge sets
  1484. notes:
  1485. matches qh_initmergesets
  1486. */
  1487. void qh_freemergesets(qhT *qh) {
  1488. if (!qh->facet_mergeset || !qh->degen_mergeset || !qh->vertex_mergeset) {
  1489. qh_fprintf(qh, qh->ferr, 6388, "qhull internal error (qh_freemergesets): expecting mergesets. Got a NULL mergeset, qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
  1490. qh->facet_mergeset, qh->degen_mergeset, qh->vertex_mergeset);
  1491. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1492. }
  1493. if (!SETempty_(qh->facet_mergeset) || !SETempty_(qh->degen_mergeset) || !SETempty_(qh->vertex_mergeset)) {
  1494. qh_fprintf(qh, qh->ferr, 6389, "qhull internal error (qh_freemergesets): expecting empty mergesets. Got qh.facet_mergeset (%d merges), qh.degen_mergeset (%d merges), qh.vertex_mergeset (%d merges)\n",
  1495. qh_setsize(qh, qh->facet_mergeset), qh_setsize(qh, qh->degen_mergeset), qh_setsize(qh, qh->vertex_mergeset));
  1496. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1497. }
  1498. qh_settempfree(qh, &qh->facet_mergeset);
  1499. qh_settempfree(qh, &qh->vertex_mergeset);
  1500. qh_settempfree(qh, &qh->degen_mergeset);
  1501. } /* freemergesets */
  1502. /*-<a href="qh-merge_r.htm#TOC"
  1503. >-------------------------------</a><a name="getmergeset">-</a>
  1504. qh_getmergeset(qh, facetlist )
  1505. determines nonconvex facets on facetlist
  1506. tests !tested ridges and nonconvex ridges of !tested facets
  1507. returns:
  1508. returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
  1509. all ridges tested
  1510. notes:
  1511. facetlist is qh.facet_newlist, use qh_getmergeset_initial for all facets
  1512. assumes no nonconvex ridges with both facets tested
  1513. uses facet->tested/ridge->tested to prevent duplicate tests
  1514. can not limit tests to modified ridges since the centrum changed
  1515. uses qh.visit_id
  1516. design:
  1517. for each facet on facetlist
  1518. for each ridge of facet
  1519. if untested ridge
  1520. test ridge for convexity
  1521. if non-convex
  1522. append ridge to qh.facet_mergeset
  1523. sort qh.facet_mergeset by mergetype and angle or distance
  1524. */
  1525. void qh_getmergeset(qhT *qh, facetT *facetlist) {
  1526. facetT *facet, *neighbor, **neighborp;
  1527. ridgeT *ridge, **ridgep;
  1528. int nummerges;
  1529. boolT simplicial;
  1530. nummerges= qh_setsize(qh, qh->facet_mergeset);
  1531. trace4((qh, qh->ferr, 4026, "qh_getmergeset: started.\n"));
  1532. qh->visit_id++;
  1533. FORALLfacet_(facetlist) {
  1534. if (facet->tested)
  1535. continue;
  1536. facet->visitid= qh->visit_id;
  1537. FOREACHneighbor_(facet)
  1538. neighbor->seen= False;
  1539. /* facet must be non-simplicial due to merge to qh.facet_newlist */
  1540. FOREACHridge_(facet->ridges) {
  1541. if (ridge->tested && !ridge->nonconvex)
  1542. continue;
  1543. /* if r.tested & r.nonconvex, need to retest and append merge */
  1544. neighbor= otherfacet_(ridge, facet);
  1545. if (neighbor->seen) { /* another ridge for this facet-neighbor pair was already tested in this loop */
  1546. ridge->tested= True;
  1547. ridge->nonconvex= False; /* only one ridge is marked nonconvex per facet-neighbor pair */
  1548. }else if (neighbor->visitid != qh->visit_id) {
  1549. neighbor->seen= True;
  1550. ridge->nonconvex= False;
  1551. simplicial= False;
  1552. if (ridge->simplicialbot && ridge->simplicialtop)
  1553. simplicial= True;
  1554. if (qh_test_appendmerge(qh, facet, neighbor, simplicial))
  1555. ridge->nonconvex= True;
  1556. ridge->tested= True;
  1557. }
  1558. }
  1559. facet->tested= True;
  1560. }
  1561. nummerges= qh_setsize(qh, qh->facet_mergeset);
  1562. if (qh->ANGLEmerge)
  1563. qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  1564. else
  1565. qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  1566. nummerges += qh_setsize(qh, qh->degen_mergeset);
  1567. if (qh->POSTmerging) {
  1568. zadd_(Zmergesettot2, nummerges);
  1569. }else {
  1570. zadd_(Zmergesettot, nummerges);
  1571. zmax_(Zmergesetmax, nummerges);
  1572. }
  1573. trace2((qh, qh->ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges));
  1574. } /* getmergeset */
  1575. /*-<a href="qh-merge_r.htm#TOC"
  1576. >-------------------------------</a><a name="getmergeset_initial">-</a>
  1577. qh_getmergeset_initial(qh, facetlist )
  1578. determine initial qh.facet_mergeset for facets
  1579. tests all facet/neighbor pairs on facetlist
  1580. returns:
  1581. sorted qh.facet_mergeset with nonconvex ridges
  1582. sets facet->tested, ridge->tested, and ridge->nonconvex
  1583. notes:
  1584. uses visit_id, assumes ridge->nonconvex is False
  1585. see qh_getmergeset
  1586. design:
  1587. for each facet on facetlist
  1588. for each untested neighbor of facet
  1589. test facet and neighbor for convexity
  1590. if non-convex
  1591. append merge to qh.facet_mergeset
  1592. mark one of the ridges as nonconvex
  1593. sort qh.facet_mergeset by mergetype and angle or distance
  1594. */
  1595. void qh_getmergeset_initial(qhT *qh, facetT *facetlist) {
  1596. facetT *facet, *neighbor, **neighborp;
  1597. ridgeT *ridge, **ridgep;
  1598. int nummerges;
  1599. boolT simplicial;
  1600. qh->visit_id++;
  1601. FORALLfacet_(facetlist) {
  1602. facet->visitid= qh->visit_id;
  1603. FOREACHneighbor_(facet) {
  1604. if (neighbor->visitid != qh->visit_id) {
  1605. simplicial= False; /* ignores r.simplicialtop/simplicialbot. Need to test horizon facets */
  1606. if (facet->simplicial && neighbor->simplicial)
  1607. simplicial= True;
  1608. if (qh_test_appendmerge(qh, facet, neighbor, simplicial)) {
  1609. FOREACHridge_(neighbor->ridges) {
  1610. if (facet == otherfacet_(ridge, neighbor)) {
  1611. ridge->nonconvex= True;
  1612. break; /* only one ridge is marked nonconvex */
  1613. }
  1614. }
  1615. }
  1616. }
  1617. }
  1618. facet->tested= True;
  1619. FOREACHridge_(facet->ridges)
  1620. ridge->tested= True;
  1621. }
  1622. nummerges= qh_setsize(qh, qh->facet_mergeset);
  1623. if (qh->ANGLEmerge)
  1624. qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_anglemerge);
  1625. else
  1626. qsort(SETaddr_(qh->facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compare_facetmerge);
  1627. nummerges += qh_setsize(qh, qh->degen_mergeset);
  1628. if (qh->POSTmerging) {
  1629. zadd_(Zmergeinittot2, nummerges);
  1630. }else {
  1631. zadd_(Zmergeinittot, nummerges);
  1632. zmax_(Zmergeinitmax, nummerges);
  1633. }
  1634. trace2((qh, qh->ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges));
  1635. } /* getmergeset_initial */
  1636. /*-<a href="qh-merge_r.htm#TOC"
  1637. >-------------------------------</a><a name="getpinchedmerges">-</a>
  1638. qh_getpinchedmerges(qh, apex, maxdist, iscoplanar )
  1639. get pinched merges for dupridges in qh.facet_mergeset
  1640. qh.NEWtentative==True
  1641. qh.newfacet_list with apex
  1642. qh.horizon_list is attached to qh.visible_list instead of qh.newfacet_list
  1643. maxdist for vertex-facet of a dupridge
  1644. qh.facet_mergeset is empty
  1645. qh.vertex_mergeset is a temporary set
  1646. returns:
  1647. False if nearest vertex would increase facet width by more than maxdist or qh_WIDEpinched
  1648. True and iscoplanar, if the pinched vertex is the apex (i.e., make the apex a coplanar point)
  1649. True and !iscoplanar, if should merge a pinched vertex of a dupridge
  1650. qh.vertex_mergeset contains one or more MRGsubridge with a pinched vertex and a nearby, neighboring vertex
  1651. qh.facet_mergeset is empty
  1652. notes:
  1653. called by qh_buildcone_mergepinched
  1654. hull_dim >= 3
  1655. a pinched vertex is in a dupridge and the horizon
  1656. selects the pinched vertex that is closest to its neighbor
  1657. design:
  1658. for each dupridge
  1659. determine the best pinched vertex to be merged into a neighboring vertex
  1660. if merging the pinched vertex would produce a wide merge (qh_WIDEpinched)
  1661. ignore pinched vertex with a warning, and use qh_merge_degenredundant instead
  1662. else
  1663. append the pinched vertex to vertex_mergeset for merging
  1664. */
  1665. boolT qh_getpinchedmerges(qhT *qh, vertexT *apex, coordT maxdupdist, boolT *iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */) {
  1666. mergeT *merge, **mergep, *bestmerge= NULL;
  1667. vertexT *nearest, *pinched, *bestvertex= NULL, *bestpinched= NULL;
  1668. boolT result;
  1669. coordT dist, prevdist, bestdist= REALmax/(qh_RATIOcoplanarapex+1.0); /* allow *3.0 */
  1670. realT ratio;
  1671. trace2((qh, qh->ferr, 2062, "qh_getpinchedmerges: try to merge pinched vertices for dupridges in new facets with apex p%d(v%d) max dupdist %2.2g\n",
  1672. qh_pointid(qh, apex->point), apex->id, maxdupdist));
  1673. *iscoplanar= False;
  1674. prevdist= fmax_(qh->ONEmerge + qh->DISTround, qh->MINoutside + qh->DISTround);
  1675. maximize_(prevdist, qh->max_outside);
  1676. maximize_(prevdist, -qh->min_vertex);
  1677. qh_mark_dupridges(qh, qh->newfacet_list, !qh_ALL); /* qh.facet_mergeset, creates ridges */
  1678. /* qh_mark_dupridges is called a second time in qh_premerge */
  1679. FOREACHmerge_(qh->facet_mergeset) { /* read-only */
  1680. if (merge->mergetype != MRGdupridge) {
  1681. qh_fprintf(qh, qh->ferr, 6393, "qhull internal error (qh_getpinchedmerges): expecting MRGdupridge from qh_mark_dupridges. Got merge f%d f%d type %d\n",
  1682. getid_(merge->facet1), getid_(merge->facet2), merge->mergetype);
  1683. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1684. }
  1685. /* dist is distance between vertices */
  1686. pinched= qh_findbest_pinchedvertex(qh, merge, apex, &nearest, &dist /* qh.newfacet_list */);
  1687. if (pinched == apex && dist < qh_RATIOcoplanarapex*bestdist) { /* prefer coplanar apex since it always works */
  1688. bestdist= dist/qh_RATIOcoplanarapex;
  1689. bestmerge= merge;
  1690. bestpinched= pinched;
  1691. bestvertex= nearest;
  1692. }else if (dist < bestdist) {
  1693. bestdist= dist;
  1694. bestmerge= merge;
  1695. bestpinched= pinched;
  1696. bestvertex= nearest;
  1697. }
  1698. }
  1699. result= False;
  1700. if (bestmerge && bestdist < maxdupdist) {
  1701. ratio= bestdist / prevdist;
  1702. if (ratio > qh_WIDEpinched) {
  1703. if (bestmerge->facet1->mergehorizon || bestmerge->facet2->mergehorizon) { /* e.g., rbox 175 C3,2e-13 t1539182828 | qhull d */
  1704. trace1((qh, qh->ferr, 1051, "qh_getpinchedmerges: dupridge (MRGdupridge) of coplanar horizon would produce a wide merge (%.0fx) due to pinched vertices v%d and v%d (dist %2.2g) for f%d and f%d. qh_mergecycle_all will merge one or both facets\n",
  1705. ratio, bestpinched->id, bestvertex->id, bestdist, bestmerge->facet1->id, bestmerge->facet2->id));
  1706. }else {
  1707. qh_fprintf(qh, qh->ferr, 7081, "qhull precision warning (qh_getpinchedmerges): pinched vertices v%d and v%d (dist %2.2g, %.0fx) would produce a wide merge for f%d and f%d. Will merge dupridge instead\n",
  1708. bestpinched->id, bestvertex->id, bestdist, ratio, bestmerge->facet1->id, bestmerge->facet2->id);
  1709. }
  1710. }else {
  1711. if (bestpinched == apex) {
  1712. trace2((qh, qh->ferr, 2063, "qh_getpinchedmerges: will make the apex a coplanar point. apex p%d(v%d) is the nearest vertex to v%d on dupridge. Dist %2.2g\n",
  1713. qh_pointid(qh, apex->point), apex->id, bestvertex->id, bestdist*qh_RATIOcoplanarapex));
  1714. qh->coplanar_apex= apex->point;
  1715. *iscoplanar= True;
  1716. result= True;
  1717. }else if (qh_setin(bestmerge->facet1->vertices, bestpinched) != qh_setin(bestmerge->facet2->vertices, bestpinched)) { /* pinched in one facet but not the other facet */
  1718. trace2((qh, qh->ferr, 2064, "qh_getpinchedmerges: will merge new facets to resolve dupridge between f%d and f%d with pinched v%d and v%d\n",
  1719. bestmerge->facet1->id, bestmerge->facet2->id, bestpinched->id, bestvertex->id));
  1720. qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
  1721. result= True;
  1722. }else {
  1723. trace2((qh, qh->ferr, 2065, "qh_getpinchedmerges: will merge pinched v%d into v%d to resolve dupridge between f%d and f%d\n",
  1724. bestpinched->id, bestvertex->id, bestmerge->facet1->id, bestmerge->facet2->id));
  1725. qh_appendvertexmerge(qh, bestpinched, bestvertex, MRGsubridge, bestdist, NULL, NULL);
  1726. result= True;
  1727. }
  1728. }
  1729. }
  1730. /* delete MRGdupridge, qh_mark_dupridges is called a second time in qh_premerge */
  1731. while ((merge= (mergeT *)qh_setdellast(qh->facet_mergeset)))
  1732. qh_memfree(qh, merge, (int)sizeof(mergeT));
  1733. return result;
  1734. }/* getpinchedmerges */
  1735. /*-<a href="qh-merge_r.htm#TOC"
  1736. >-------------------------------</a><a name="hasmerge">-</a>
  1737. qh_hasmerge( mergeset, mergetype, facetA, facetB )
  1738. True if mergeset has mergetype for facetA and facetB
  1739. */
  1740. boolT qh_hasmerge(setT *mergeset, mergeType type, facetT *facetA, facetT *facetB) {
  1741. mergeT *merge, **mergep;
  1742. FOREACHmerge_(mergeset) {
  1743. if (merge->mergetype == type) {
  1744. if (merge->facet1 == facetA && merge->facet2 == facetB)
  1745. return True;
  1746. if (merge->facet1 == facetB && merge->facet2 == facetA)
  1747. return True;
  1748. }
  1749. }
  1750. return False;
  1751. }/* hasmerge */
  1752. /*-<a href="qh-merge_r.htm#TOC"
  1753. >-------------------------------</a><a name="hashridge">-</a>
  1754. qh_hashridge(qh, hashtable, hashsize, ridge, oldvertex )
  1755. add ridge to hashtable without oldvertex
  1756. notes:
  1757. assumes hashtable is large enough
  1758. design:
  1759. determine hash value for ridge without oldvertex
  1760. find next empty slot for ridge
  1761. */
  1762. void qh_hashridge(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
  1763. int hash;
  1764. ridgeT *ridgeA;
  1765. hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, oldvertex);
  1766. while (True) {
  1767. if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
  1768. SETelem_(hashtable, hash)= ridge;
  1769. break;
  1770. }else if (ridgeA == ridge)
  1771. break;
  1772. if (++hash == hashsize)
  1773. hash= 0;
  1774. }
  1775. } /* hashridge */
  1776. /*-<a href="qh-merge_r.htm#TOC"
  1777. >-------------------------------</a><a name="hashridge_find">-</a>
  1778. qh_hashridge_find(qh, hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
  1779. returns matching ridge without oldvertex in hashtable
  1780. for ridge without vertex
  1781. if oldvertex is NULL
  1782. matches with any one skip
  1783. returns:
  1784. matching ridge or NULL
  1785. if no match,
  1786. if ridge already in table
  1787. hashslot= -1
  1788. else
  1789. hashslot= next NULL index
  1790. notes:
  1791. assumes hashtable is large enough
  1792. can't match ridge to itself
  1793. design:
  1794. get hash value for ridge without vertex
  1795. for each hashslot
  1796. return match if ridge matches ridgeA without oldvertex
  1797. */
  1798. ridgeT *qh_hashridge_find(qhT *qh, setT *hashtable, int hashsize, ridgeT *ridge,
  1799. vertexT *vertex, vertexT *oldvertex, int *hashslot) {
  1800. int hash;
  1801. ridgeT *ridgeA;
  1802. *hashslot= 0;
  1803. zinc_(Zhashridge);
  1804. hash= qh_gethash(qh, hashsize, ridge->vertices, qh->hull_dim-1, 0, vertex);
  1805. while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
  1806. if (ridgeA == ridge)
  1807. *hashslot= -1;
  1808. else {
  1809. zinc_(Zhashridgetest);
  1810. if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex))
  1811. return ridgeA;
  1812. }
  1813. if (++hash == hashsize)
  1814. hash= 0;
  1815. }
  1816. if (!*hashslot)
  1817. *hashslot= hash;
  1818. return NULL;
  1819. } /* hashridge_find */
  1820. /*-<a href="qh-merge_r.htm#TOC"
  1821. >-------------------------------</a><a name="initmergesets">-</a>
  1822. qh_initmergesets(qh )
  1823. initialize the merge sets
  1824. if 'all', include qh.degen_mergeset
  1825. notes:
  1826. matches qh_freemergesets
  1827. */
  1828. void qh_initmergesets(qhT *qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */) {
  1829. if (qh->facet_mergeset || qh->degen_mergeset || qh->vertex_mergeset) {
  1830. qh_fprintf(qh, qh->ferr, 6386, "qhull internal error (qh_initmergesets): expecting NULL mergesets. Got qh.facet_mergeset (0x%x), qh.degen_mergeset (0x%x), qh.vertex_mergeset (0x%x)\n",
  1831. qh->facet_mergeset, qh->degen_mergeset, qh->vertex_mergeset);
  1832. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  1833. }
  1834. qh->degen_mergeset= qh_settemp(qh, qh->TEMPsize);
  1835. qh->vertex_mergeset= qh_settemp(qh, qh->TEMPsize);
  1836. qh->facet_mergeset= qh_settemp(qh, qh->TEMPsize); /* last temporary set for qh_forcedmerges */
  1837. } /* initmergesets */
  1838. /*-<a href="qh-merge_r.htm#TOC"
  1839. >-------------------------------</a><a name="makeridges">-</a>
  1840. qh_makeridges(qh, facet )
  1841. creates explicit ridges between simplicial facets
  1842. returns:
  1843. facet with ridges and without qh_MERGEridge
  1844. ->simplicial is False
  1845. if facet was tested, new ridges are tested
  1846. notes:
  1847. allows qh_MERGEridge flag
  1848. uses existing ridges
  1849. duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
  1850. see:
  1851. qh_mergecycle_ridges()
  1852. qh_rename_adjacentvertex for qh_merge_pinchedvertices
  1853. design:
  1854. look for qh_MERGEridge neighbors
  1855. mark neighbors that already have ridges
  1856. for each unprocessed neighbor of facet
  1857. create a ridge for neighbor and facet
  1858. if any qh_MERGEridge neighbors
  1859. delete qh_MERGEridge flags (previously processed by qh_mark_dupridges)
  1860. */
  1861. void qh_makeridges(qhT *qh, facetT *facet) {
  1862. facetT *neighbor, **neighborp;
  1863. ridgeT *ridge, **ridgep;
  1864. int neighbor_i, neighbor_n;
  1865. boolT toporient, mergeridge= False;
  1866. if (!facet->simplicial)
  1867. return;
  1868. trace4((qh, qh->ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id));
  1869. facet->simplicial= False;
  1870. FOREACHneighbor_(facet) {
  1871. if (neighbor == qh_MERGEridge)
  1872. mergeridge= True;
  1873. else
  1874. neighbor->seen= False;
  1875. }
  1876. FOREACHridge_(facet->ridges)
  1877. otherfacet_(ridge, facet)->seen= True;
  1878. FOREACHneighbor_i_(qh, facet) {
  1879. if (neighbor == qh_MERGEridge)
  1880. continue; /* fixed by qh_mark_dupridges */
  1881. else if (!neighbor->seen) { /* no current ridges */
  1882. ridge= qh_newridge(qh);
  1883. ridge->vertices= qh_setnew_delnthsorted(qh, facet->vertices, qh->hull_dim,
  1884. neighbor_i, 0);
  1885. toporient= (boolT)(facet->toporient ^ (neighbor_i & 0x1));
  1886. if (toporient) {
  1887. ridge->top= facet;
  1888. ridge->bottom= neighbor;
  1889. ridge->simplicialtop= True;
  1890. ridge->simplicialbot= neighbor->simplicial;
  1891. }else {
  1892. ridge->top= neighbor;
  1893. ridge->bottom= facet;
  1894. ridge->simplicialtop= neighbor->simplicial;
  1895. ridge->simplicialbot= True;
  1896. }
  1897. if (facet->tested && !mergeridge)
  1898. ridge->tested= True;
  1899. #if 0 /* this also works */
  1900. flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
  1901. if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
  1902. ridge->top= neighbor;
  1903. ridge->bottom= facet;
  1904. ridge->simplicialtop= True;
  1905. ridge->simplicialbot= neighbor->simplicial;
  1906. }else {
  1907. ridge->top= facet;
  1908. ridge->bottom= neighbor;
  1909. ridge->simplicialtop= neighbor->simplicial;
  1910. ridge->simplicialbot= True;
  1911. }
  1912. #endif
  1913. qh_setappend(qh, &(facet->ridges), ridge);
  1914. trace5((qh, qh->ferr, 5005, "makeridges: appended r%d to ridges for f%d. Next is ridges for neighbor f%d\n",
  1915. ridge->id, facet->id, neighbor->id));
  1916. qh_setappend(qh, &(neighbor->ridges), ridge);
  1917. if (qh->ridge_id == qh->traceridge_id)
  1918. qh->traceridge= ridge;
  1919. }
  1920. }
  1921. if (mergeridge) {
  1922. while (qh_setdel(facet->neighbors, qh_MERGEridge))
  1923. ; /* delete each one */
  1924. }
  1925. } /* makeridges */
  1926. /*-<a href="qh-merge_r.htm#TOC"
  1927. >-------------------------------</a><a name="mark_dupridges">-</a>
  1928. qh_mark_dupridges(qh, facetlist, allmerges )
  1929. add duplicated ridges to qh.facet_mergeset
  1930. facet-dupridge is true if it contains a subridge shared by more than one new facet
  1931. for each such facet, one has a neighbor marked qh_MERGEridge
  1932. allmerges is true if merging dupridges
  1933. allmerges is false if merging pinched vertices followed by retry addpoint
  1934. qh_mark_dupridges will be called again if pinched vertices not found
  1935. returns:
  1936. dupridges on qh.facet_mergeset (MRGdupridge)
  1937. f.mergeridge and f.mergeridge2 set for facet
  1938. f.mergeridge set for neighbor
  1939. if allmerges is true
  1940. make ridges for facets with dupridges as marked by qh_MERGEridge and both sides facet->dupridge
  1941. removes qh_MERGEridge from neighbor sets
  1942. notes:
  1943. called by qh_premerge and qh_getpinchedmerges
  1944. dupridges are due to duplicate subridges
  1945. i.e. a subridge occurs in more than two horizon ridges.
  1946. i.e., a ridge has more than two neighboring facets
  1947. dupridges occur in at least two cases
  1948. 1) a pinched horizon with nearly adjacent vertices -> merge the vertices (qh_getpinchedmerges)
  1949. 2) more than one newfacet for a horizon face -> merge coplanar facets (qh_premerge)
  1950. qh_matchdupridge previously identified the furthest apart pair of facets to retain
  1951. they must have a matching subridge and the same orientation
  1952. only way to set facet->mergeridge and mergeridge2
  1953. uses qh.visit_id
  1954. design:
  1955. for all facets on facetlist
  1956. if facet contains a dupridge
  1957. for each neighbor of facet
  1958. if neighbor marked qh_MERGEridge (one side of the merge)
  1959. set facet->mergeridge
  1960. else
  1961. if neighbor contains a dupridge
  1962. and the back link is qh_MERGEridge
  1963. append dupridge to qh.facet_mergeset
  1964. exit if !allmerges for repeating qh_mark_dupridges later
  1965. for each dupridge
  1966. make ridge sets in preparation for merging
  1967. remove qh_MERGEridge from neighbor set
  1968. for each dupridge
  1969. restore the missing neighbor from the neighbor set that was qh_MERGEridge
  1970. add the missing ridge for this neighbor
  1971. */
  1972. void qh_mark_dupridges(qhT *qh, facetT *facetlist, boolT allmerges) {
  1973. facetT *facet, *neighbor, **neighborp;
  1974. int nummerge=0;
  1975. mergeT *merge, **mergep;
  1976. trace4((qh, qh->ferr, 4028, "qh_mark_dupridges: identify dupridges in facetlist f%d, allmerges? %d\n",
  1977. facetlist->id, allmerges));
  1978. FORALLfacet_(facetlist) { /* not necessary for first call */
  1979. facet->mergeridge2= False;
  1980. facet->mergeridge= False;
  1981. }
  1982. FORALLfacet_(facetlist) {
  1983. if (facet->dupridge) {
  1984. FOREACHneighbor_(facet) {
  1985. if (neighbor == qh_MERGEridge) {
  1986. facet->mergeridge= True;
  1987. continue;
  1988. }
  1989. if (neighbor->dupridge) {
  1990. if (!qh_setin(neighbor->neighbors, facet)) { /* i.e., it is qh_MERGEridge, neighbors are distinct */
  1991. qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
  1992. facet->mergeridge2= True;
  1993. facet->mergeridge= True;
  1994. nummerge++;
  1995. }else if (qh_setequal(facet->vertices, neighbor->vertices)) { /* neighbors are the same except for horizon and qh_MERGEridge, see QH7085 */
  1996. trace3((qh, qh->ferr, 3043, "qh_mark_dupridges): dupridge due to duplicate vertices for subridges f%d and f%d\n",
  1997. facet->id, neighbor->id));
  1998. qh_appendmergeset(qh, facet, neighbor, MRGdupridge, 0.0, 1.0);
  1999. facet->mergeridge2= True;
  2000. facet->mergeridge= True;
  2001. nummerge++;
  2002. break; /* same for all neighbors */
  2003. }
  2004. }
  2005. }
  2006. }
  2007. }
  2008. if (!nummerge)
  2009. return;
  2010. if (!allmerges) {
  2011. trace1((qh, qh->ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_getpinchedmerges\n", nummerge));
  2012. return;
  2013. }
  2014. trace1((qh, qh->ferr, 1048, "qh_mark_dupridges: found %d duplicated ridges (MRGdupridge) for qh_premerge. Prepare facets for merging\n", nummerge));
  2015. /* make ridges in preparation for merging */
  2016. FORALLfacet_(facetlist) {
  2017. if (facet->mergeridge && !facet->mergeridge2)
  2018. qh_makeridges(qh, facet);
  2019. }
  2020. trace3((qh, qh->ferr, 3075, "qh_mark_dupridges: restore missing neighbors and ridges due to qh_MERGEridge\n"));
  2021. FOREACHmerge_(qh->facet_mergeset) { /* restore the missing neighbors */
  2022. if (merge->mergetype == MRGdupridge) { /* only between simplicial facets */
  2023. if (merge->facet2->mergeridge2 && qh_setin(merge->facet2->neighbors, merge->facet1)) {
  2024. /* Due to duplicate or multiple subridges, e.g., ../eg/qtest.sh t712682 '200 s W1e-13 C1,1e-13 D5' 'd'
  2025. merge->facet1: - neighboring facets: f27779 f59186 f59186 f59186 MERGEridge f59186
  2026. merge->facet2: - neighboring facets: f27779 f59100 f59100 f59100 f59100 f59100
  2027. or, ../eg/qtest.sh 100 '500 s W1e-13 C1,1e-13 D4' 'd'
  2028. both facets will be degenerate after merge, consider for special case handling
  2029. */
  2030. qh_fprintf(qh, qh->ferr, 6361, "qhull topological error (qh_mark_dupridges): multiple dupridges for f%d and f%d, including reverse\n",
  2031. merge->facet1->id, merge->facet2->id);
  2032. qh_errexit2(qh, qh_ERRtopology, merge->facet1, merge->facet2);
  2033. }else
  2034. qh_setappend(qh, &merge->facet2->neighbors, merge->facet1);
  2035. qh_makeridges(qh, merge->facet1); /* and the missing ridges */
  2036. }
  2037. }
  2038. } /* mark_dupridges */
  2039. /*-<a href="qh-merge_r.htm#TOC"
  2040. >-------------------------------</a><a name="maybe_duplicateridge">-</a>
  2041. qh_maybe_duplicateridge(qh, ridge )
  2042. add MRGvertices if neighboring facet has another ridge with the same vertices
  2043. returns:
  2044. adds rename requests to qh.vertex_mergeset
  2045. notes:
  2046. called by qh_renamevertex
  2047. nop if 2-D
  2048. expensive test
  2049. Duplicate ridges may lead to new facets with same vertex set (QH7084), will try merging vertices
  2050. same as qh_maybe_duplicateridges
  2051. design:
  2052. for the two neighbors
  2053. if non-simplicial
  2054. for each ridge with the same first and last vertices (max id and min id)
  2055. if the remaining vertices are the same
  2056. get the closest pair of vertices
  2057. add to vertex_mergeset for merging
  2058. */
  2059. void qh_maybe_duplicateridge(qhT *qh, ridgeT *ridgeA) {
  2060. ridgeT *ridge, **ridgep;
  2061. vertexT *vertex, *pinched;
  2062. facetT *neighbor;
  2063. coordT dist;
  2064. int i, k, last= qh->hull_dim-2;
  2065. if (qh->hull_dim < 3 )
  2066. return;
  2067. for (neighbor= ridgeA->top, i=0; i<2; neighbor= ridgeA->bottom, i++) {
  2068. if (!neighbor->simplicial && neighbor->nummerge > 0) { /* skip degenerate neighbors with both new and old vertices that will be merged */
  2069. FOREACHridge_(neighbor->ridges) {
  2070. if (ridge != ridgeA && SETfirst_(ridge->vertices) == SETfirst_(ridgeA->vertices)) {
  2071. if (SETelem_(ridge->vertices, last) == SETelem_(ridgeA->vertices, last)) {
  2072. for (k=1; k<last; k++) {
  2073. if (SETelem_(ridge->vertices, k) != SETelem_(ridgeA->vertices, k))
  2074. break;
  2075. }
  2076. if (k == last) {
  2077. vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
  2078. trace2((qh, qh->ferr, 2069, "qh_maybe_duplicateridge: will merge v%d into v%d (dist %2.2g) due to duplicate ridges r%d/r%d with the same vertices. mergevertex set\n",
  2079. pinched->id, vertex->id, dist, ridgeA->id, ridge->id, ridgeA->top->id, ridgeA->bottom->id, ridge->top->id, ridge->bottom->id));
  2080. qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridgeA, ridge);
  2081. ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
  2082. ridgeA->mergevertex= True;
  2083. }
  2084. }
  2085. }
  2086. }
  2087. }
  2088. }
  2089. } /* maybe_duplicateridge */
  2090. /*-<a href="qh-merge_r.htm#TOC"
  2091. >-------------------------------</a><a name="maybe_duplicateridges">-</a>
  2092. qh_maybe_duplicateridges(qh, facet )
  2093. if Q15, add MRGvertices if facet has ridges with the same vertices
  2094. returns:
  2095. adds rename requests to qh.vertex_mergeset
  2096. notes:
  2097. called at end of qh_mergefacet and qh_mergecycle_all
  2098. only enabled if qh.CHECKduplicates ('Q15') and 3-D or more
  2099. expensive test, not worth it
  2100. same as qh_maybe_duplicateridge
  2101. design:
  2102. for all ridge pairs in facet
  2103. if the same first and last vertices (max id and min id)
  2104. if the remaining vertices are the same
  2105. get the closest pair of vertices
  2106. add to vertex_mergeset for merging
  2107. */
  2108. void qh_maybe_duplicateridges(qhT *qh, facetT *facet) {
  2109. facetT *otherfacet;
  2110. ridgeT *ridge, *ridge2;
  2111. vertexT *vertex, *pinched;
  2112. coordT dist;
  2113. int ridge_i, ridge_n, i, k, last_v= qh->hull_dim-2;
  2114. if (qh->hull_dim < 3 || !qh->CHECKduplicates)
  2115. return;
  2116. FOREACHridge_i_(qh, facet->ridges) {
  2117. otherfacet= otherfacet_(ridge, facet);
  2118. if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
  2119. continue;
  2120. for (i=ridge_i+1; i < ridge_n; i++) {
  2121. ridge2= SETelemt_(facet->ridges, i, ridgeT);
  2122. otherfacet= otherfacet_(ridge2, facet);
  2123. if (otherfacet->degenerate || otherfacet->redundant || otherfacet->dupridge || otherfacet->flipped) /* will merge */
  2124. continue;
  2125. /* optimize qh_setequal(ridge->vertices, ridge2->vertices) */
  2126. if (SETelem_(ridge->vertices, last_v) == SETelem_(ridge2->vertices, last_v)) { /* SETfirst is likely to be the same */
  2127. if (SETfirst_(ridge->vertices) == SETfirst_(ridge2->vertices)) {
  2128. for (k=1; k<last_v; k++) {
  2129. if (SETelem_(ridge->vertices, k) != SETelem_(ridge2->vertices, k))
  2130. break;
  2131. }
  2132. if (k == last_v) {
  2133. vertex= qh_findbest_ridgevertex(qh, ridge, &pinched, &dist);
  2134. if (ridge->top == ridge2->bottom && ridge->bottom == ridge2->top) {
  2135. /* proof that ridges may have opposite orientation */
  2136. trace2((qh, qh->ferr, 2088, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to opposite oriented ridges r%d/r%d for f%d and f%d\n",
  2137. pinched->id, vertex->id, dist, ridge->id, ridge2->id, ridge->top->id, ridge->bottom->id));
  2138. }else {
  2139. trace2((qh, qh->ferr, 2083, "qh_maybe_duplicateridges: will merge v%d into v%d (dist %2.2g) due to duplicate ridges with the same vertices r%d/r%d in merged facet f%d\n",
  2140. pinched->id, vertex->id, dist, ridge->id, ridge2->id, facet->id));
  2141. }
  2142. qh_appendvertexmerge(qh, pinched, vertex, MRGvertices, dist, ridge, ridge2);
  2143. ridge->mergevertex= True; /* disables check for duplicate vertices in qh_checkfacet */
  2144. ridge2->mergevertex= True;
  2145. }
  2146. }
  2147. }
  2148. }
  2149. }
  2150. } /* maybe_duplicateridges */
  2151. /*-<a href="qh-merge_r.htm#TOC"
  2152. >-------------------------------</a><a name="maydropneighbor">-</a>
  2153. qh_maydropneighbor(qh, facet )
  2154. drop neighbor relationship if ridge was deleted between a non-simplicial facet and its neighbors
  2155. returns:
  2156. for deleted ridges
  2157. ridges made for simplicial neighbors
  2158. neighbor sets updated
  2159. appends degenerate facets to qh.facet_mergeset
  2160. notes:
  2161. called by qh_renamevertex
  2162. assumes neighbors do not include qh_MERGEridge (qh_makeridges)
  2163. won't cause redundant facets since vertex inclusion is the same
  2164. may drop vertex and neighbor if no ridge
  2165. uses qh.visit_id
  2166. design:
  2167. visit all neighbors with ridges
  2168. for each unvisited neighbor of facet
  2169. delete neighbor and facet from the non-simplicial neighbor sets
  2170. if neighbor becomes degenerate
  2171. append neighbor to qh.degen_mergeset
  2172. if facet is degenerate
  2173. append facet to qh.degen_mergeset
  2174. */
  2175. void qh_maydropneighbor(qhT *qh, facetT *facet) {
  2176. ridgeT *ridge, **ridgep;
  2177. facetT *neighbor, **neighborp;
  2178. qh->visit_id++;
  2179. trace4((qh, qh->ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
  2180. facet->id));
  2181. if (facet->simplicial) {
  2182. qh_fprintf(qh, qh->ferr, 6278, "qhull internal error (qh_maydropneighbor): not valid for simplicial f%d while adding furthest p%d\n",
  2183. facet->id, qh->furthest_id);
  2184. qh_errexit(qh, qh_ERRqhull, facet, NULL);
  2185. }
  2186. FOREACHridge_(facet->ridges) {
  2187. ridge->top->visitid= qh->visit_id;
  2188. ridge->bottom->visitid= qh->visit_id;
  2189. }
  2190. FOREACHneighbor_(facet) {
  2191. if (neighbor->visible) {
  2192. qh_fprintf(qh, qh->ferr, 6358, "qhull internal error (qh_maydropneighbor): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
  2193. facet->id, neighbor->id);
  2194. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  2195. }
  2196. if (neighbor->visitid != qh->visit_id) {
  2197. trace2((qh, qh->ferr, 2104, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors while adding furthest p%d\n",
  2198. facet->id, neighbor->id, qh->furthest_id));
  2199. if (neighbor->simplicial) {
  2200. qh_fprintf(qh, qh->ferr, 6280, "qhull internal error (qh_maydropneighbor): not valid for simplicial neighbor f%d of f%d while adding furthest p%d\n",
  2201. neighbor->id, facet->id, qh->furthest_id);
  2202. qh_errexit2(qh, qh_ERRqhull, neighbor, facet);
  2203. }
  2204. zinc_(Zdropneighbor);
  2205. qh_setdel(neighbor->neighbors, facet);
  2206. if (qh_setsize(qh, neighbor->neighbors) < qh->hull_dim) {
  2207. zinc_(Zdropdegen);
  2208. qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, qh_ANGLEnone);
  2209. trace2((qh, qh->ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
  2210. }
  2211. qh_setdel(facet->neighbors, neighbor);
  2212. neighborp--; /* repeat, deleted a neighbor */
  2213. }
  2214. }
  2215. if (qh_setsize(qh, facet->neighbors) < qh->hull_dim) {
  2216. zinc_(Zdropdegen);
  2217. qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, qh_ANGLEnone);
  2218. trace2((qh, qh->ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
  2219. }
  2220. } /* maydropneighbor */
  2221. /*-<a href="qh-merge_r.htm#TOC"
  2222. >-------------------------------</a><a name="merge_degenredundant">-</a>
  2223. qh_merge_degenredundant(qh)
  2224. merge all degenerate and redundant facets
  2225. qh.degen_mergeset contains merges from qh_test_degen_neighbors, qh_test_redundant_neighbors, and qh_degen_redundant_facet
  2226. returns:
  2227. number of merges performed
  2228. resets facet->degenerate/redundant
  2229. if deleted (visible) facet has no neighbors
  2230. sets ->f.replace to NULL
  2231. notes:
  2232. redundant merges happen before degenerate ones
  2233. merging and renaming vertices can result in degen/redundant facets
  2234. check for coplanar and convex neighbors afterwards
  2235. design:
  2236. for each merge on qh.degen_mergeset
  2237. if redundant merge
  2238. if non-redundant facet merged into redundant facet
  2239. recheck facet for redundancy
  2240. else
  2241. merge redundant facet into other facet
  2242. */
  2243. int qh_merge_degenredundant(qhT *qh) {
  2244. int size;
  2245. mergeT *merge;
  2246. facetT *bestneighbor, *facet1, *facet2, *facet3;
  2247. realT dist, mindist, maxdist;
  2248. vertexT *vertex, **vertexp;
  2249. int nummerges= 0;
  2250. mergeType mergetype;
  2251. setT *mergedfacets;
  2252. trace2((qh, qh->ferr, 2095, "qh_merge_degenredundant: merge %d degenerate, redundant, and mirror facets\n",
  2253. qh_setsize(qh, qh->degen_mergeset)));
  2254. mergedfacets= qh_settemp(qh, qh->TEMPsize);
  2255. while ((merge= (mergeT *)qh_setdellast(qh->degen_mergeset))) {
  2256. facet1= merge->facet1;
  2257. facet2= merge->facet2;
  2258. mergetype= merge->mergetype;
  2259. qh_memfree(qh, merge, (int)sizeof(mergeT)); /* 'merge' is invalidated */
  2260. if (facet1->visible)
  2261. continue;
  2262. facet1->degenerate= False;
  2263. facet1->redundant= False;
  2264. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  2265. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2266. if (mergetype == MRGredundant) {
  2267. zinc_(Zredundant);
  2268. facet3= qh_getreplacement(qh, facet2); /* the same facet if !facet2.visible */
  2269. if (!facet3) {
  2270. qh_fprintf(qh, qh->ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d is redundant but visible f%d has no replacement\n",
  2271. facet1->id, getid_(facet2));
  2272. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  2273. }
  2274. qh_setunique(qh, &mergedfacets, facet3);
  2275. if (facet1 == facet3) {
  2276. continue;
  2277. }
  2278. trace2((qh, qh->ferr, 2025, "qh_merge_degenredundant: merge redundant f%d into f%d (arg f%d)\n",
  2279. facet1->id, facet3->id, facet2->id));
  2280. qh_mergefacet(qh, facet1, facet3, mergetype, NULL, NULL, !qh_MERGEapex);
  2281. /* merge distance is already accounted for */
  2282. nummerges++;
  2283. }else { /* mergetype == MRGdegen or MRGmirror, other merges may have fixed */
  2284. if (!(size= qh_setsize(qh, facet1->neighbors))) {
  2285. zinc_(Zdelfacetdup);
  2286. trace2((qh, qh->ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors. Deleted\n", facet1->id));
  2287. qh_willdelete(qh, facet1, NULL);
  2288. FOREACHvertex_(facet1->vertices) {
  2289. qh_setdel(vertex->neighbors, facet1);
  2290. if (!SETfirst_(vertex->neighbors)) {
  2291. zinc_(Zdegenvertex);
  2292. trace2((qh, qh->ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
  2293. vertex->id, facet1->id));
  2294. vertex->deleted= True;
  2295. qh_setappend(qh, &qh->del_vertices, vertex);
  2296. }
  2297. }
  2298. nummerges++;
  2299. }else if (size < qh->hull_dim) {
  2300. bestneighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
  2301. trace2((qh, qh->ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
  2302. facet1->id, size, bestneighbor->id, dist));
  2303. qh_mergefacet(qh, facet1, bestneighbor, mergetype, &mindist, &maxdist, !qh_MERGEapex);
  2304. nummerges++;
  2305. if (qh->PRINTstatistics) {
  2306. zinc_(Zdegen);
  2307. wadd_(Wdegentot, dist);
  2308. wmax_(Wdegenmax, dist);
  2309. }
  2310. } /* else, another merge fixed the degeneracy and redundancy tested */
  2311. }
  2312. }
  2313. qh_settempfree(qh, &mergedfacets);
  2314. return nummerges;
  2315. } /* merge_degenredundant */
  2316. /*-<a href="qh-merge_r.htm#TOC"
  2317. >-------------------------------</a><a name="merge_nonconvex">-</a>
  2318. qh_merge_nonconvex(qh, facet1, facet2, mergetype )
  2319. remove non-convex ridge between facet1 into facet2
  2320. mergetype gives why the facet's are non-convex
  2321. returns:
  2322. merges one of the facets into the best neighbor
  2323. notes:
  2324. mergetype is MRGcoplanar..MRGconvex
  2325. design:
  2326. if one of the facets is a new facet
  2327. prefer merging new facet into old facet
  2328. find best neighbors for both facets
  2329. merge the nearest facet into its best neighbor
  2330. update the statistics
  2331. */
  2332. void qh_merge_nonconvex(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
  2333. facetT *bestfacet, *bestneighbor, *neighbor, *merging, *merged;
  2334. realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
  2335. if (mergetype < MRGcoplanar || mergetype > MRGconcavecoplanar) {
  2336. qh_fprintf(qh, qh->ferr, 6398, "qhull internal error (qh_merge_nonconvex): expecting mergetype MRGcoplanar..MRGconcavecoplanar. Got merge f%d and f%d type %d\n",
  2337. facet1->id, facet2->id, mergetype);
  2338. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  2339. }
  2340. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  2341. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2342. trace3((qh, qh->ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
  2343. zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
  2344. /* concave or coplanar */
  2345. if (!facet1->newfacet) {
  2346. bestfacet= facet2; /* avoid merging old facet if new is ok */
  2347. facet2= facet1;
  2348. facet1= bestfacet;
  2349. }else
  2350. bestfacet= facet1;
  2351. bestneighbor= qh_findbestneighbor(qh, bestfacet, &dist, &mindist, &maxdist);
  2352. neighbor= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
  2353. if (dist < dist2) {
  2354. merging= bestfacet;
  2355. merged= bestneighbor;
  2356. }else if (qh->AVOIDold && !facet2->newfacet
  2357. && ((mindist >= -qh->MAXcoplanar && maxdist <= qh->max_outside)
  2358. || dist * 1.5 < dist2)) {
  2359. zinc_(Zavoidold);
  2360. wadd_(Wavoidoldtot, dist);
  2361. wmax_(Wavoidoldmax, dist);
  2362. trace2((qh, qh->ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g. Use f%d dist %2.2g instead\n",
  2363. facet2->id, dist2, facet1->id, dist2));
  2364. merging= bestfacet;
  2365. merged= bestneighbor;
  2366. }else {
  2367. merging= facet2;
  2368. merged= neighbor;
  2369. dist= dist2;
  2370. mindist= mindist2;
  2371. maxdist= maxdist2;
  2372. }
  2373. qh_mergefacet(qh, merging, merged, mergetype, &mindist, &maxdist, !qh_MERGEapex);
  2374. /* caller merges qh_degenredundant */
  2375. if (qh->PRINTstatistics) {
  2376. if (mergetype == MRGanglecoplanar) {
  2377. zinc_(Zacoplanar);
  2378. wadd_(Wacoplanartot, dist);
  2379. wmax_(Wacoplanarmax, dist);
  2380. }else if (mergetype == MRGconcave) {
  2381. zinc_(Zconcave);
  2382. wadd_(Wconcavetot, dist);
  2383. wmax_(Wconcavemax, dist);
  2384. }else if (mergetype == MRGconcavecoplanar) {
  2385. zinc_(Zconcavecoplanar);
  2386. wadd_(Wconcavecoplanartot, dist);
  2387. wmax_(Wconcavecoplanarmax, dist);
  2388. }else { /* MRGcoplanar */
  2389. zinc_(Zcoplanar);
  2390. wadd_(Wcoplanartot, dist);
  2391. wmax_(Wcoplanarmax, dist);
  2392. }
  2393. }
  2394. } /* merge_nonconvex */
  2395. /*-<a href="qh-merge_r.htm#TOC"
  2396. >-------------------------------</a><a name="merge_pinchedvertices">-</a>
  2397. qh_merge_pinchedvertices(qh, apex )
  2398. merge pinched vertices in qh.vertex_mergeset to avoid qh_forcedmerges of dupridges
  2399. notes:
  2400. only called by qh_all_vertexmerges
  2401. hull_dim >= 3
  2402. design:
  2403. make vertex neighbors if necessary
  2404. for each pinched vertex
  2405. determine the ridges for the pinched vertex (make ridges as needed)
  2406. merge the pinched vertex into the horizon vertex
  2407. merge the degenerate and redundant facets that result
  2408. check and resolve new dupridges
  2409. */
  2410. void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
  2411. mergeT *merge, *mergeA, **mergeAp;
  2412. vertexT *vertex, *vertex2;
  2413. realT dist;
  2414. boolT firstmerge= True;
  2415. qh_vertexneighbors(qh);
  2416. if (qh->visible_list || qh->newfacet_list || qh->newvertex_list) {
  2417. qh_fprintf(qh, qh->ferr, 6402, "qhull internal error (qh_merge_pinchedvertices): qh.visible_list (f%d), newfacet_list (f%d), or newvertex_list (v%d) not empty\n",
  2418. getid_(qh->visible_list), getid_(qh->newfacet_list), getid_(qh->newvertex_list));
  2419. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  2420. }
  2421. qh->visible_list= qh->newfacet_list= qh->facet_tail;
  2422. qh->newvertex_list= qh->vertex_tail;
  2423. qh->isRenameVertex= True; /* disable duplicate ridge vertices check in qh_checkfacet */
  2424. while ((merge= qh_next_vertexmerge(qh /* qh.vertex_mergeset */))) { /* only one at a time from qh_getpinchedmerges */
  2425. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  2426. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2427. if (merge->mergetype == MRGsubridge) {
  2428. zzinc_(Zpinchedvertex);
  2429. trace1((qh, qh->ferr, 1050, "qh_merge_pinchedvertices: merge one of %d pinched vertices before adding apex p%d. Try to resolve duplicate ridges in newfacets\n",
  2430. qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
  2431. qh_remove_mergetype(qh, qh->vertex_mergeset, MRGsubridge);
  2432. }else {
  2433. zzinc_(Zpinchduplicate);
  2434. if (firstmerge)
  2435. trace1((qh, qh->ferr, 1056, "qh_merge_pinchedvertices: merge %d pinched vertices from dupridges in merged facets, apex p%d\n",
  2436. qh_setsize(qh, qh->vertex_mergeset)+1, apexpointid));
  2437. firstmerge= False;
  2438. }
  2439. vertex= merge->vertex1;
  2440. vertex2= merge->vertex2;
  2441. dist= merge->distance;
  2442. qh_memfree(qh, merge, (int)sizeof(mergeT)); /* merge is invalidated */
  2443. qh_rename_adjacentvertex(qh, vertex, vertex2, dist);
  2444. #ifndef qh_NOtrace
  2445. if (qh->IStracing >= 2) {
  2446. FOREACHmergeA_(qh->degen_mergeset) {
  2447. if (mergeA->mergetype== MRGdegen) {
  2448. qh_fprintf(qh, qh->ferr, 2072, "qh_merge_pinchedvertices: merge degenerate f%d into an adjacent facet\n", mergeA->facet1->id);
  2449. }else {
  2450. qh_fprintf(qh, qh->ferr, 2084, "qh_merge_pinchedvertices: merge f%d into f%d mergeType %d\n", mergeA->facet1->id, mergeA->facet2->id, mergeA->mergetype);
  2451. }
  2452. }
  2453. }
  2454. #endif
  2455. qh_merge_degenredundant(qh); /* simplicial facets with both old and new vertices */
  2456. }
  2457. qh->isRenameVertex= False;
  2458. }/* merge_pinchedvertices */
  2459. /*-<a href="qh-merge_r.htm#TOC"
  2460. >-------------------------------</a><a name="merge_twisted">-</a>
  2461. qh_merge_twisted(qh, facet1, facet2 )
  2462. remove twisted ridge between facet1 into facet2 or report error
  2463. returns:
  2464. merges one of the facets into the best neighbor
  2465. notes:
  2466. a twisted ridge has opposite vertices that are convex and concave
  2467. design:
  2468. find best neighbors for both facets
  2469. error if wide merge
  2470. merge the nearest facet into its best neighbor
  2471. update statistics
  2472. */
  2473. void qh_merge_twisted(qhT *qh, facetT *facet1, facetT *facet2) {
  2474. facetT *neighbor2, *neighbor, *merging, *merged;
  2475. vertexT *bestvertex, *bestpinched;
  2476. realT dist, dist2, mindist, mindist2, maxdist, maxdist2, mintwisted, bestdist;
  2477. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  2478. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2479. trace3((qh, qh->ferr, 3050, "qh_merge_twisted: merge #%d for twisted f%d and f%d\n",
  2480. zzval_(Ztotmerge) + 1, facet1->id, facet2->id));
  2481. /* twisted */
  2482. neighbor= qh_findbestneighbor(qh, facet1, &dist, &mindist, &maxdist);
  2483. neighbor2= qh_findbestneighbor(qh, facet2, &dist2, &mindist2, &maxdist2);
  2484. mintwisted= qh_RATIOtwisted * qh->ONEmerge;
  2485. maximize_(mintwisted, facet1->maxoutside);
  2486. maximize_(mintwisted, facet2->maxoutside);
  2487. if (dist > mintwisted && dist2 > mintwisted) {
  2488. bestdist= qh_vertex_bestdist2(qh, facet1->vertices, &bestvertex, &bestpinched);
  2489. if (bestdist > mintwisted) {
  2490. qh_fprintf(qh, qh->ferr, 6417, "qhull precision error (qh_merge_twisted): twisted facet f%d does not contain pinched vertices. Too wide to merge into neighbor. mindist %2.2g maxdist %2.2g vertexdist %2.2g maxpinched %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
  2491. facet1->id, mindist, maxdist, bestdist, mintwisted, facet2->id, mindist2, maxdist2);
  2492. }else {
  2493. qh_fprintf(qh, qh->ferr, 6418, "qhull precision error (qh_merge_twisted): twisted facet f%d with pinched vertices. Could merge vertices, but too wide to merge into neighbor. mindist %2.2g maxdist %2.2g vertexdist %2.2g neighbor f%d mindist %2.2g maxdist %2.2g\n",
  2494. facet1->id, mindist, maxdist, bestdist, facet2->id, mindist2, maxdist2);
  2495. }
  2496. qh_errexit2(qh, qh_ERRwide, facet1, facet2);
  2497. }
  2498. if (dist < dist2) {
  2499. merging= facet1;
  2500. merged= neighbor;
  2501. }else {
  2502. /* ignores qh.AVOIDold ('Q4') */
  2503. merging= facet2;
  2504. merged= neighbor2;
  2505. dist= dist2;
  2506. mindist= mindist2;
  2507. maxdist= maxdist2;
  2508. }
  2509. qh_mergefacet(qh, merging, merged, MRGtwisted, &mindist, &maxdist, !qh_MERGEapex);
  2510. /* caller merges qh_degenredundant */
  2511. zinc_(Ztwisted);
  2512. wadd_(Wtwistedtot, dist);
  2513. wmax_(Wtwistedmax, dist);
  2514. } /* merge_twisted */
  2515. /*-<a href="qh-merge_r.htm#TOC"
  2516. >-------------------------------</a><a name="mergecycle">-</a>
  2517. qh_mergecycle(qh, samecycle, newfacet )
  2518. merge a cycle of facets starting at samecycle into a newfacet
  2519. newfacet is a horizon facet with ->normal
  2520. samecycle facets are simplicial from an apex
  2521. returns:
  2522. initializes vertex neighbors on first merge
  2523. samecycle deleted (placed on qh.visible_list)
  2524. newfacet at end of qh.facet_list
  2525. deleted vertices on qh.del_vertices
  2526. notes:
  2527. only called by qh_mergecycle_all for multiple, same cycle facets
  2528. see qh_mergefacet
  2529. design:
  2530. make vertex neighbors if necessary
  2531. make ridges for newfacet
  2532. merge neighbor sets of samecycle into newfacet
  2533. merge ridges of samecycle into newfacet
  2534. merge vertex neighbors of samecycle into newfacet
  2535. make apex of samecycle the apex of newfacet
  2536. if newfacet wasn't a new facet
  2537. add its vertices to qh.newvertex_list
  2538. delete samecycle facets a make newfacet a newfacet
  2539. */
  2540. void qh_mergecycle(qhT *qh, facetT *samecycle, facetT *newfacet) {
  2541. int traceonce= False, tracerestore= 0;
  2542. vertexT *apex;
  2543. #ifndef qh_NOtrace
  2544. facetT *same;
  2545. #endif
  2546. zzinc_(Ztotmerge);
  2547. if (qh->REPORTfreq2 && qh->POSTmerging) {
  2548. if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
  2549. qh_tracemerging(qh);
  2550. }
  2551. #ifndef qh_NOtrace
  2552. if (qh->TRACEmerge == zzval_(Ztotmerge))
  2553. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2554. trace2((qh, qh->ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n",
  2555. zzval_(Ztotmerge), samecycle->id, newfacet->id));
  2556. if (newfacet == qh->tracefacet) {
  2557. tracerestore= qh->IStracing;
  2558. qh->IStracing= 4;
  2559. qh_fprintf(qh, qh->ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
  2560. zzval_(Ztotmerge), samecycle->id, newfacet->id, qh->furthest_id);
  2561. traceonce= True;
  2562. }
  2563. if (qh->IStracing >=4) {
  2564. qh_fprintf(qh, qh->ferr, 8069, " same cycle:");
  2565. FORALLsame_cycle_(samecycle)
  2566. qh_fprintf(qh, qh->ferr, 8070, " f%d", same->id);
  2567. qh_fprintf(qh, qh->ferr, 8071, "\n");
  2568. }
  2569. if (qh->IStracing >=4)
  2570. qh_errprint(qh, "MERGING CYCLE", samecycle, newfacet, NULL, NULL);
  2571. #endif /* !qh_NOtrace */
  2572. if (newfacet->tricoplanar) {
  2573. if (!qh->TRInormals) {
  2574. qh_fprintf(qh, qh->ferr, 6224, "qhull internal error (qh_mergecycle): does not work for tricoplanar facets. Use option 'Q11'\n");
  2575. qh_errexit(qh, qh_ERRqhull, newfacet, NULL);
  2576. }
  2577. newfacet->tricoplanar= False;
  2578. newfacet->keepcentrum= False;
  2579. }
  2580. if (qh->CHECKfrequently)
  2581. qh_checkdelridge(qh);
  2582. if (!qh->VERTEXneighbors)
  2583. qh_vertexneighbors(qh);
  2584. apex= SETfirstt_(samecycle->vertices, vertexT);
  2585. qh_makeridges(qh, newfacet);
  2586. qh_mergecycle_neighbors(qh, samecycle, newfacet);
  2587. qh_mergecycle_ridges(qh, samecycle, newfacet);
  2588. qh_mergecycle_vneighbors(qh, samecycle, newfacet);
  2589. if (SETfirstt_(newfacet->vertices, vertexT) != apex)
  2590. qh_setaddnth(qh, &newfacet->vertices, 0, apex); /* apex has last id */
  2591. if (!newfacet->newfacet)
  2592. qh_newvertices(qh, newfacet->vertices);
  2593. qh_mergecycle_facets(qh, samecycle, newfacet);
  2594. qh_tracemerge(qh, samecycle, newfacet, MRGcoplanarhorizon);
  2595. /* check for degen_redundant_neighbors after qh_forcedmerges() */
  2596. if (traceonce) {
  2597. qh_fprintf(qh, qh->ferr, 8072, "qh_mergecycle: end of trace facet\n");
  2598. qh->IStracing= tracerestore;
  2599. }
  2600. } /* mergecycle */
  2601. /*-<a href="qh-merge_r.htm#TOC"
  2602. >-------------------------------</a><a name="mergecycle_all">-</a>
  2603. qh_mergecycle_all(qh, facetlist, wasmerge )
  2604. merge all samecycles of coplanar facets into horizon
  2605. don't merge facets with ->mergeridge (these already have ->normal)
  2606. all facets are simplicial from apex
  2607. all facet->cycledone == False
  2608. returns:
  2609. all newfacets merged into coplanar horizon facets
  2610. deleted vertices on qh.del_vertices
  2611. sets wasmerge if any merge
  2612. notes:
  2613. called by qh_premerge
  2614. calls qh_mergecycle for multiple, same cycle facets
  2615. design:
  2616. for each facet on facetlist
  2617. skip facets with dupridges and normals
  2618. check that facet is in a samecycle (->mergehorizon)
  2619. if facet only member of samecycle
  2620. sets vertex->delridge for all vertices except apex
  2621. merge facet into horizon
  2622. else
  2623. mark all facets in samecycle
  2624. remove facets with dupridges from samecycle
  2625. merge samecycle into horizon (deletes facets from facetlist)
  2626. */
  2627. void qh_mergecycle_all(qhT *qh, facetT *facetlist, boolT *wasmerge) {
  2628. facetT *facet, *same, *prev, *horizon, *newfacet;
  2629. facetT *samecycle= NULL, *nextfacet, *nextsame;
  2630. vertexT *apex, *vertex, **vertexp;
  2631. int cycles=0, total=0, facets, nummerge, numdegen= 0;
  2632. trace2((qh, qh->ferr, 2031, "qh_mergecycle_all: merge new facets into coplanar horizon facets. Bulk merge a cycle of facets with the same horizon facet\n"));
  2633. for (facet=facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
  2634. if (facet->normal)
  2635. continue;
  2636. if (!facet->mergehorizon) {
  2637. qh_fprintf(qh, qh->ferr, 6225, "qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id);
  2638. qh_errexit(qh, qh_ERRqhull, facet, NULL);
  2639. }
  2640. horizon= SETfirstt_(facet->neighbors, facetT);
  2641. if (facet->f.samecycle == facet) {
  2642. if (qh->TRACEmerge-1 == zzval_(Ztotmerge))
  2643. qh->qhmem.IStracing= qh->IStracing= qh->TRACElevel;
  2644. zinc_(Zonehorizon);
  2645. /* merge distance done in qh_findhorizon */
  2646. apex= SETfirstt_(facet->vertices, vertexT);
  2647. FOREACHvertex_(facet->vertices) {
  2648. if (vertex != apex)
  2649. vertex->delridge= True;
  2650. }
  2651. horizon->f.newcycle= NULL;
  2652. qh_mergefacet(qh, facet, horizon, MRGcoplanarhorizon, NULL, NULL, qh_MERGEapex);
  2653. }else {
  2654. samecycle= facet;
  2655. facets= 0;
  2656. prev= facet;
  2657. for (same= facet->f.samecycle; same; /* FORALLsame_cycle_(facet) */
  2658. same= (same == facet ? NULL :nextsame)) { /* ends at facet */
  2659. nextsame= same->f.samecycle;
  2660. if (same->cycledone || same->visible)
  2661. qh_infiniteloop(qh, same);
  2662. same->cycledone= True;
  2663. if (same->normal) {
  2664. prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
  2665. same->f.samecycle= NULL;
  2666. }else {
  2667. prev= same;
  2668. facets++;
  2669. }
  2670. }
  2671. while (nextfacet && nextfacet->cycledone) /* will delete samecycle */
  2672. nextfacet= nextfacet->next;
  2673. horizon->f.newcycle= NULL;
  2674. qh_mergecycle(qh, samecycle, horizon);
  2675. nummerge= horizon->nummerge + facets;
  2676. if (nummerge > qh_MAXnummerge)
  2677. horizon->nummerge= qh_MAXnummerge;
  2678. else
  2679. horizon->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
  2680. zzinc_(Zcyclehorizon);
  2681. total += facets;
  2682. zzadd_(Zcyclefacettot, facets);
  2683. zmax_(Zcyclefacetmax, facets);
  2684. }
  2685. cycles++;
  2686. }
  2687. if (cycles) {
  2688. FORALLnew_facets {
  2689. /* qh_maybe_duplicateridges postponed since qh_mergecycle_ridges deletes ridges without calling qh_delridge_merge */
  2690. if (newfacet->coplanarhorizon) {
  2691. qh_test_redundant_neighbors(qh, newfacet);
  2692. qh_maybe_duplicateridges(qh, newfacet);
  2693. newfacet->coplanarhorizon= False;
  2694. }
  2695. }
  2696. numdegen += qh_merge_degenredundant(qh);
  2697. *wasmerge= True;
  2698. trace1((qh, qh->ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons and %d degenredundant facets\n",
  2699. cycles, numdegen));
  2700. }
  2701. } /* mergecycle_all */
  2702. /*-<a href="qh-merge_r.htm#TOC"
  2703. >-------------------------------</a><a name="mergecycle_facets">-</a>
  2704. qh_mergecycle_facets(qh, samecycle, newfacet )
  2705. finish merge of samecycle into newfacet
  2706. returns:
  2707. samecycle prepended to visible_list for later deletion and partitioning
  2708. each facet->f.replace == newfacet
  2709. newfacet moved to end of qh.facet_list
  2710. makes newfacet a newfacet (get's facet1->id if it was old)
  2711. sets newfacet->newmerge
  2712. clears newfacet->center (unless merging into a large facet)
  2713. clears newfacet->tested and ridge->tested for facet1
  2714. adds neighboring facets to facet_mergeset if redundant or degenerate
  2715. design:
  2716. make newfacet a new facet and set its flags
  2717. move samecycle facets to qh.visible_list for later deletion
  2718. unless newfacet is large
  2719. remove its centrum
  2720. */
  2721. void qh_mergecycle_facets(qhT *qh, facetT *samecycle, facetT *newfacet) {
  2722. facetT *same, *next;
  2723. trace4((qh, qh->ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));
  2724. qh_removefacet(qh, newfacet); /* append as a newfacet to end of qh->facet_list */
  2725. qh_appendfacet(qh, newfacet);
  2726. newfacet->newfacet= True;
  2727. newfacet->simplicial= False;
  2728. newfacet->newmerge= True;
  2729. for (same= samecycle->f.samecycle; same; same= (same == samecycle ? NULL : next)) {
  2730. next= same->f.samecycle; /* reused by willdelete */
  2731. qh_willdelete(qh, same, newfacet);
  2732. }
  2733. if (newfacet->center
  2734. && qh_setsize(qh, newfacet->vertices) <= qh->hull_dim + qh_MAXnewcentrum) {
  2735. qh_memfree(qh, newfacet->center, qh->normal_size);
  2736. newfacet->center= NULL;
  2737. }
  2738. trace3((qh, qh->ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n",
  2739. samecycle->id, newfacet->id));
  2740. } /* mergecycle_facets */
  2741. /*-<a href="qh-merge_r.htm#TOC"
  2742. >-------------------------------</a><a name="mergecycle_neighbors">-</a>
  2743. qh_mergecycle_neighbors(qh, samecycle, newfacet )
  2744. add neighbors for samecycle facets to newfacet
  2745. returns:
  2746. newfacet with updated neighbors and vice-versa
  2747. newfacet has ridges
  2748. all neighbors of newfacet marked with qh.visit_id
  2749. samecycle facets marked with qh.visit_id-1
  2750. ridges updated for simplicial neighbors of samecycle with a ridge
  2751. notes:
  2752. assumes newfacet not in samecycle
  2753. usually, samecycle facets are new, simplicial facets without internal ridges
  2754. not so if horizon facet is coplanar to two different samecycles
  2755. see:
  2756. qh_mergeneighbors()
  2757. design:
  2758. check samecycle
  2759. delete neighbors from newfacet that are also in samecycle
  2760. for each neighbor of a facet in samecycle
  2761. if neighbor is simplicial
  2762. if first visit
  2763. move the neighbor relation to newfacet
  2764. update facet links for its ridges
  2765. else
  2766. make ridges for neighbor
  2767. remove samecycle reference
  2768. else
  2769. update neighbor sets
  2770. */
  2771. void qh_mergecycle_neighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
  2772. facetT *same, *neighbor, **neighborp;
  2773. int delneighbors= 0, newneighbors= 0;
  2774. unsigned int samevisitid;
  2775. ridgeT *ridge, **ridgep;
  2776. samevisitid= ++qh->visit_id;
  2777. FORALLsame_cycle_(samecycle) {
  2778. if (same->visitid == samevisitid || same->visible)
  2779. qh_infiniteloop(qh, samecycle);
  2780. same->visitid= samevisitid;
  2781. }
  2782. newfacet->visitid= ++qh->visit_id;
  2783. trace4((qh, qh->ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));
  2784. FOREACHneighbor_(newfacet) {
  2785. if (neighbor->visitid == samevisitid) {
  2786. SETref_(neighbor)= NULL; /* samecycle neighbors deleted */
  2787. delneighbors++;
  2788. }else
  2789. neighbor->visitid= qh->visit_id;
  2790. }
  2791. qh_setcompact(qh, newfacet->neighbors);
  2792. trace4((qh, qh->ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n"));
  2793. FORALLsame_cycle_(samecycle) {
  2794. FOREACHneighbor_(same) {
  2795. if (neighbor->visitid == samevisitid)
  2796. continue;
  2797. if (neighbor->simplicial) {
  2798. if (neighbor->visitid != qh->visit_id) {
  2799. qh_setappend(qh, &newfacet->neighbors, neighbor);
  2800. qh_setreplace(qh, neighbor->neighbors, same, newfacet);
  2801. newneighbors++;
  2802. neighbor->visitid= qh->visit_id;
  2803. FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
  2804. if (ridge->top == same) {
  2805. ridge->top= newfacet;
  2806. break;
  2807. }else if (ridge->bottom == same) {
  2808. ridge->bottom= newfacet;
  2809. break;
  2810. }
  2811. }
  2812. }else {
  2813. qh_makeridges(qh, neighbor);
  2814. qh_setdel(neighbor->neighbors, same);
  2815. /* same can't be horizon facet for neighbor */
  2816. }
  2817. }else { /* non-simplicial neighbor */
  2818. qh_setdel(neighbor->neighbors, same);
  2819. if (neighbor->visitid != qh->visit_id) {
  2820. qh_setappend(qh, &neighbor->neighbors, newfacet);
  2821. qh_setappend(qh, &newfacet->neighbors, neighbor);
  2822. neighbor->visitid= qh->visit_id;
  2823. newneighbors++;
  2824. }
  2825. }
  2826. }
  2827. }
  2828. trace2((qh, qh->ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n",
  2829. delneighbors, newneighbors));
  2830. } /* mergecycle_neighbors */
  2831. /*-<a href="qh-merge_r.htm#TOC"
  2832. >-------------------------------</a><a name="mergecycle_ridges">-</a>
  2833. qh_mergecycle_ridges(qh, samecycle, newfacet )
  2834. add ridges/neighbors for facets in samecycle to newfacet
  2835. all new/old neighbors of newfacet marked with qh.visit_id
  2836. facets in samecycle marked with qh.visit_id-1
  2837. newfacet marked with qh.visit_id
  2838. returns:
  2839. newfacet has merged ridges
  2840. notes:
  2841. ridge already updated for simplicial neighbors of samecycle with a ridge
  2842. qh_checkdelridge called by qh_mergecycle
  2843. see:
  2844. qh_mergeridges()
  2845. qh_makeridges()
  2846. design:
  2847. remove ridges between newfacet and samecycle
  2848. for each facet in samecycle
  2849. for each ridge in facet
  2850. update facet pointers in ridge
  2851. skip ridges processed in qh_mergecycle_neighors
  2852. free ridges between newfacet and samecycle
  2853. free ridges between facets of samecycle (on 2nd visit)
  2854. append remaining ridges to newfacet
  2855. if simplicial facet
  2856. for each neighbor of facet
  2857. if simplicial facet
  2858. and not samecycle facet or newfacet
  2859. make ridge between neighbor and newfacet
  2860. */
  2861. void qh_mergecycle_ridges(qhT *qh, facetT *samecycle, facetT *newfacet) {
  2862. facetT *same, *neighbor= NULL;
  2863. int numold=0, numnew=0;
  2864. int neighbor_i, neighbor_n;
  2865. unsigned int samevisitid;
  2866. ridgeT *ridge, **ridgep;
  2867. boolT toporient;
  2868. void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
  2869. trace4((qh, qh->ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));
  2870. samevisitid= qh->visit_id -1;
  2871. FOREACHridge_(newfacet->ridges) {
  2872. neighbor= otherfacet_(ridge, newfacet);
  2873. if (neighbor->visitid == samevisitid)
  2874. SETref_(ridge)= NULL; /* ridge free'd below */
  2875. }
  2876. qh_setcompact(qh, newfacet->ridges);
  2877. trace4((qh, qh->ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n"));
  2878. FORALLsame_cycle_(samecycle) {
  2879. FOREACHridge_(same->ridges) {
  2880. if (ridge->top == same) {
  2881. ridge->top= newfacet;
  2882. neighbor= ridge->bottom;
  2883. }else if (ridge->bottom == same) {
  2884. ridge->bottom= newfacet;
  2885. neighbor= ridge->top;
  2886. }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
  2887. qh_setappend(qh, &newfacet->ridges, ridge);
  2888. numold++; /* already set by qh_mergecycle_neighbors */
  2889. continue;
  2890. }else {
  2891. qh_fprintf(qh, qh->ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
  2892. qh_errexit(qh, qh_ERRqhull, NULL, ridge);
  2893. }
  2894. if (neighbor == newfacet) {
  2895. if (qh->traceridge == ridge)
  2896. qh->traceridge= NULL;
  2897. qh_setfree(qh, &(ridge->vertices));
  2898. qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
  2899. numold++;
  2900. }else if (neighbor->visitid == samevisitid) {
  2901. qh_setdel(neighbor->ridges, ridge);
  2902. if (qh->traceridge == ridge)
  2903. qh->traceridge= NULL;
  2904. qh_setfree(qh, &(ridge->vertices));
  2905. qh_memfree_(qh, ridge, (int)sizeof(ridgeT), freelistp);
  2906. numold++;
  2907. }else {
  2908. qh_setappend(qh, &newfacet->ridges, ridge);
  2909. numold++;
  2910. }
  2911. }
  2912. if (same->ridges)
  2913. qh_settruncate(qh, same->ridges, 0);
  2914. if (!same->simplicial)
  2915. continue;
  2916. FOREACHneighbor_i_(qh, same) { /* note: !newfact->simplicial */
  2917. if (neighbor->visitid != samevisitid && neighbor->simplicial) {
  2918. ridge= qh_newridge(qh);
  2919. ridge->vertices= qh_setnew_delnthsorted(qh, same->vertices, qh->hull_dim,
  2920. neighbor_i, 0);
  2921. toporient= (boolT)(same->toporient ^ (neighbor_i & 0x1));
  2922. if (toporient) {
  2923. ridge->top= newfacet;
  2924. ridge->bottom= neighbor;
  2925. ridge->simplicialbot= True;
  2926. }else {
  2927. ridge->top= neighbor;
  2928. ridge->bottom= newfacet;
  2929. ridge->simplicialtop= True;
  2930. }
  2931. qh_setappend(qh, &(newfacet->ridges), ridge);
  2932. qh_setappend(qh, &(neighbor->ridges), ridge);
  2933. if (qh->ridge_id == qh->traceridge_id)
  2934. qh->traceridge= ridge;
  2935. numnew++;
  2936. }
  2937. }
  2938. }
  2939. trace2((qh, qh->ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n",
  2940. numold, numnew));
  2941. } /* mergecycle_ridges */
  2942. /*-<a href="qh-merge_r.htm#TOC"
  2943. >-------------------------------</a><a name="mergecycle_vneighbors">-</a>
  2944. qh_mergecycle_vneighbors(qh, samecycle, newfacet )
  2945. create vertex neighbors for newfacet from vertices of facets in samecycle
  2946. samecycle marked with visitid == qh.visit_id - 1
  2947. returns:
  2948. newfacet vertices with updated neighbors
  2949. marks newfacet with qh.visit_id-1
  2950. deletes vertices that are merged away
  2951. sets delridge on all vertices (faster here than in mergecycle_ridges)
  2952. see:
  2953. qh_mergevertex_neighbors()
  2954. design:
  2955. for each vertex of samecycle facet
  2956. set vertex->delridge
  2957. delete samecycle facets from vertex neighbors
  2958. append newfacet to vertex neighbors
  2959. if vertex only in newfacet
  2960. delete it from newfacet
  2961. add it to qh.del_vertices for later deletion
  2962. */
  2963. void qh_mergecycle_vneighbors(qhT *qh, facetT *samecycle, facetT *newfacet) {
  2964. facetT *neighbor, **neighborp;
  2965. unsigned int mergeid;
  2966. vertexT *vertex, **vertexp, *apex;
  2967. setT *vertices;
  2968. trace4((qh, qh->ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));
  2969. mergeid= qh->visit_id - 1;
  2970. newfacet->visitid= mergeid;
  2971. vertices= qh_basevertices(qh, samecycle); /* temp */
  2972. apex= SETfirstt_(samecycle->vertices, vertexT);
  2973. qh_setappend(qh, &vertices, apex);
  2974. FOREACHvertex_(vertices) {
  2975. vertex->delridge= True;
  2976. FOREACHneighbor_(vertex) {
  2977. if (neighbor->visitid == mergeid)
  2978. SETref_(neighbor)= NULL;
  2979. }
  2980. qh_setcompact(qh, vertex->neighbors);
  2981. qh_setappend(qh, &vertex->neighbors, newfacet);
  2982. if (!SETsecond_(vertex->neighbors)) {
  2983. zinc_(Zcyclevertex);
  2984. trace2((qh, qh->ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
  2985. vertex->id, samecycle->id, newfacet->id));
  2986. qh_setdelsorted(newfacet->vertices, vertex);
  2987. vertex->deleted= True;
  2988. qh_setappend(qh, &qh->del_vertices, vertex);
  2989. }
  2990. }
  2991. qh_settempfree(qh, &vertices);
  2992. trace3((qh, qh->ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n",
  2993. samecycle->id, newfacet->id));
  2994. } /* mergecycle_vneighbors */
  2995. /*-<a href="qh-merge_r.htm#TOC"
  2996. >-------------------------------</a><a name="mergefacet">-</a>
  2997. qh_mergefacet(qh, facet1, facet2, mergetype, mindist, maxdist, mergeapex )
  2998. merges facet1 into facet2
  2999. mergeapex==qh_MERGEapex if merging new facet into coplanar horizon (optimizes qh_mergesimplex)
  3000. returns:
  3001. qh.max_outside and qh.min_vertex updated
  3002. initializes vertex neighbors on first merge
  3003. note:
  3004. mergetype only used for logging and error reporting
  3005. returns:
  3006. facet2 contains facet1's vertices, neighbors, and ridges
  3007. facet2 moved to end of qh.facet_list
  3008. makes facet2 a newfacet
  3009. sets facet2->newmerge set
  3010. clears facet2->center (unless merging into a large facet)
  3011. clears facet2->tested and ridge->tested for facet1
  3012. facet1 prepended to visible_list for later deletion and partitioning
  3013. facet1->f.replace == facet2
  3014. adds neighboring facets to facet_mergeset if redundant or degenerate
  3015. notes:
  3016. when done, tests facet1 and facet2 for degenerate or redundant neighbors and dupridges
  3017. mindist/maxdist may be NULL (only if both NULL)
  3018. traces merge if fmax_(maxdist,-mindist) > TRACEdist
  3019. see:
  3020. qh_mergecycle()
  3021. design:
  3022. trace merge and check for degenerate simplex
  3023. make ridges for both facets
  3024. update qh.max_outside, qh.max_vertex, qh.min_vertex
  3025. update facet2->maxoutside and keepcentrum
  3026. update facet2->nummerge
  3027. update tested flags for facet2
  3028. if facet1 is simplicial
  3029. merge facet1 into facet2
  3030. else
  3031. merge facet1's neighbors into facet2
  3032. merge facet1's ridges into facet2
  3033. merge facet1's vertices into facet2
  3034. merge facet1's vertex neighbors into facet2
  3035. add facet2's vertices to qh.new_vertexlist
  3036. move facet2 to end of qh.newfacet_list
  3037. unless MRGcoplanarhorizon
  3038. test facet2 for redundant neighbors
  3039. test facet1 for degenerate neighbors
  3040. test for redundant facet2
  3041. maybe test for duplicate ridges ('Q15')
  3042. move facet1 to qh.visible_list for later deletion
  3043. */
  3044. void qh_mergefacet(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype, realT *mindist, realT *maxdist, boolT mergeapex) {
  3045. boolT traceonce= False;
  3046. vertexT *vertex, **vertexp;
  3047. realT mintwisted, vertexdist;
  3048. realT onemerge;
  3049. int tracerestore=0, nummerge;
  3050. const char *mergename;
  3051. if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
  3052. mergename= mergetypes[mergetype];
  3053. else
  3054. mergename= mergetypes[MRGnone];
  3055. if (facet1->tricoplanar || facet2->tricoplanar) {
  3056. if (!qh->TRInormals) {
  3057. qh_fprintf(qh, qh->ferr, 6226, "qhull internal error (qh_mergefacet): merge f%d into f%d for mergetype %d (%s) does not work for tricoplanar facets. Use option 'Q11'\n",
  3058. facet1->id, facet2->id, mergetype, mergename);
  3059. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  3060. }
  3061. if (facet2->tricoplanar) {
  3062. facet2->tricoplanar= False;
  3063. facet2->keepcentrum= False;
  3064. }
  3065. }
  3066. zzinc_(Ztotmerge);
  3067. if (qh->REPORTfreq2 && qh->POSTmerging) {
  3068. if (zzval_(Ztotmerge) > qh->mergereport + qh->REPORTfreq2)
  3069. qh_tracemerging(qh);
  3070. }
  3071. #ifndef qh_NOtrace
  3072. if (qh->build_cnt >= qh->RERUN) {
  3073. if (mindist && (-*mindist > qh->TRACEdist || *maxdist > qh->TRACEdist)) {
  3074. tracerestore= 0;
  3075. qh->IStracing= qh->TRACElevel;
  3076. traceonce= True;
  3077. qh_fprintf(qh, qh->ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d for mergetype %d (%s), last point was p%d\n",
  3078. zzval_(Ztotmerge), fmax_(-*mindist, *maxdist), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
  3079. }else if (facet1 == qh->tracefacet || facet2 == qh->tracefacet) {
  3080. tracerestore= qh->IStracing;
  3081. qh->IStracing= 4;
  3082. traceonce= True;
  3083. qh_fprintf(qh, qh->ferr, 8076, "qh_mergefacet: ========= trace merge #%d for f%d into f%d for mergetype %d (%s), furthest is p%d\n",
  3084. zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
  3085. }
  3086. }
  3087. if (qh->IStracing >= 2) {
  3088. realT mergemin= -2;
  3089. realT mergemax= -2;
  3090. if (mindist) {
  3091. mergemin= *mindist;
  3092. mergemax= *maxdist;
  3093. }
  3094. qh_fprintf(qh, qh->ferr, 2081, "qh_mergefacet: #%d merge f%d into f%d for merge for mergetype %d (%s), mindist= %2.2g, maxdist= %2.2g, max_outside %2.2g\n",
  3095. zzval_(Ztotmerge), facet1->id, facet2->id, mergetype, mergename, mergemin, mergemax, qh->max_outside);
  3096. }
  3097. #endif /* !qh_NOtrace */
  3098. if(!qh->ALLOWwide && mindist) {
  3099. mintwisted= qh_WIDEmaxoutside * qh->ONEmerge; /* same as qh_merge_twisted and qh_check_maxout (poly2) */
  3100. maximize_(mintwisted, facet1->maxoutside);
  3101. maximize_(mintwisted, facet2->maxoutside);
  3102. if (*maxdist > mintwisted || -*mindist > mintwisted) {
  3103. vertexdist= qh_vertex_bestdist(qh, facet1->vertices);
  3104. onemerge= qh->ONEmerge + qh->DISTround;
  3105. if (vertexdist > mintwisted) {
  3106. qh_fprintf(qh, qh->ferr, 6347, "qhull precision error (qh_mergefacet): wide merge for facet f%d into f%d for mergetype %d (%s). maxdist %2.2g (%.1fx) mindist %2.2g (%.1fx) vertexdist %2.2g Allow with 'Q12' (allow-wide)\n",
  3107. facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
  3108. }else {
  3109. qh_fprintf(qh, qh->ferr, 6348, "qhull precision error (qh_mergefacet): wide merge for pinched facet f%d into f%d for mergetype %d (%s). maxdist %2.2g (%.fx) mindist %2.2g (%.1fx) vertexdist %2.2g Allow with 'Q12' (allow-wide)\n",
  3110. facet1->id, facet2->id, mergetype, mergename, *maxdist, *maxdist/onemerge, *mindist, -*mindist/onemerge, vertexdist);
  3111. }
  3112. qh_errexit2(qh, qh_ERRwide, facet1, facet2);
  3113. }
  3114. }
  3115. if (facet1 == facet2 || facet1->visible || facet2->visible) {
  3116. qh_fprintf(qh, qh->ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet, mergetype %d (%s)\n",
  3117. facet1->id, facet2->id, mergetype, mergename);
  3118. qh_errexit2(qh, qh_ERRqhull, facet1, facet2);
  3119. }
  3120. if (qh->num_facets - qh->num_visible <= qh->hull_dim + 1) {
  3121. qh_fprintf(qh, qh->ferr, 6227, "qhull topology error: Only %d facets remain. The input is too degenerate or the convexity constraints are too strong.\n",
  3122. qh->hull_dim+1);
  3123. if (qh->hull_dim >= 5 && !qh->MERGEexact)
  3124. qh_fprintf(qh, qh->ferr, 8079, " Option 'Qx' may avoid this problem.\n");
  3125. qh_errexit(qh, qh_ERRtopology, NULL, NULL);
  3126. }
  3127. if (!qh->VERTEXneighbors)
  3128. qh_vertexneighbors(qh);
  3129. qh_makeridges(qh, facet1);
  3130. qh_makeridges(qh, facet2);
  3131. if (qh->IStracing >=4)
  3132. qh_errprint(qh, "MERGING", facet1, facet2, NULL, NULL);
  3133. if (mindist) {
  3134. maximize_(qh->max_outside, *maxdist);
  3135. maximize_(qh->max_vertex, *maxdist);
  3136. #if qh_MAXoutside
  3137. maximize_(facet2->maxoutside, *maxdist);
  3138. #endif
  3139. minimize_(qh->min_vertex, *mindist);
  3140. if (!facet2->keepcentrum
  3141. && (*maxdist > qh->WIDEfacet || *mindist < -qh->WIDEfacet)) {
  3142. facet2->keepcentrum= True;
  3143. zinc_(Zwidefacet);
  3144. }
  3145. }
  3146. nummerge= facet1->nummerge + facet2->nummerge + 1;
  3147. if (nummerge >= qh_MAXnummerge)
  3148. facet2->nummerge= qh_MAXnummerge;
  3149. else
  3150. facet2->nummerge= (short unsigned int)nummerge; /* limited to 9 bits by qh_MAXnummerge, -Wconversion */
  3151. facet2->newmerge= True;
  3152. facet2->dupridge= False;
  3153. qh_updatetested(qh, facet1, facet2);
  3154. if (qh->hull_dim > 2 && qh_setsize(qh, facet1->vertices) == qh->hull_dim)
  3155. qh_mergesimplex(qh, facet1, facet2, mergeapex);
  3156. else {
  3157. qh->vertex_visit++;
  3158. FOREACHvertex_(facet2->vertices)
  3159. vertex->visitid= qh->vertex_visit;
  3160. if (qh->hull_dim == 2)
  3161. qh_mergefacet2d(qh, facet1, facet2);
  3162. else {
  3163. qh_mergeneighbors(qh, facet1, facet2);
  3164. qh_mergevertices(qh, facet1->vertices, &facet2->vertices);
  3165. }
  3166. qh_mergeridges(qh, facet1, facet2);
  3167. qh_mergevertex_neighbors(qh, facet1, facet2);
  3168. if (!facet2->newfacet)
  3169. qh_newvertices(qh, facet2->vertices);
  3170. }
  3171. if (facet2->coplanarhorizon) {
  3172. zinc_(Zmergeintocoplanar);
  3173. }else if (!facet2->newfacet) {
  3174. zinc_(Zmergeintohorizon);
  3175. }else if (!facet1->newfacet && facet2->newfacet) {
  3176. zinc_(Zmergehorizon);
  3177. }else {
  3178. zinc_(Zmergenew);
  3179. }
  3180. qh_removefacet(qh, facet2); /* append as a newfacet to end of qh->facet_list */
  3181. qh_appendfacet(qh, facet2);
  3182. facet2->newfacet= True;
  3183. facet2->tested= False;
  3184. qh_tracemerge(qh, facet1, facet2, mergetype);
  3185. if (traceonce) {
  3186. qh_fprintf(qh, qh->ferr, 8080, "qh_mergefacet: end of wide tracing\n");
  3187. qh->IStracing= tracerestore;
  3188. }
  3189. if (mergetype != MRGcoplanarhorizon) {
  3190. trace3((qh, qh->ferr, 3076, "qh_mergefacet: check f%d and f%d for redundant and degenerate neighbors\n",
  3191. facet1->id, facet2->id));
  3192. qh_test_redundant_neighbors(qh, facet2);
  3193. qh_test_degen_neighbors(qh, facet1); /* after qh_test_redundant_neighbors since MRGdegen more difficult than MRGredundant
  3194. and before qh_willdelete which clears facet1.neighbors */
  3195. qh_degen_redundant_facet(qh, facet2); /* may occur in qh_merge_pinchedvertices, e.g., rbox 175 C3,2e-13 D4 t1545228104 | qhull d */
  3196. qh_maybe_duplicateridges(qh, facet2);
  3197. }
  3198. qh_willdelete(qh, facet1, facet2);
  3199. } /* mergefacet */
  3200. /*-<a href="qh-merge_r.htm#TOC"
  3201. >-------------------------------</a><a name="mergefacet2d">-</a>
  3202. qh_mergefacet2d(qh, facet1, facet2 )
  3203. in 2d, merges neighbors and vertices of facet1 into facet2
  3204. returns:
  3205. build ridges for neighbors if necessary
  3206. facet2 looks like a simplicial facet except for centrum, ridges
  3207. neighbors are opposite the corresponding vertex
  3208. maintains orientation of facet2
  3209. notes:
  3210. qh_mergefacet() retains non-simplicial structures
  3211. they are not needed in 2d, but later routines may use them
  3212. preserves qh.vertex_visit for qh_mergevertex_neighbors()
  3213. design:
  3214. get vertices and neighbors
  3215. determine new vertices and neighbors
  3216. set new vertices and neighbors and adjust orientation
  3217. make ridges for new neighbor if needed
  3218. */
  3219. void qh_mergefacet2d(qhT *qh, facetT *facet1, facetT *facet2) {
  3220. vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
  3221. facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
  3222. vertex1A= SETfirstt_(facet1->vertices, vertexT);
  3223. vertex1B= SETsecondt_(facet1->vertices, vertexT);
  3224. vertex2A= SETfirstt_(facet2->vertices, vertexT);
  3225. vertex2B= SETsecondt_(facet2->vertices, vertexT);
  3226. neighbor1A= SETfirstt_(facet1->neighbors, facetT);
  3227. neighbor1B= SETsecondt_(facet1->neighbors, facetT);
  3228. neighbor2A= SETfirstt_(facet2->neighbors, facetT);
  3229. neighbor2B= SETsecondt_(facet2->neighbors, facetT);
  3230. if (vertex1A == vertex2A) {
  3231. vertexA= vertex1B;
  3232. vertexB= vertex2B;
  3233. neighborA= neighbor2A;
  3234. neighborB= neighbor1A;
  3235. }else if (vertex1A == vertex2B) {
  3236. vertexA= vertex1B;
  3237. vertexB= vertex2A;
  3238. neighborA= neighbor2B;
  3239. neighborB= neighbor1A;
  3240. }else if (vertex1B == vertex2A) {
  3241. vertexA= vertex1A;
  3242. vertexB= vertex2B;
  3243. neighborA= neighbor2A;
  3244. neighborB= neighbor1B;
  3245. }else { /* 1B == 2B */
  3246. vertexA= vertex1A;
  3247. vertexB= vertex2A;
  3248. neighborA= neighbor2B;
  3249. neighborB= neighbor1B;
  3250. }
  3251. /* vertexB always from facet2, neighborB always from facet1 */
  3252. if (vertexA->id > vertexB->id) {
  3253. SETfirst_(facet2->vertices)= vertexA;
  3254. SETsecond_(facet2->vertices)= vertexB;
  3255. if (vertexB == vertex2A)
  3256. facet2->toporient= !facet2->toporient;
  3257. SETfirst_(facet2->neighbors)= neighborA;
  3258. SETsecond_(facet2->neighbors)= neighborB;
  3259. }else {
  3260. SETfirst_(facet2->vertices)= vertexB;
  3261. SETsecond_(facet2->vertices)= vertexA;
  3262. if (vertexB == vertex2B)
  3263. facet2->toporient= !facet2->toporient;
  3264. SETfirst_(facet2->neighbors)= neighborB;
  3265. SETsecond_(facet2->neighbors)= neighborA;
  3266. }
  3267. /* qh_makeridges not needed since neighborB is not degenerate */
  3268. qh_setreplace(qh, neighborB->neighbors, facet1, facet2);
  3269. trace4((qh, qh->ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
  3270. vertexA->id, neighborB->id, facet1->id, facet2->id));
  3271. } /* mergefacet2d */
  3272. /*-<a href="qh-merge_r.htm#TOC"
  3273. >-------------------------------</a><a name="mergeneighbors">-</a>
  3274. qh_mergeneighbors(qh, facet1, facet2 )
  3275. merges the neighbors of facet1 into facet2
  3276. notes:
  3277. only called by qh_mergefacet
  3278. qh.hull_dim >= 3
  3279. see qh_mergecycle_neighbors
  3280. design:
  3281. for each neighbor of facet1
  3282. if neighbor is also a neighbor of facet2
  3283. if neighbor is simplicial
  3284. make ridges for later deletion as a degenerate facet
  3285. update its neighbor set
  3286. else
  3287. move the neighbor relation to facet2
  3288. remove the neighbor relation for facet1 and facet2
  3289. */
  3290. void qh_mergeneighbors(qhT *qh, facetT *facet1, facetT *facet2) {
  3291. facetT *neighbor, **neighborp;
  3292. trace4((qh, qh->ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
  3293. facet1->id, facet2->id));
  3294. qh->visit_id++;
  3295. FOREACHneighbor_(facet2) {
  3296. neighbor->visitid= qh->visit_id;
  3297. }
  3298. FOREACHneighbor_(facet1) {
  3299. if (neighbor->visitid == qh->visit_id) {
  3300. if (neighbor->simplicial) /* is degen, needs ridges */
  3301. qh_makeridges(qh, neighbor);
  3302. if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
  3303. qh_setdel(neighbor->neighbors, facet1);
  3304. else {
  3305. qh_setdel(neighbor->neighbors, facet2);
  3306. qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
  3307. }
  3308. }else if (neighbor != facet2) {
  3309. qh_setappend(qh, &(facet2->neighbors), neighbor);
  3310. qh_setreplace(qh, neighbor->neighbors, facet1, facet2);
  3311. }
  3312. }
  3313. qh_setdel(facet1->neighbors, facet2); /* here for makeridges */
  3314. qh_setdel(facet2->neighbors, facet1);
  3315. } /* mergeneighbors */
  3316. /*-<a href="qh-merge_r.htm#TOC"
  3317. >-------------------------------</a><a name="mergeridges">-</a>
  3318. qh_mergeridges(qh, facet1, facet2 )
  3319. merges the ridge set of facet1 into facet2
  3320. returns:
  3321. may delete all ridges for a vertex
  3322. sets vertex->delridge on deleted ridges
  3323. see:
  3324. qh_mergecycle_ridges()
  3325. design:
  3326. delete ridges between facet1 and facet2
  3327. mark (delridge) vertices on these ridges for later testing
  3328. for each remaining ridge
  3329. rename facet1 to facet2
  3330. */
  3331. void qh_mergeridges(qhT *qh, facetT *facet1, facetT *facet2) {
  3332. ridgeT *ridge, **ridgep;
  3333. trace4((qh, qh->ferr, 4038, "qh_mergeridges: merge ridges of f%d into f%d\n",
  3334. facet1->id, facet2->id));
  3335. FOREACHridge_(facet2->ridges) {
  3336. if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
  3337. /* ridge.nonconvex is irrelevant due to merge */
  3338. qh_delridge_merge(qh, ridge); /* expensive in high-d, could rebuild */
  3339. ridgep--; /* deleted this ridge, repeat with next ridge*/
  3340. }
  3341. }
  3342. FOREACHridge_(facet1->ridges) {
  3343. if (ridge->top == facet1) {
  3344. ridge->top= facet2;
  3345. ridge->simplicialtop= False;
  3346. }else { /* ridge.bottom is facet1 */
  3347. ridge->bottom= facet2;
  3348. ridge->simplicialbot= False;
  3349. }
  3350. qh_setappend(qh, &(facet2->ridges), ridge);
  3351. }
  3352. } /* mergeridges */
  3353. /*-<a href="qh-merge_r.htm#TOC"
  3354. >-------------------------------</a><a name="mergesimplex">-</a>
  3355. qh_mergesimplex(qh, facet1, facet2, mergeapex )
  3356. merge simplicial facet1 into facet2
  3357. mergeapex==qh_MERGEapex if merging samecycle into horizon facet
  3358. vertex id is latest (most recently created)
  3359. facet1 may be contained in facet2
  3360. ridges exist for both facets
  3361. returns:
  3362. facet2 with updated vertices, ridges, neighbors
  3363. updated neighbors for facet1's vertices
  3364. facet1 not deleted
  3365. sets vertex->delridge on deleted ridges
  3366. notes:
  3367. special case code since this is the most common merge
  3368. called from qh_mergefacet()
  3369. design:
  3370. if qh_MERGEapex
  3371. add vertices of facet2 to qh.new_vertexlist if necessary
  3372. add apex to facet2
  3373. else
  3374. for each ridge between facet1 and facet2
  3375. set vertex->delridge
  3376. determine the apex for facet1 (i.e., vertex to be merged)
  3377. unless apex already in facet2
  3378. insert apex into vertices for facet2
  3379. add vertices of facet2 to qh.new_vertexlist if necessary
  3380. add apex to qh.new_vertexlist if necessary
  3381. for each vertex of facet1
  3382. if apex
  3383. rename facet1 to facet2 in its vertex neighbors
  3384. else
  3385. delete facet1 from vertex neighbors
  3386. if only in facet2
  3387. add vertex to qh.del_vertices for later deletion
  3388. for each ridge of facet1
  3389. delete ridges between facet1 and facet2
  3390. append other ridges to facet2 after renaming facet to facet2
  3391. */
  3392. void qh_mergesimplex(qhT *qh, facetT *facet1, facetT *facet2, boolT mergeapex) {
  3393. vertexT *vertex, **vertexp, *opposite;
  3394. ridgeT *ridge, **ridgep;
  3395. boolT isnew= False;
  3396. facetT *neighbor, **neighborp, *otherfacet;
  3397. if (mergeapex) {
  3398. opposite= SETfirstt_(facet1->vertices, vertexT); /* apex is opposite facet2. It has the last vertex id */
  3399. trace4((qh, qh->ferr, 4086, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
  3400. opposite->id, facet1->id, facet2->id));
  3401. if (!facet2->newfacet)
  3402. qh_newvertices(qh, facet2->vertices); /* apex, the first vertex, is already new */
  3403. if (SETfirstt_(facet2->vertices, vertexT) != opposite) {
  3404. qh_setaddnth(qh, &facet2->vertices, 0, opposite);
  3405. isnew= True;
  3406. }
  3407. }else {
  3408. zinc_(Zmergesimplex);
  3409. FOREACHvertex_(facet1->vertices)
  3410. vertex->seen= False;
  3411. FOREACHridge_(facet1->ridges) {
  3412. if (otherfacet_(ridge, facet1) == facet2) {
  3413. FOREACHvertex_(ridge->vertices) {
  3414. vertex->seen= True;
  3415. vertex->delridge= True;
  3416. }
  3417. break;
  3418. }
  3419. }
  3420. FOREACHvertex_(facet1->vertices) {
  3421. if (!vertex->seen)
  3422. break; /* must occur */
  3423. }
  3424. opposite= vertex;
  3425. trace4((qh, qh->ferr, 4039, "qh_mergesimplex: merge opposite v%d of f%d into facet f%d\n",
  3426. opposite->id, facet1->id, facet2->id));
  3427. isnew= qh_addfacetvertex(qh, facet2, opposite);
  3428. if (!facet2->newfacet)
  3429. qh_newvertices(qh, facet2->vertices);
  3430. else if (!opposite->newfacet) {
  3431. qh_removevertex(qh, opposite);
  3432. qh_appendvertex(qh, opposite);
  3433. }
  3434. }
  3435. trace4((qh, qh->ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n",
  3436. facet1->id));
  3437. FOREACHvertex_(facet1->vertices) {
  3438. if (vertex == opposite && isnew)
  3439. qh_setreplace(qh, vertex->neighbors, facet1, facet2);
  3440. else {
  3441. qh_setdel(vertex->neighbors, facet1);
  3442. if (!SETsecond_(vertex->neighbors))
  3443. qh_mergevertex_del(qh, vertex, facet1, facet2);
  3444. }
  3445. }
  3446. trace4((qh, qh->ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
  3447. facet1->id, facet2->id));
  3448. qh->visit_id++;
  3449. FOREACHneighbor_(facet2)
  3450. neighbor->visitid= qh->visit_id;
  3451. FOREACHridge_(facet1->ridges) {
  3452. otherfacet= otherfacet_(ridge, facet1);
  3453. if (otherfacet == facet2) {
  3454. /* ridge.nonconvex is irrelevant due to merge */
  3455. qh_delridge_merge(qh, ridge); /* expensive in high-d, could rebuild */
  3456. ridgep--; /* deleted this ridge, repeat with next ridge*/
  3457. qh_setdel(facet2->neighbors, facet1); /* a simplicial facet may have duplicate neighbors, need to delete each one */
  3458. }else if (otherfacet->dupridge && !qh_setin(otherfacet->neighbors, facet1)) {
  3459. qh_fprintf(qh, qh->ferr, 6356, "qhull topology error (qh_mergesimplex): f%d is a dupridge of f%d, cannot merge f%d into f%d\n",
  3460. facet1->id, otherfacet->id, facet1->id, facet2->id);
  3461. qh_errexit2(qh, qh_ERRqhull, facet1, otherfacet);
  3462. }else {
  3463. trace4((qh, qh->ferr, 4059, "qh_mergesimplex: move r%d with f%d to f%d, new neighbor? %d, maybe horizon? %d\n",
  3464. ridge->id, otherfacet->id, facet2->id, (otherfacet->visitid != qh->visit_id), (SETfirstt_(otherfacet->neighbors, facetT) == facet1)));
  3465. qh_setappend(qh, &facet2->ridges, ridge);
  3466. if (otherfacet->visitid != qh->visit_id) {
  3467. qh_setappend(qh, &facet2->neighbors, otherfacet);
  3468. qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
  3469. otherfacet->visitid= qh->visit_id;
  3470. }else {
  3471. if (otherfacet->simplicial) /* is degen, needs ridges */
  3472. qh_makeridges(qh, otherfacet);
  3473. if (SETfirstt_(otherfacet->neighbors, facetT) == facet1) {
  3474. /* keep new, otherfacet->neighbors->horizon */
  3475. qh_setdel(otherfacet->neighbors, facet2);
  3476. qh_setreplace(qh, otherfacet->neighbors, facet1, facet2);
  3477. }else {
  3478. /* facet2 is already a neighbor of otherfacet, by f.visitid */
  3479. qh_setdel(otherfacet->neighbors, facet1);
  3480. }
  3481. }
  3482. if (ridge->top == facet1) { /* wait until after qh_makeridges */
  3483. ridge->top= facet2;
  3484. ridge->simplicialtop= False;
  3485. }else {
  3486. ridge->bottom= facet2;
  3487. ridge->simplicialbot= False;
  3488. }
  3489. }
  3490. }
  3491. trace3((qh, qh->ferr, 3006, "qh_mergesimplex: merged simplex f%d v%d into facet f%d\n",
  3492. facet1->id, opposite->id, facet2->id));
  3493. } /* mergesimplex */
  3494. /*-<a href="qh-merge_r.htm#TOC"
  3495. >-------------------------------</a><a name="mergevertex_del">-</a>
  3496. qh_mergevertex_del(qh, vertex, facet1, facet2 )
  3497. delete a vertex because of merging facet1 into facet2
  3498. returns:
  3499. deletes vertex from facet2
  3500. adds vertex to qh.del_vertices for later deletion
  3501. */
  3502. void qh_mergevertex_del(qhT *qh, vertexT *vertex, facetT *facet1, facetT *facet2) {
  3503. zinc_(Zmergevertex);
  3504. trace2((qh, qh->ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
  3505. vertex->id, facet1->id, facet2->id));
  3506. qh_setdelsorted(facet2->vertices, vertex);
  3507. vertex->deleted= True;
  3508. qh_setappend(qh, &qh->del_vertices, vertex);
  3509. } /* mergevertex_del */
  3510. /*-<a href="qh-merge_r.htm#TOC"
  3511. >-------------------------------</a><a name="mergevertex_neighbors">-</a>
  3512. qh_mergevertex_neighbors(qh, facet1, facet2 )
  3513. merge the vertex neighbors of facet1 to facet2
  3514. returns:
  3515. if vertex is current qh.vertex_visit
  3516. deletes facet1 from vertex->neighbors
  3517. else
  3518. renames facet1 to facet2 in vertex->neighbors
  3519. deletes vertices if only one neighbor
  3520. notes:
  3521. assumes vertex neighbor sets are good
  3522. */
  3523. void qh_mergevertex_neighbors(qhT *qh, facetT *facet1, facetT *facet2) {
  3524. vertexT *vertex, **vertexp;
  3525. trace4((qh, qh->ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighborset for f%d into f%d\n",
  3526. facet1->id, facet2->id));
  3527. if (qh->tracevertex) {
  3528. qh_fprintf(qh, qh->ferr, 8081, "qh_mergevertex_neighbors: of f%d into f%d at furthest p%d f0= %p\n",
  3529. facet1->id, facet2->id, qh->furthest_id, qh->tracevertex->neighbors->e[0].p);
  3530. qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
  3531. }
  3532. FOREACHvertex_(facet1->vertices) {
  3533. if (vertex->visitid != qh->vertex_visit)
  3534. qh_setreplace(qh, vertex->neighbors, facet1, facet2);
  3535. else {
  3536. qh_setdel(vertex->neighbors, facet1);
  3537. if (!SETsecond_(vertex->neighbors))
  3538. qh_mergevertex_del(qh, vertex, facet1, facet2);
  3539. }
  3540. }
  3541. if (qh->tracevertex)
  3542. qh_errprint(qh, "TRACE", NULL, NULL, NULL, qh->tracevertex);
  3543. } /* mergevertex_neighbors */
  3544. /*-<a href="qh-merge_r.htm#TOC"
  3545. >-------------------------------</a><a name="mergevertices">-</a>
  3546. qh_mergevertices(qh, vertices1, vertices2 )
  3547. merges the vertex set of facet1 into facet2
  3548. returns:
  3549. replaces vertices2 with merged set
  3550. preserves vertex_visit for qh_mergevertex_neighbors
  3551. updates qh.newvertex_list
  3552. design:
  3553. create a merged set of both vertices (in inverse id order)
  3554. */
  3555. void qh_mergevertices(qhT *qh, setT *vertices1, setT **vertices2) {
  3556. int newsize= qh_setsize(qh, vertices1)+qh_setsize(qh, *vertices2) - qh->hull_dim + 1;
  3557. setT *mergedvertices;
  3558. vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
  3559. mergedvertices= qh_settemp(qh, newsize);
  3560. FOREACHvertex_(vertices1) {
  3561. if (!*vertex2 || vertex->id > (*vertex2)->id)
  3562. qh_setappend(qh, &mergedvertices, vertex);
  3563. else {
  3564. while (*vertex2 && (*vertex2)->id > vertex->id)
  3565. qh_setappend(qh, &mergedvertices, *vertex2++);
  3566. if (!*vertex2 || (*vertex2)->id < vertex->id)
  3567. qh_setappend(qh, &mergedvertices, vertex);
  3568. else
  3569. qh_setappend(qh, &mergedvertices, *vertex2++);
  3570. }
  3571. }
  3572. while (*vertex2)
  3573. qh_setappend(qh, &mergedvertices, *vertex2++);
  3574. if (newsize < qh_setsize(qh, mergedvertices)) {
  3575. qh_fprintf(qh, qh->ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
  3576. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  3577. }
  3578. qh_setfree(qh, vertices2);
  3579. *vertices2= mergedvertices;
  3580. qh_settemppop(qh);
  3581. } /* mergevertices */
  3582. /*-<a href="qh-merge_r.htm#TOC"
  3583. >-------------------------------</a><a name="neighbor_intersections">-</a>
  3584. qh_neighbor_intersections(qh, vertex )
  3585. return intersection of all vertices in vertex->neighbors except for vertex
  3586. returns:
  3587. returns temporary set of vertices
  3588. does not include vertex
  3589. NULL if a neighbor is simplicial
  3590. NULL if empty set
  3591. notes:
  3592. only called by qh_redundant_vertex for qh_reducevertices
  3593. so f.vertices does not contain extraneous vertices that are not in f.ridges
  3594. used for renaming vertices
  3595. design:
  3596. initialize the intersection set with vertices of the first two neighbors
  3597. delete vertex from the intersection
  3598. for each remaining neighbor
  3599. intersect its vertex set with the intersection set
  3600. return NULL if empty
  3601. return the intersection set
  3602. */
  3603. setT *qh_neighbor_intersections(qhT *qh, vertexT *vertex) {
  3604. facetT *neighbor, **neighborp, *neighborA, *neighborB;
  3605. setT *intersect;
  3606. int neighbor_i, neighbor_n;
  3607. FOREACHneighbor_(vertex) {
  3608. if (neighbor->simplicial)
  3609. return NULL;
  3610. }
  3611. neighborA= SETfirstt_(vertex->neighbors, facetT);
  3612. neighborB= SETsecondt_(vertex->neighbors, facetT);
  3613. zinc_(Zintersectnum);
  3614. if (!neighborA)
  3615. return NULL;
  3616. if (!neighborB)
  3617. intersect= qh_setcopy(qh, neighborA->vertices, 0);
  3618. else
  3619. intersect= qh_vertexintersect_new(qh, neighborA->vertices, neighborB->vertices);
  3620. qh_settemppush(qh, intersect);
  3621. qh_setdelsorted(intersect, vertex);
  3622. FOREACHneighbor_i_(qh, vertex) {
  3623. if (neighbor_i >= 2) {
  3624. zinc_(Zintersectnum);
  3625. qh_vertexintersect(qh, &intersect, neighbor->vertices);
  3626. if (!SETfirst_(intersect)) {
  3627. zinc_(Zintersectfail);
  3628. qh_settempfree(qh, &intersect);
  3629. return NULL;
  3630. }
  3631. }
  3632. }
  3633. trace3((qh, qh->ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
  3634. qh_setsize(qh, intersect), vertex->id));
  3635. return intersect;
  3636. } /* neighbor_intersections */
  3637. /*-<a href="qh-merge_r.htm#TOC"
  3638. >-------------------------------</a><a name="neighbor_vertices">-</a>
  3639. qh_neighbor_vertices(qh, vertex )
  3640. return neighboring vertices for a vertex (not in subridge)
  3641. assumes vertices have full vertex->neighbors
  3642. returns:
  3643. temporary set of vertices
  3644. notes:
  3645. updates qh.visit_id and qh.vertex_visit
  3646. similar to qh_vertexridges
  3647. */
  3648. setT *qh_neighbor_vertices(qhT *qh, vertexT *vertexA, setT *subridge) {
  3649. facetT *neighbor, **neighborp;
  3650. vertexT *vertex, **vertexp;
  3651. setT *vertices= qh_settemp(qh, qh->TEMPsize);
  3652. qh->visit_id++;
  3653. FOREACHneighbor_(vertexA)
  3654. neighbor->visitid= qh->visit_id;
  3655. qh->vertex_visit++;
  3656. vertexA->visitid= qh->vertex_visit;
  3657. FOREACHvertex_(subridge) {
  3658. vertex->visitid= qh->vertex_visit;
  3659. }
  3660. FOREACHneighbor_(vertexA) {
  3661. if (*neighborp) /* no new ridges in last neighbor */
  3662. qh_neighbor_vertices_facet(qh, vertexA, neighbor, &vertices);
  3663. }
  3664. trace3((qh, qh->ferr, 3035, "qh_neighbor_vertices: %d non-subridge, vertex neighbors for v%d\n",
  3665. qh_setsize(qh, vertices), vertexA->id));
  3666. return vertices;
  3667. } /* neighbor_vertices */
  3668. /*-<a href="qh-merge_r.htm#TOC"
  3669. >-------------------------------</a><a name="neighbor_vertices_facet">-</a>
  3670. qh_neighbor_vertices_facet(qh, vertex, facet, vertices )
  3671. add neighboring vertices on ridges for vertex in facet
  3672. neighbor->visitid==qh.visit_id if it hasn't been visited
  3673. v.visitid==qh.vertex_visit if it is already in vertices
  3674. returns:
  3675. vertices updated
  3676. sets facet->visitid to qh.visit_id-1
  3677. notes:
  3678. only called by qh_neighbor_vertices
  3679. similar to qh_vertexridges_facet
  3680. design:
  3681. for each ridge of facet
  3682. if ridge of visited neighbor (i.e., unprocessed)
  3683. if vertex in ridge
  3684. append unprocessed vertices of ridge
  3685. mark facet processed
  3686. */
  3687. void qh_neighbor_vertices_facet(qhT *qh, vertexT *vertexA, facetT *facet, setT **vertices) {
  3688. ridgeT *ridge, **ridgep;
  3689. facetT *neighbor;
  3690. vertexT *second, *last, *vertex, **vertexp;
  3691. int last_i= qh->hull_dim-2, count= 0;
  3692. boolT isridge;
  3693. if (facet->simplicial) {
  3694. FOREACHvertex_(facet->vertices) {
  3695. if (vertex->visitid != qh->vertex_visit) {
  3696. vertex->visitid= qh->vertex_visit;
  3697. qh_setappend(qh, vertices, vertex);
  3698. count++;
  3699. }
  3700. }
  3701. }else {
  3702. FOREACHridge_(facet->ridges) {
  3703. neighbor= otherfacet_(ridge, facet);
  3704. if (neighbor->visitid == qh->visit_id) {
  3705. isridge= False;
  3706. if (SETfirst_(ridge->vertices) == vertexA) {
  3707. isridge= True;
  3708. }else if (last_i > 2) {
  3709. second= SETsecondt_(ridge->vertices, vertexT);
  3710. last= SETelemt_(ridge->vertices, last_i, vertexT);
  3711. if (second->id >= vertexA->id && last->id <= vertexA->id) { /* vertices inverse sorted by id */
  3712. if (second == vertexA || last == vertexA)
  3713. isridge= True;
  3714. else if (qh_setin(ridge->vertices, vertexA))
  3715. isridge= True;
  3716. }
  3717. }else if (SETelem_(ridge->vertices, last_i) == vertexA) {
  3718. isridge= True;
  3719. }else if (last_i > 1 && SETsecond_(ridge->vertices) == vertexA) {
  3720. isridge= True;
  3721. }
  3722. if (isridge) {
  3723. FOREACHvertex_(ridge->vertices) {
  3724. if (vertex->visitid != qh->vertex_visit) {
  3725. vertex->visitid= qh->vertex_visit;
  3726. qh_setappend(qh, vertices, vertex);
  3727. count++;
  3728. }
  3729. }
  3730. }
  3731. }
  3732. }
  3733. }
  3734. facet->visitid= qh->visit_id-1;
  3735. if (count) {
  3736. trace4((qh, qh->ferr, 4079, "qh_neighbor_vertices_facet: found %d vertex neighbors for v%d in f%d (simplicial? %d)\n",
  3737. count, vertexA->id, facet->id, facet->simplicial));
  3738. }
  3739. } /* neighbor_vertices_facet */
  3740. /*-<a href="qh-merge_r.htm#TOC"
  3741. >-------------------------------</a><a name="newvertices">-</a>
  3742. qh_newvertices(qh, vertices )
  3743. add vertices to end of qh.vertex_list (marks as new vertices)
  3744. returns:
  3745. vertices on qh.newvertex_list
  3746. vertex->newfacet set
  3747. */
  3748. void qh_newvertices(qhT *qh, setT *vertices) {
  3749. vertexT *vertex, **vertexp;
  3750. FOREACHvertex_(vertices) {
  3751. if (!vertex->newfacet) {
  3752. qh_removevertex(qh, vertex);
  3753. qh_appendvertex(qh, vertex);
  3754. }
  3755. }
  3756. } /* newvertices */
  3757. /*-<a href="qh-merge_r.htm#TOC"
  3758. >-------------------------------</a><a name="next_vertexmerge">-</a>
  3759. qh_next_vertexmerge(qh )
  3760. return next vertex merge from qh.vertex_mergeset
  3761. returns:
  3762. vertex merge either MRGvertices or MRGsubridge
  3763. drops merges of deleted vertices
  3764. notes:
  3765. called from qh_merge_pinchedvertices
  3766. */
  3767. mergeT *qh_next_vertexmerge(qhT *qh /* qh.vertex_mergeset */) {
  3768. mergeT *merge;
  3769. int merge_i, merge_n, best_i= -1;
  3770. realT bestdist= REALmax;
  3771. FOREACHmerge_i_(qh, qh->vertex_mergeset) {
  3772. if (!merge->vertex1 || !merge->vertex2) {
  3773. qh_fprintf(qh, qh->ferr, 6299, "qhull internal error (qh_next_vertexmerge): expecting two vertices for vertex merge. Got v%d v%d and optional f%d\n",
  3774. getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->facet1));
  3775. qh_errexit(qh, qh_ERRqhull, merge->facet1, NULL);
  3776. }
  3777. if (merge->vertex1->deleted || merge->vertex2->deleted) {
  3778. trace3((qh, qh->ferr, 3030, "qh_next_vertexmerge: drop merge of v%d (del? %d) into v%d (del? %d) due to deleted vertex of r%d and r%d\n",
  3779. merge->vertex1->id, merge->vertex1->deleted, merge->vertex2->id, merge->vertex2->deleted, getid_(merge->ridge1), getid_(merge->ridge2)));
  3780. qh_drop_mergevertex(qh, merge);
  3781. qh_setdelnth(qh, qh->vertex_mergeset, merge_i);
  3782. merge_i--; merge_n--;
  3783. qh_memfree(qh, merge, (int)sizeof(mergeT));
  3784. }else if (merge->distance < bestdist) {
  3785. bestdist= merge->distance;
  3786. best_i= merge_i;
  3787. }
  3788. }
  3789. merge= NULL;
  3790. if (best_i >= 0) {
  3791. merge= SETelemt_(qh->vertex_mergeset, best_i, mergeT);
  3792. if (bestdist/qh->ONEmerge > qh_WIDEpinched) {
  3793. if (merge->mergetype==MRGvertices) {
  3794. if (merge->ridge1->top == merge->ridge2->bottom && merge->ridge1->bottom == merge->ridge2->top)
  3795. qh_fprintf(qh, qh->ferr, 6391, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve opposite oriented ridges r%d and r%d in f%d and f%d. Nearest v%d and v%d dist %2.2g (%.1fx)\n",
  3796. merge->ridge1->id, merge->ridge2->id, merge->ridge1->top->id, merge->ridge1->bottom->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
  3797. else
  3798. qh_fprintf(qh, qh->ferr, 6381, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve duplicate ridges r%d and r%d. Nearest v%d and v%d dist %2.2g (%.1fx)\n",
  3799. merge->ridge1->id, merge->ridge2->id, merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
  3800. }else {
  3801. qh_fprintf(qh, qh->ferr, 6208, "qhull topology error (qh_next_vertexmerge): no nearly adjacent vertices to resolve dupridge. Nearest v%d and v%d dist %2.2g (%.1fx)\n",
  3802. merge->vertex1->id, merge->vertex2->id, bestdist, bestdist/qh->ONEmerge);
  3803. }
  3804. /* it may be possible to find a different vertex, after other vertex merges have occurred */
  3805. qh_errexit(qh, qh_ERRtopology, NULL, merge->ridge1);
  3806. }
  3807. qh_setdelnth(qh, qh->vertex_mergeset, best_i);
  3808. }
  3809. return merge;
  3810. } /* next_vertexmerge */
  3811. /*-<a href="qh-merge_r.htm#TOC"
  3812. >-------------------------------</a><a name="opposite_horizonfacet">-</a>
  3813. qh_opposite_horizonfacet(qh, merge, opposite )
  3814. return horizon facet for one of the merge facets, and its opposite vertex across the ridge
  3815. assumes either facet1 or facet2 of merge is 'mergehorizon'
  3816. assumes both facets are simplicial facets on qh.new_facetlist
  3817. returns:
  3818. horizon facet and opposite vertex
  3819. notes:
  3820. called by qh_getpinchedmerges
  3821. */
  3822. facetT *qh_opposite_horizonfacet(qhT *qh, mergeT *merge, vertexT **opposite) {
  3823. facetT *facet, *horizon, *otherfacet;
  3824. int neighbor_i;
  3825. if (!merge->facet1->simplicial || !merge->facet2->simplicial || (!merge->facet1->mergehorizon && !merge->facet2->mergehorizon)) {
  3826. qh_fprintf(qh, qh->ferr, 6273, "qhull internal error (qh_opposite_horizonfacet): expecting merge of simplicial facets, at least one of which is mergehorizon. Either simplicial or mergehorizon is wrong\n");
  3827. qh_errexit2(qh, qh_ERRqhull, merge->facet1, merge->facet2);
  3828. }
  3829. if (merge->facet1->mergehorizon) {
  3830. facet= merge->facet1;
  3831. otherfacet= merge->facet2;
  3832. }else {
  3833. facet= merge->facet2;
  3834. otherfacet= merge->facet1;
  3835. }
  3836. horizon= SETfirstt_(facet->neighbors, facetT);
  3837. neighbor_i= qh_setindex(otherfacet->neighbors, facet);
  3838. if (neighbor_i==-1)
  3839. neighbor_i= qh_setindex(otherfacet->neighbors, qh_MERGEridge);
  3840. if (neighbor_i==-1) {
  3841. qh_fprintf(qh, qh->ferr, 6238, "qhull internal error (qh_opposite_horizonfacet): merge facet f%d not connected to mergehorizon f%d\n",
  3842. otherfacet->id, facet->id);
  3843. qh_errexit2(qh, qh_ERRqhull, otherfacet, facet);
  3844. }
  3845. *opposite= SETelemt_(otherfacet->vertices, neighbor_i, vertexT);
  3846. return horizon;
  3847. } /* opposite_horizonfacet */
  3848. /*-<a href="qh-merge_r.htm#TOC"
  3849. >-------------------------------</a><a name="reducevertices">-</a>
  3850. qh_reducevertices(qh)
  3851. reduce extra vertices, shared vertices, and redundant vertices
  3852. facet->newmerge is set if merged since last call
  3853. vertex->delridge is set if vertex was on a deleted ridge
  3854. if !qh.MERGEvertices, only removes extra vertices
  3855. returns:
  3856. True if also merged degen_redundant facets
  3857. vertices are renamed if possible
  3858. clears facet->newmerge and vertex->delridge
  3859. notes:
  3860. called by qh_all_merges and qh_postmerge
  3861. ignored if 2-d
  3862. design:
  3863. merge any degenerate or redundant facets
  3864. repeat until no more degenerate or redundant facets
  3865. for each newly merged facet
  3866. remove extra vertices
  3867. if qh.MERGEvertices
  3868. for each newly merged facet
  3869. for each vertex
  3870. if vertex was on a deleted ridge
  3871. rename vertex if it is shared
  3872. for each new, undeleted vertex
  3873. remove delridge flag
  3874. if vertex is redundant
  3875. merge degenerate or redundant facets
  3876. */
  3877. boolT qh_reducevertices(qhT *qh) {
  3878. int numshare=0, numrename= 0;
  3879. boolT degenredun= False;
  3880. facetT *newfacet;
  3881. vertexT *vertex, **vertexp;
  3882. if (qh->hull_dim == 2)
  3883. return False;
  3884. trace2((qh, qh->ferr, 2101, "qh_reducevertices: reduce extra vertices, shared vertices, and redundant vertices\n"));
  3885. if (qh_merge_degenredundant(qh))
  3886. degenredun= True;
  3887. LABELrestart:
  3888. FORALLnew_facets {
  3889. if (newfacet->newmerge) {
  3890. if (!qh->MERGEvertices)
  3891. newfacet->newmerge= False;
  3892. if (qh_remove_extravertices(qh, newfacet)) {
  3893. qh_degen_redundant_facet(qh, newfacet);
  3894. if (qh_merge_degenredundant(qh)) {
  3895. degenredun= True;
  3896. goto LABELrestart;
  3897. }
  3898. }
  3899. }
  3900. }
  3901. if (!qh->MERGEvertices)
  3902. return False;
  3903. FORALLnew_facets {
  3904. if (newfacet->newmerge) {
  3905. newfacet->newmerge= False;
  3906. FOREACHvertex_(newfacet->vertices) {
  3907. if (vertex->delridge) {
  3908. if (qh_rename_sharedvertex(qh, vertex, newfacet)) {
  3909. numshare++;
  3910. if (qh_merge_degenredundant(qh)) {
  3911. degenredun= True;
  3912. goto LABELrestart;
  3913. }
  3914. vertexp--; /* repeat since deleted vertex */
  3915. }
  3916. }
  3917. }
  3918. }
  3919. }
  3920. FORALLvertex_(qh->newvertex_list) {
  3921. if (vertex->delridge && !vertex->deleted) {
  3922. vertex->delridge= False;
  3923. if (qh->hull_dim >= 4 && qh_redundant_vertex(qh, vertex)) {
  3924. numrename++;
  3925. if (qh_merge_degenredundant(qh)) {
  3926. degenredun= True;
  3927. goto LABELrestart;
  3928. }
  3929. }
  3930. }
  3931. }
  3932. trace1((qh, qh->ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
  3933. numshare, numrename, degenredun));
  3934. return degenredun;
  3935. } /* reducevertices */
  3936. /*-<a href="qh-merge_r.htm#TOC"
  3937. >-------------------------------</a><a name="redundant_vertex">-</a>
  3938. qh_redundant_vertex(qh, vertex )
  3939. rename a redundant vertex if qh_find_newvertex succeeds
  3940. assumes vertices have full vertex->neighbors
  3941. returns:
  3942. if find a replacement vertex
  3943. returns new vertex
  3944. qh_renamevertex sets vertex->deleted for redundant vertex
  3945. notes:
  3946. only called by qh_reducevertices for vertex->delridge and hull_dim >= 4
  3947. may add degenerate facets to qh.facet_mergeset
  3948. doesn't change vertex->neighbors or create redundant facets
  3949. design:
  3950. intersect vertices of all facet neighbors of vertex
  3951. determine ridges for these vertices
  3952. if find a new vertex for vertex among these ridges and vertices
  3953. rename vertex to the new vertex
  3954. */
  3955. vertexT *qh_redundant_vertex(qhT *qh, vertexT *vertex) {
  3956. vertexT *newvertex= NULL;
  3957. setT *vertices, *ridges;
  3958. trace3((qh, qh->ferr, 3008, "qh_redundant_vertex: check if v%d from a deleted ridge can be renamed\n", vertex->id));
  3959. if ((vertices= qh_neighbor_intersections(qh, vertex))) {
  3960. ridges= qh_vertexridges(qh, vertex, !qh_ALL);
  3961. if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges))) {
  3962. zinc_(Zrenameall);
  3963. qh_renamevertex(qh, vertex, newvertex, ridges, NULL, NULL); /* ridges invalidated */
  3964. }
  3965. qh_settempfree(qh, &ridges);
  3966. qh_settempfree(qh, &vertices);
  3967. }
  3968. return newvertex;
  3969. } /* redundant_vertex */
  3970. /*-<a href="qh-merge_r.htm#TOC"
  3971. >-------------------------------</a><a name="remove_extravertices">-</a>
  3972. qh_remove_extravertices(qh, facet )
  3973. remove extra vertices from non-simplicial facets
  3974. returns:
  3975. returns True if it finds them
  3976. deletes facet from vertex neighbors
  3977. facet may be redundant (test with qh_degen_redundant)
  3978. notes:
  3979. called by qh_renamevertex and qh_reducevertices
  3980. a merge (qh_reducevertices) or qh_renamevertex may drop all ridges for a vertex in a facet
  3981. design:
  3982. for each vertex in facet
  3983. if vertex not in a ridge (i.e., no longer used)
  3984. delete vertex from facet
  3985. delete facet from vertex's neighbors
  3986. unless vertex in another facet
  3987. add vertex to qh.del_vertices for later deletion
  3988. */
  3989. boolT qh_remove_extravertices(qhT *qh, facetT *facet) {
  3990. ridgeT *ridge, **ridgep;
  3991. vertexT *vertex, **vertexp;
  3992. boolT foundrem= False;
  3993. if (facet->simplicial) {
  3994. return False;
  3995. }
  3996. trace4((qh, qh->ferr, 4043, "qh_remove_extravertices: test non-simplicial f%d for extra vertices\n",
  3997. facet->id));
  3998. FOREACHvertex_(facet->vertices)
  3999. vertex->seen= False;
  4000. FOREACHridge_(facet->ridges) {
  4001. FOREACHvertex_(ridge->vertices)
  4002. vertex->seen= True;
  4003. }
  4004. FOREACHvertex_(facet->vertices) {
  4005. if (!vertex->seen) {
  4006. foundrem= True;
  4007. zinc_(Zremvertex);
  4008. qh_setdelsorted(facet->vertices, vertex);
  4009. qh_setdel(vertex->neighbors, facet);
  4010. if (!qh_setsize(qh, vertex->neighbors)) {
  4011. vertex->deleted= True;
  4012. qh_setappend(qh, &qh->del_vertices, vertex);
  4013. zinc_(Zremvertexdel);
  4014. trace2((qh, qh->ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
  4015. }else
  4016. trace3((qh, qh->ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
  4017. vertexp--; /*repeat*/
  4018. }
  4019. }
  4020. return foundrem;
  4021. } /* remove_extravertices */
  4022. /*-<a href="qh-merge_r.htm#TOC"
  4023. >-------------------------------</a><a name="remove_mergetype">-</a>
  4024. qh_remove_mergetype(qh, mergeset, mergetype )
  4025. Remove mergetype merges from mergeset
  4026. notes:
  4027. Does not preserve order
  4028. */
  4029. void qh_remove_mergetype(qhT *qh, setT *mergeset, mergeType type) {
  4030. mergeT *merge;
  4031. int merge_i, merge_n;
  4032. FOREACHmerge_i_(qh, mergeset) {
  4033. if (merge->mergetype == type) {
  4034. trace3((qh, qh->ferr, 3037, "qh_remove_mergetype: remove merge f%d f%d v%d v%d r%d r%d dist %2.2g type %d",
  4035. getid_(merge->facet1), getid_(merge->facet2), getid_(merge->vertex1), getid_(merge->vertex2), getid_(merge->ridge1), getid_(merge->ridge2), merge->distance, type));
  4036. qh_setdelnth(qh, mergeset, merge_i);
  4037. merge_i--; merge_n--; /* repeat with next merge */
  4038. }
  4039. }
  4040. } /* remove_mergetype */
  4041. /*-<a href="qh-merge_r.htm#TOC"
  4042. >-------------------------------</a><a name="rename_adjacentvertex">-</a>
  4043. qh_rename_adjacentvertex(qh, oldvertex, newvertex )
  4044. renames oldvertex as newvertex. Must be adjacent (i.e., in the same subridge)
  4045. no-op if either vertex is deleted
  4046. notes:
  4047. called from qh_merge_pinchedvertices
  4048. design:
  4049. for all neighbors of oldvertex
  4050. if simplicial, rename oldvertex to newvertex and drop if degenerate
  4051. if needed, add oldvertex neighbor to newvertex
  4052. determine ridges for oldvertex
  4053. rename oldvertex as newvertex in ridges (qh_renamevertex)
  4054. */
  4055. void qh_rename_adjacentvertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, realT dist) {
  4056. setT *ridges;
  4057. facetT *neighbor, **neighborp, *maxfacet= NULL;
  4058. ridgeT *ridge, **ridgep;
  4059. boolT istrace= False;
  4060. int oldsize= qh_setsize(qh, oldvertex->neighbors);
  4061. int newsize= qh_setsize(qh, newvertex->neighbors);
  4062. coordT maxdist2= -REALmax, dist2;
  4063. if (qh->IStracing >= 4 || oldvertex->id == qh->tracevertex_id || newvertex->id == qh->tracevertex_id) {
  4064. istrace= True;
  4065. }
  4066. zzinc_(Ztotmerge);
  4067. if (istrace) {
  4068. qh_fprintf(qh, qh->ferr, 2071, "qh_rename_adjacentvertex: merge #%d rename v%d (%d neighbors) to v%d (%d neighbors) dist %2.2g\n",
  4069. zzval_(Ztotmerge), oldvertex->id, oldsize, newvertex->id, newsize, dist);
  4070. }
  4071. if (oldvertex->deleted || newvertex->deleted) {
  4072. if (istrace || qh->IStracing >= 2) {
  4073. qh_fprintf(qh, qh->ferr, 2072, "qh_rename_adjacentvertex: ignore rename. Either v%d (%d) or v%d (%d) is deleted\n",
  4074. oldvertex->id, oldvertex->deleted, newvertex->id, newvertex->deleted);
  4075. }
  4076. return;
  4077. }
  4078. if (oldsize == 0 || newsize == 0) {
  4079. qh_fprintf(qh, qh->ferr, 2072, "qhull internal error (qh_rename_adjacentvertex): expecting neighbor facets for v%d and v%d. Got %d and %d neighbors resp.\n",
  4080. oldvertex->id, newvertex->id, oldsize, newsize);
  4081. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  4082. }
  4083. FOREACHneighbor_(oldvertex) {
  4084. if (neighbor->simplicial) {
  4085. if (qh_setin(neighbor->vertices, newvertex)) {
  4086. if (istrace || qh->IStracing >= 2) {
  4087. qh_fprintf(qh, qh->ferr, 2070, "qh_rename_adjacentvertex: simplicial f%d contains old v%d and new v%d. Will be marked degenerate by qh_renamevertex\n",
  4088. neighbor->id, oldvertex->id, newvertex->id);
  4089. }
  4090. qh_makeridges(qh, neighbor); /* no longer simplicial, nummerge==0, skipped by qh_maybe_duplicateridge */
  4091. }else {
  4092. qh_replacefacetvertex(qh, neighbor, oldvertex, newvertex);
  4093. qh_setunique(qh, &newvertex->neighbors, neighbor);
  4094. qh_newvertices(qh, neighbor->vertices); /* for qh_update_vertexneighbors of vertex neighbors */
  4095. }
  4096. }
  4097. }
  4098. ridges= qh_vertexridges(qh, oldvertex, qh_ALL);
  4099. if (istrace) {
  4100. FOREACHridge_(ridges) {
  4101. qh_printridge(qh, qh->ferr, ridge);
  4102. }
  4103. }
  4104. FOREACHneighbor_(oldvertex) {
  4105. if (!neighbor->simplicial){
  4106. qh_addfacetvertex(qh, neighbor, newvertex);
  4107. qh_setunique(qh, &newvertex->neighbors, neighbor);
  4108. qh_newvertices(qh, neighbor->vertices); /* for qh_update_vertexneighbors of vertex neighbors */
  4109. if (qh->newfacet_list == qh->facet_tail) {
  4110. qh_removefacet(qh, neighbor); /* add a neighbor to newfacet_list so that qh_partitionvisible has a newfacet */
  4111. qh_appendfacet(qh, neighbor);
  4112. neighbor->newfacet= True;
  4113. }
  4114. }
  4115. }
  4116. qh_renamevertex(qh, oldvertex, newvertex, ridges, NULL, NULL); /* ridges invalidated */
  4117. if (oldvertex->deleted && !oldvertex->partitioned) {
  4118. FOREACHneighbor_(newvertex) {
  4119. if (!neighbor->visible) {
  4120. qh_distplane(qh, oldvertex->point, neighbor, &dist2);
  4121. if (dist2>maxdist2) {
  4122. maxdist2= dist2;
  4123. maxfacet= neighbor;
  4124. }
  4125. }
  4126. }
  4127. trace2((qh, qh->ferr, 2096, "qh_rename_adjacentvertex: partition old p%d(v%d) as a coplanar point for furthest f%d dist %2.2g. Maybe repartition later (QH0031)\n",
  4128. qh_pointid(qh, oldvertex->point), oldvertex->id, maxfacet->id, maxdist2))
  4129. qh_partitioncoplanar(qh, oldvertex->point, maxfacet, NULL, !qh_ALL); /* faster with maxdist2, otherwise duplicates distance tests from maxdist2/dist2 */
  4130. oldvertex->partitioned= True;
  4131. }
  4132. qh_settempfree(qh, &ridges);
  4133. } /* rename_adjacentvertex */
  4134. /*-<a href="qh-merge_r.htm#TOC"
  4135. >-------------------------------</a><a name="rename_sharedvertex">-</a>
  4136. qh_rename_sharedvertex(qh, vertex, facet )
  4137. detect and rename if shared vertex in facet
  4138. vertices have full ->neighbors
  4139. returns:
  4140. newvertex or NULL
  4141. the vertex may still exist in other facets (i.e., a neighbor was pinched)
  4142. does not change facet->neighbors
  4143. updates vertex->neighbors
  4144. notes:
  4145. only called by qh_reducevertices after qh_remove_extravertices
  4146. so f.vertices does not contain extraneous vertices
  4147. a shared vertex for a facet is only in ridges to one neighbor
  4148. this may undo a pinched facet
  4149. it does not catch pinches involving multiple facets. These appear
  4150. to be difficult to detect, since an exhaustive search is too expensive.
  4151. design:
  4152. if vertex only has two neighbors
  4153. determine the ridges that contain the vertex
  4154. determine the vertices shared by both neighbors
  4155. if can find a new vertex in this set
  4156. rename the vertex to the new vertex
  4157. */
  4158. vertexT *qh_rename_sharedvertex(qhT *qh, vertexT *vertex, facetT *facet) {
  4159. facetT *neighbor, **neighborp, *neighborA= NULL;
  4160. setT *vertices, *ridges;
  4161. vertexT *newvertex= NULL;
  4162. if (qh_setsize(qh, vertex->neighbors) == 2) {
  4163. neighborA= SETfirstt_(vertex->neighbors, facetT);
  4164. if (neighborA == facet)
  4165. neighborA= SETsecondt_(vertex->neighbors, facetT);
  4166. }else if (qh->hull_dim == 3)
  4167. return NULL;
  4168. else {
  4169. qh->visit_id++;
  4170. FOREACHneighbor_(facet)
  4171. neighbor->visitid= qh->visit_id;
  4172. FOREACHneighbor_(vertex) {
  4173. if (neighbor->visitid == qh->visit_id) {
  4174. if (neighborA)
  4175. return NULL;
  4176. neighborA= neighbor;
  4177. }
  4178. }
  4179. }
  4180. if (!neighborA) {
  4181. qh_fprintf(qh, qh->ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
  4182. vertex->id, facet->id);
  4183. qh_errprint(qh, "ERRONEOUS", facet, NULL, NULL, vertex);
  4184. qh_errexit(qh, qh_ERRqhull, NULL, NULL);
  4185. }
  4186. if (neighborA) { /* avoid warning */
  4187. /* the vertex is shared by facet and neighborA */
  4188. ridges= qh_settemp(qh, qh->TEMPsize);
  4189. neighborA->visitid= ++qh->visit_id;
  4190. qh_vertexridges_facet(qh, vertex, facet, &ridges);
  4191. trace2((qh, qh->ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n",
  4192. qh_pointid(qh, vertex->point), vertex->id, facet->id, qh_setsize(qh, ridges), neighborA->id));
  4193. zinc_(Zintersectnum);
  4194. vertices= qh_vertexintersect_new(qh, facet->vertices, neighborA->vertices);
  4195. qh_setdel(vertices, vertex);
  4196. qh_settemppush(qh, vertices);
  4197. if ((newvertex= qh_find_newvertex(qh, vertex, vertices, ridges)))
  4198. qh_renamevertex(qh, vertex, newvertex, ridges, facet, neighborA); /* ridges invalidated */
  4199. qh_settempfree(qh, &vertices);
  4200. qh_settempfree(qh, &ridges);
  4201. }
  4202. return newvertex;
  4203. } /* rename_sharedvertex */
  4204. /*-<a href="qh-merge_r.htm#TOC"
  4205. >-------------------------------</a><a name="renameridgevertex">-</a>
  4206. qh_renameridgevertex(qh, ridge, oldvertex, newvertex )
  4207. renames oldvertex as newvertex in ridge
  4208. returns:
  4209. True if renames oldvertex
  4210. False if deleted the ridge
  4211. notes:
  4212. called by qh_renamevertex
  4213. caller sets newvertex->delridge for deleted ridges (qh_reducevertices)
  4214. design:
  4215. delete oldvertex from ridge
  4216. if newvertex already in ridge
  4217. copy ridge->noconvex to another ridge if possible
  4218. delete the ridge
  4219. else
  4220. insert newvertex into the ridge
  4221. adjust the ridge's orientation
  4222. */
  4223. boolT qh_renameridgevertex(qhT *qh, ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
  4224. int nth= 0, oldnth;
  4225. facetT *temp;
  4226. vertexT *vertex, **vertexp;
  4227. oldnth= qh_setindex(ridge->vertices, oldvertex);
  4228. if (oldnth < 0) {
  4229. qh_fprintf(qh, qh->ferr, 6424, "qhull internal error (qh_renameridgevertex): oldvertex v%d not found in r%d. Cannot rename to v%d\n",
  4230. oldvertex->id, ridge->id, newvertex->id);
  4231. qh_errexit(qh, qh_ERRqhull, NULL, ridge);
  4232. }
  4233. qh_setdelnthsorted(qh, ridge->vertices, oldnth);
  4234. FOREACHvertex_(ridge->vertices) {
  4235. if (vertex == newvertex) {
  4236. zinc_(Zdelridge);
  4237. if (ridge->nonconvex) /* only one ridge has nonconvex set */
  4238. qh_copynonconvex(qh, ridge);
  4239. trace2((qh, qh->ferr, 2038, "qh_renameridgevertex: ridge r%d deleted. It contained both v%d and v%d\n",
  4240. ridge->id, oldvertex->id, newvertex->id));
  4241. qh_delridge_merge(qh, ridge); /* ridge.vertices deleted */
  4242. return False;
  4243. }
  4244. if (vertex->id < newvertex->id)
  4245. break;
  4246. nth++;
  4247. }
  4248. qh_setaddnth(qh, &ridge->vertices, nth, newvertex);
  4249. ridge->simplicialtop= False;
  4250. ridge->simplicialbot= False;
  4251. if (abs(oldnth - nth)%2) {
  4252. trace3((qh, qh->ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
  4253. ridge->id));
  4254. temp= ridge->top;
  4255. ridge->top= ridge->bottom;
  4256. ridge->bottom= temp;
  4257. }
  4258. return True;
  4259. } /* renameridgevertex */
  4260. /*-<a href="qh-merge_r.htm#TOC"
  4261. >-------------------------------</a><a name="renamevertex">-</a>
  4262. qh_renamevertex(qh, oldvertex, newvertex, ridges, oldfacet, neighborA )
  4263. renames oldvertex as newvertex in ridges of non-simplicial neighbors
  4264. set oldfacet/neighborA if oldvertex is shared between two facets (qh_rename_sharedvertex)
  4265. otherwise qh_redundant_vertex or qh_rename_adjacentvertex
  4266. returns:
  4267. if oldfacet and multiple neighbors, oldvertex may still exist afterwards
  4268. otherwise sets oldvertex->deleted for later deletion
  4269. one or more ridges maybe deleted
  4270. ridges is invalidated
  4271. merges may be added to degen_mergeset via qh_maydropneighbor or qh_degen_redundant_facet
  4272. notes:
  4273. qh_rename_sharedvertex can not change neighbors of newvertex (since it's a subset)
  4274. qh_redundant_vertex due to vertex->delridge for qh_reducevertices
  4275. qh_rename_adjacentvertex for complete renames
  4276. design:
  4277. for each ridge in ridges
  4278. rename oldvertex to newvertex and delete degenerate ridges
  4279. if oldfacet not defined
  4280. for each non-simplicial neighbor of oldvertex
  4281. delete oldvertex from neighbor's vertices
  4282. remove extra vertices from neighbor
  4283. add oldvertex to qh.del_vertices
  4284. else if oldvertex only between oldfacet and neighborA
  4285. delete oldvertex from oldfacet and neighborA
  4286. add oldvertex to qh.del_vertices
  4287. else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
  4288. delete oldvertex from oldfacet
  4289. delete oldfacet from old vertex's neighbors
  4290. remove extra vertices (e.g., oldvertex) from neighborA
  4291. */
  4292. void qh_renamevertex(qhT *qh, vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
  4293. facetT *neighbor, **neighborp;
  4294. ridgeT *ridge, **ridgep;
  4295. int topsize, bottomsize;
  4296. boolT istrace= False;
  4297. #ifndef qh_NOtrace
  4298. if (qh->IStracing >= 2 || oldvertex->id == qh->tracevertex_id ||
  4299. newvertex->id == qh->tracevertex_id) {
  4300. istrace= True;
  4301. qh_fprintf(qh, qh->ferr, 2086, "qh_renamevertex: rename v%d to v%d in %d ridges with old f%d and neighbor f%d\n",
  4302. oldvertex->id, newvertex->id, qh_setsize(qh, ridges), getid_(oldfacet), getid_(neighborA));
  4303. }
  4304. #endif
  4305. FOREACHridge_(ridges) {
  4306. if (qh_renameridgevertex(qh, ridge, oldvertex, newvertex)) { /* ridge is deleted if False, invalidating ridges */
  4307. topsize= qh_setsize(qh, ridge->top->vertices);
  4308. bottomsize= qh_setsize(qh, ridge->bottom->vertices);
  4309. if (topsize < qh->hull_dim || (topsize == qh->hull_dim && !ridge->top->simplicial && qh_setin(ridge->top->vertices, newvertex))) {
  4310. trace4((qh, qh->ferr, 4070, "qh_renamevertex: ignore duplicate check for r%d. top f%d (size %d) will be degenerate after rename v%d to v%d\n",
  4311. ridge->id, ridge->top->id, topsize, oldvertex->id, newvertex->id));
  4312. }else if (bottomsize < qh->hull_dim || (bottomsize == qh->hull_dim && !ridge->bottom->simplicial && qh_setin(ridge->bottom->vertices, newvertex))) {
  4313. trace4((qh, qh->ferr, 4071, "qh_renamevertex: ignore duplicate check for r%d. bottom f%d (size %d) will be degenerate after rename v%d to v%d\n",
  4314. ridge->id, ridge->bottom->id, bottomsize, oldvertex->id, newvertex->id));
  4315. }else
  4316. qh_maybe_duplicateridge(qh, ridge);
  4317. }
  4318. }
  4319. if (!oldfacet) {
  4320. /* stat Zrenameall or Zpinchduplicate */
  4321. if (istrace)
  4322. qh_fprintf(qh, qh->ferr, 2087, "qh_renamevertex: renaming v%d to v%d in several facets for qh_redundant_vertex or MRGsubridge\n",
  4323. oldvertex->id, newvertex->id);
  4324. FOREACHneighbor_(oldvertex) {
  4325. if (neighbor->simplicial) {
  4326. qh_degen_redundant_facet(qh, neighbor); /* e.g., rbox 175 C3,2e-13 D4 t1545235541 | qhull d */
  4327. }else {
  4328. if (istrace)
  4329. qh_fprintf(qh, qh->ferr, 4080, "qh_renamevertex: rename vertices in non-simplicial neighbor f%d of v%d\n", neighbor->id, oldvertex->id);
  4330. qh_maydropneighbor(qh, neighbor);
  4331. qh_setdelsorted(neighbor->vertices, oldvertex); /* if degenerate, qh_degen_redundant_facet will add to mergeset */
  4332. if (qh_remove_extravertices(qh, neighbor))
  4333. neighborp--; /* neighbor deleted from oldvertex neighborset */
  4334. qh_degen_redundant_facet(qh, neighbor); /* either direction may be redundant, faster if combine? */
  4335. qh_test_redundant_neighbors(qh, neighbor);
  4336. qh_test_degen_neighbors(qh, neighbor);
  4337. }
  4338. }
  4339. if (!oldvertex->deleted) {
  4340. oldvertex->deleted= True;
  4341. qh_setappend(qh, &qh->del_vertices, oldvertex);
  4342. }
  4343. }else if (qh_setsize(qh, oldvertex->neighbors) == 2) {
  4344. zinc_(Zrenameshare);
  4345. if (istrace)
  4346. qh_fprintf(qh, qh->ferr, 3039, "qh_renamevertex: renaming v%d to v%d in oldfacet f%d for qh_rename_sharedvertex\n",
  4347. oldvertex->id, newvertex->id, oldfacet->id);
  4348. FOREACHneighbor_(oldvertex) {
  4349. qh_setdelsorted(neighbor->vertices, oldvertex);
  4350. qh_degen_redundant_facet(qh, neighbor);
  4351. }
  4352. oldvertex->deleted= True;
  4353. qh_setappend(qh, &qh->del_vertices, oldvertex);
  4354. }else {
  4355. zinc_(Zrenamepinch);
  4356. if (istrace || qh->IStracing >= 1)
  4357. qh_fprintf(qh, qh->ferr, 3040, "qh_renamevertex: renaming pinched v%d to v%d between f%d and f%d\n",
  4358. oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
  4359. qh_setdelsorted(oldfacet->vertices, oldvertex);
  4360. qh_setdel(oldvertex->neighbors, oldfacet);
  4361. if (qh_remove_extravertices(qh, neighborA))
  4362. qh_degen_redundant_facet(qh, neighborA);
  4363. }
  4364. if (oldfacet)
  4365. qh_degen_redundant_facet(qh, oldfacet);
  4366. } /* renamevertex */
  4367. /*-<a href="qh-merge_r.htm#TOC"
  4368. >-------------------------------</a><a name="test_appendmerge">-</a>
  4369. qh_test_appendmerge(qh, facet, neighbor, simplicial )
  4370. test convexity and append to qh.facet_mergeset if non-convex
  4371. if pre-merging,
  4372. no-op if qh.SKIPconvex, or qh.MERGEexact and coplanar
  4373. if simplicial, assumes centrum test is valid (e.g., adjacent, simplicial new facets)
  4374. returns:
  4375. true if appends facet/neighbor to qh.facet_mergeset
  4376. sets facet->center as needed
  4377. does not change facet->seen
  4378. notes:
  4379. called from qh_getmergeset_initial, qh_getmergeset, and qh_test_vneighbors
  4380. must be at least as strong as qh_checkconvex (poly2_r.c)
  4381. assumes !f.flipped
  4382. design:
  4383. exit if qh.SKIPconvex ('Q0') and !qh.POSTmerging
  4384. if qh.cos_max ('An') is defined and merging coplanars
  4385. if the angle between facet normals is too shallow
  4386. append an angle-coplanar merge to qh.mergeset
  4387. return True
  4388. test convexity of facet and neighbor
  4389. */
  4390. boolT qh_test_appendmerge(qhT *qh, facetT *facet, facetT *neighbor, boolT simplicial) {
  4391. realT angle= -REALmax;
  4392. boolT okangle= False;
  4393. if (qh->SKIPconvex && !qh->POSTmerging)
  4394. return False;
  4395. if (qh->cos_max < REALmax/2 && (!qh->MERGEexact || qh->POSTmerging)) {
  4396. angle= qh_getangle(qh, facet->normal, neighbor->normal);
  4397. okangle= True;
  4398. zinc_(Zangletests);
  4399. if (angle > qh->cos_max) {
  4400. zinc_(Zcoplanarangle);
  4401. qh_appendmergeset(qh, facet, neighbor, MRGanglecoplanar, 0.0, angle);
  4402. trace2((qh, qh->ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
  4403. angle, facet->id, neighbor->id));
  4404. return True;
  4405. }
  4406. }
  4407. if (simplicial || qh->hull_dim <= 3)
  4408. return qh_test_centrum_merge(qh, facet, neighbor, angle, okangle);
  4409. else
  4410. return qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle);
  4411. } /* test_appendmerge */
  4412. /*-<a href="qh-merge_r.htm#TOC"
  4413. >-------------------------------</a><a name="test_centrum_merge">-</a>
  4414. qh_test_centrum_merge(qh, facet, neighbor, angle, okangle )
  4415. test centrum convexity and append non-convex facets to qh.facet_mergeset
  4416. 'angle' is angle between facets if okangle is true, otherwise use 0.0
  4417. returns:
  4418. true if append facet/neighbor to qh.facet_mergeset
  4419. sets facet->center as needed
  4420. does not change facet->seen
  4421. notes:
  4422. called from test_appendmerge if adjacent simplicial facets or 2-d/3-d
  4423. at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
  4424. design:
  4425. make facet's centrum if needed
  4426. if facet's centrum is above the neighbor (qh.centrum_radius)
  4427. set isconcave
  4428. if facet's centrum is not below the neighbor (-qh.centrum_radius)
  4429. set iscoplanar
  4430. make neighbor's centrum if needed
  4431. if neighbor's centrum is above the facet
  4432. set isconcave
  4433. else if neighbor's centrum is not below the facet
  4434. set iscoplanar
  4435. if isconcave or iscoplanar and merging coplanars
  4436. get angle if needed (qh.ANGLEmerge 'An')
  4437. append concave-coplanar, concave ,or coplanar merge to qh.mergeset
  4438. */
  4439. boolT qh_test_centrum_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  4440. coordT dist, dist2, mergedist;
  4441. boolT isconcave= False, iscoplanar= False;
  4442. if (!facet->center)
  4443. facet->center= qh_getcentrum(qh, facet);
  4444. zzinc_(Zcentrumtests);
  4445. qh_distplane(qh, facet->center, neighbor, &dist);
  4446. if (dist > qh->centrum_radius)
  4447. isconcave= True;
  4448. else if (dist >= -qh->centrum_radius)
  4449. iscoplanar= True;
  4450. if (!neighbor->center)
  4451. neighbor->center= qh_getcentrum(qh, neighbor);
  4452. zzinc_(Zcentrumtests);
  4453. qh_distplane(qh, neighbor->center, facet, &dist2);
  4454. if (dist2 > qh->centrum_radius)
  4455. isconcave= True;
  4456. else if (!iscoplanar && dist2 >= -qh->centrum_radius)
  4457. iscoplanar= True;
  4458. if (!isconcave && (!iscoplanar || (qh->MERGEexact && !qh->POSTmerging)))
  4459. return False;
  4460. if (!okangle && qh->ANGLEmerge) {
  4461. angle= qh_getangle(qh, facet->normal, neighbor->normal);
  4462. zinc_(Zangletests);
  4463. }
  4464. if (isconcave && iscoplanar) {
  4465. zinc_(Zconcavecoplanarridge);
  4466. if (dist > dist2)
  4467. qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, dist, angle);
  4468. else
  4469. qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, dist2, angle);
  4470. trace0((qh, qh->ferr, 36, "qh_test_centrum_merge: concave f%d to coplanar f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4471. facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
  4472. }else if (isconcave) {
  4473. mergedist= fmax_(dist, dist2);
  4474. zinc_(Zconcaveridge);
  4475. qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
  4476. trace0((qh, qh->ferr, 37, "qh_test_centrum_merge: concave f%d to f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4477. facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
  4478. }else /* iscoplanar */ {
  4479. mergedist= fmin_(fabs_(dist), fabs_(dist2));
  4480. zinc_(Zcoplanarcentrum);
  4481. qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
  4482. trace2((qh, qh->ferr, 2097, "qh_test_centrum_merge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
  4483. facet->id, neighbor->id, dist, dist2, angle));
  4484. }
  4485. return True;
  4486. } /* test_centrum_merge */
  4487. /*-<a href="qh-merge_r.htm#TOC"
  4488. >-------------------------------</a><a name="test_degen_neighbors">-</a>
  4489. qh_test_degen_neighbors(qh, facet )
  4490. append degenerate neighbors to qh.degen_mergeset
  4491. notes:
  4492. called at end of qh_mergefacet() and qh_renamevertex()
  4493. call after test_redundant_facet() since MRGredundant is less expensive then MRGdegen
  4494. a degenerate facet has fewer than hull_dim neighbors
  4495. see: qh_merge_degenredundant()
  4496. */
  4497. void qh_test_degen_neighbors(qhT *qh, facetT *facet) {
  4498. facetT *neighbor, **neighborp;
  4499. int size;
  4500. trace4((qh, qh->ferr, 4073, "qh_test_degen_neighbors: test for degenerate neighbors of f%d\n", facet->id));
  4501. FOREACHneighbor_(facet) {
  4502. if (neighbor->visible) {
  4503. qh_fprintf(qh, qh->ferr, 6359, "qhull internal error (qh_test_degen_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
  4504. facet->id, neighbor->id);
  4505. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  4506. }
  4507. if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
  4508. continue;
  4509. /* merge flipped-degenerate facet before flipped facets */
  4510. if ((size= qh_setsize(qh, neighbor->neighbors)) < qh->hull_dim) {
  4511. qh_appendmergeset(qh, neighbor, neighbor, MRGdegen, 0.0, 1.0);
  4512. trace2((qh, qh->ferr, 2019, "qh_test_degen_neighbors: f%d is degenerate with %d neighbors. Neighbor of f%d.\n", neighbor->id, size, facet->id));
  4513. }
  4514. }
  4515. } /* test_degen_neighbors */
  4516. /*-<a href="qh-merge_r.htm#TOC"
  4517. >-------------------------------</a><a name="test_nonsimplicial_merge">-</a>
  4518. qh_test_nonsimplicial_merge(qh, facet, neighbor, angle, okangle )
  4519. test centrum and vertex convexity and append non-convex or redundant facets to qh.facet_mergeset
  4520. 'angle' is angle between facets if okangle is true, otherwise use 0.0
  4521. skips coplanar merges if pre-merging with qh.MERGEexact ('Qx')
  4522. returns:
  4523. true if appends facet/neighbor to qh.facet_mergeset
  4524. sets facet->center as needed
  4525. does not change facet->seen
  4526. notes:
  4527. only called from test_appendmerge if a non-simplicial facet and at least 4-d
  4528. at least as strict as qh_checkconvex, including qh.DISTround ('En' and 'Rn')
  4529. centrums must be < -qh.centrum_radius
  4530. tests vertices as well as centrums since a facet may be twisted relative to its neighbor
  4531. design:
  4532. set precision constants for maxoutside, clearlyconcave, minvertex, and coplanarcentrum
  4533. use maxoutside for coplanarcentrum if premerging with 'Qx' and qh_MAXcoplanarcentrum merges
  4534. otherwise use qh.centrum_radious for coplanarcentrum
  4535. make facet and neighbor centrums if needed
  4536. isconcave if a centrum is above neighbor (coplanarcentrum)
  4537. iscoplanar if a centrum is not below neighbor (-qh.centrum_radius)
  4538. maybeconvex if a centrum is clearly below neighbor (-clearyconvex)
  4539. return False if both centrums clearly below neighbor (-clearyconvex)
  4540. return MRGconcave if isconcave
  4541. facets are neither clearly convex nor clearly concave
  4542. test vertices as well as centrums
  4543. if maybeconvex
  4544. determine mindist and maxdist for vertices of the other facet
  4545. maybe MRGredundant
  4546. otherwise
  4547. determine mindist and maxdist for vertices of either facet
  4548. maybe MRGredundant
  4549. maybeconvex if a vertex is clearly below neighbor (-clearconvex)
  4550. vertices are concave if dist > clearlyconcave
  4551. vertices are twisted if dist > maxoutside (isconcave and maybeconvex)
  4552. return False if not concave and pre-merge of 'Qx' (qh.MERGEexact)
  4553. vertices are coplanar if dist in -minvertex..maxoutside
  4554. if !isconcave, vertices are coplanar if dist >= -qh.MAXcoplanar (n*qh.premerge_centrum)
  4555. return False if neither concave nor coplanar
  4556. return MRGtwisted if isconcave and maybeconvex
  4557. return MRGconcavecoplanar if isconcave and isconvex
  4558. return MRGconcave if isconcave
  4559. return MRGcoplanar if iscoplanar
  4560. */
  4561. boolT qh_test_nonsimplicial_merge(qhT *qh, facetT *facet, facetT *neighbor, realT angle, boolT okangle) {
  4562. coordT dist, mindist, maxdist, mindist2, maxdist2, dist2, maxoutside, clearlyconcave, minvertex, clearlyconvex, mergedist, coplanarcentrum;
  4563. boolT isconcave= False, iscoplanar= False, maybeconvex= False, isredundant= False;
  4564. vertexT *maxvertex= NULL, *maxvertex2= NULL;
  4565. maxoutside= fmax_(neighbor->maxoutside, qh->ONEmerge + qh->DISTround);
  4566. maxoutside= fmax_(maxoutside, facet->maxoutside);
  4567. clearlyconcave= qh_RATIOconcavehorizon * maxoutside;
  4568. minvertex= fmax_(-qh->min_vertex, qh->MAXcoplanar); /* non-negative, not available per facet, not used for iscoplanar */
  4569. clearlyconvex= qh_RATIOconvexmerge * minvertex; /* must be convex for MRGtwisted */
  4570. if (qh->MERGEexact && !qh->POSTmerging && (facet->nummerge > qh_MAXcoplanarcentrum || neighbor->nummerge > qh_MAXcoplanarcentrum))
  4571. coplanarcentrum= maxoutside;
  4572. else
  4573. coplanarcentrum= qh->centrum_radius;
  4574. if (!facet->center)
  4575. facet->center= qh_getcentrum(qh, facet);
  4576. zzinc_(Zcentrumtests);
  4577. qh_distplane(qh, facet->center, neighbor, &dist);
  4578. if (dist > coplanarcentrum)
  4579. isconcave= True;
  4580. else if (dist >= -qh->centrum_radius)
  4581. iscoplanar= True;
  4582. else if (dist < -clearlyconvex)
  4583. maybeconvex= True;
  4584. if (!neighbor->center)
  4585. neighbor->center= qh_getcentrum(qh, neighbor);
  4586. zzinc_(Zcentrumtests);
  4587. qh_distplane(qh, neighbor->center, facet, &dist2);
  4588. if (dist2 > coplanarcentrum)
  4589. isconcave= True;
  4590. else if (dist2 >= -qh->centrum_radius)
  4591. iscoplanar= True;
  4592. else if (dist2 < -clearlyconvex) {
  4593. if (maybeconvex)
  4594. return False; /* both centrums clearly convex */
  4595. maybeconvex= True;
  4596. }
  4597. if (isconcave) {
  4598. if (!okangle && qh->ANGLEmerge) {
  4599. angle= qh_getangle(qh, facet->normal, neighbor->normal);
  4600. zinc_(Zangletests);
  4601. }
  4602. mergedist= fmax_(dist, dist2);
  4603. zinc_(Zconcaveridge);
  4604. qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
  4605. trace0((qh, qh->ferr, 18, "qh_test_nonsimplicial_merge: concave centrum for f%d or f%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4606. facet->id, neighbor->id, dist, dist2, angle, qh->furthest_id));
  4607. return True;
  4608. }
  4609. /* neither clearly convex nor clearly concave, test vertices as well as centrums */
  4610. if (maybeconvex) {
  4611. if (dist < -clearlyconvex) {
  4612. maxdist= dist; /* facet centrum clearly convex, no need to test its vertex distance */
  4613. mindist= dist;
  4614. maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
  4615. if (!maxvertex2) {
  4616. qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
  4617. isredundant= True;
  4618. }
  4619. }else { /* dist2 < -clearlyconvex */
  4620. maxdist2= dist2; /* neighbor centrum clearly convex, no need to test its vertex distance */
  4621. mindist2= dist2;
  4622. maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
  4623. if (!maxvertex) {
  4624. qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
  4625. isredundant= True;
  4626. }
  4627. }
  4628. }else {
  4629. maxvertex= qh_furthestvertex(qh, facet, neighbor, &maxdist, &mindist);
  4630. if (maxvertex) {
  4631. maxvertex2= qh_furthestvertex(qh, neighbor, facet, &maxdist2, &mindist2);
  4632. if (!maxvertex2) {
  4633. qh_appendmergeset(qh, neighbor, facet, MRGredundant, maxdist2, qh_ANGLEnone);
  4634. isredundant= True;
  4635. }else if (mindist < -clearlyconvex || mindist2 < -clearlyconvex)
  4636. maybeconvex= True;
  4637. }else { /* !maxvertex */
  4638. qh_appendmergeset(qh, facet, neighbor, MRGredundant, maxdist, qh_ANGLEnone);
  4639. isredundant= True;
  4640. }
  4641. }
  4642. if (isredundant) {
  4643. zinc_(Zredundantmerge);
  4644. return True;
  4645. }
  4646. if (maxdist > clearlyconcave || maxdist2 > clearlyconcave)
  4647. isconcave= True;
  4648. else if (maybeconvex) {
  4649. if (maxdist > maxoutside || maxdist2 > maxoutside)
  4650. isconcave= True; /* MRGtwisted */
  4651. }
  4652. if (!isconcave && qh->MERGEexact && !qh->POSTmerging)
  4653. return False;
  4654. if (isconcave && !iscoplanar) {
  4655. if (maxdist < maxoutside && (-qh->MAXcoplanar || (maxdist2 < maxoutside && mindist2 >= -qh->MAXcoplanar)))
  4656. iscoplanar= True; /* MRGconcavecoplanar */
  4657. }else if (!iscoplanar) {
  4658. if (mindist >= -qh->MAXcoplanar || mindist2 >= -qh->MAXcoplanar)
  4659. iscoplanar= True; /* MRGcoplanar */
  4660. }
  4661. if (!isconcave && !iscoplanar)
  4662. return False;
  4663. if (!okangle && qh->ANGLEmerge) {
  4664. angle= qh_getangle(qh, facet->normal, neighbor->normal);
  4665. zinc_(Zangletests);
  4666. }
  4667. if (isconcave && maybeconvex) {
  4668. zinc_(Ztwistedridge);
  4669. if (maxdist > maxdist2)
  4670. qh_appendmergeset(qh, facet, neighbor, MRGtwisted, maxdist, angle);
  4671. else
  4672. qh_appendmergeset(qh, neighbor, facet, MRGtwisted, maxdist2, angle);
  4673. trace0((qh, qh->ferr, 27, "qh_test_nonsimplicial_merge: twisted concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4674. facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  4675. }else if (isconcave && iscoplanar) {
  4676. zinc_(Zconcavecoplanarridge);
  4677. if (maxdist > maxdist2)
  4678. qh_appendmergeset(qh, facet, neighbor, MRGconcavecoplanar, maxdist, angle);
  4679. else
  4680. qh_appendmergeset(qh, neighbor, facet, MRGconcavecoplanar, maxdist2, angle);
  4681. trace0((qh, qh->ferr, 28, "qh_test_nonsimplicial_merge: concave coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4682. facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  4683. }else if (isconcave) {
  4684. mergedist= fmax_(maxdist, maxdist2);
  4685. zinc_(Zconcaveridge);
  4686. qh_appendmergeset(qh, facet, neighbor, MRGconcave, mergedist, angle);
  4687. trace0((qh, qh->ferr, 29, "qh_test_nonsimplicial_merge: concave f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4688. facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  4689. }else /* iscoplanar */ {
  4690. mergedist= fmax_(fmax_(maxdist, maxdist2), fmax_(-mindist, -mindist2));
  4691. zinc_(Zcoplanarcentrum);
  4692. qh_appendmergeset(qh, facet, neighbor, MRGcoplanar, mergedist, angle);
  4693. trace2((qh, qh->ferr, 2099, "qh_test_nonsimplicial_merge: coplanar f%d v%d to f%d v%d, dist %4.4g and reverse dist %4.4g, angle %4.4g during p%d\n",
  4694. facet->id, getid_(maxvertex), neighbor->id, getid_(maxvertex2), maxdist, maxdist2, angle, qh->furthest_id));
  4695. }
  4696. return True;
  4697. } /* test_nonsimplicial_merge */
  4698. /*-<a href="qh-merge_r.htm#TOC"
  4699. >-------------------------------</a><a name="test_redundant_neighbors">-</a>
  4700. qh_test_redundant_neighbors(qh, facet )
  4701. append degenerate facet or its redundant neighbors to qh.degen_mergeset
  4702. returns:
  4703. bumps vertex_visit
  4704. notes:
  4705. called at end of qh_mergefacet(), qh_mergecycle_all(), and qh_renamevertex
  4706. call before qh_test_degen_neighbors (MRGdegen are more likely to cause problems)
  4707. a redundant neighbor's vertices is a subset of the facet's vertices
  4708. with pinched and flipped facets, a redundant neighbor may have a wildly different normal
  4709. see qh_merge_degenredundant() and qh_-_facet()
  4710. design:
  4711. if facet is degenerate
  4712. appends facet to degen_mergeset
  4713. else
  4714. appends redundant neighbors of facet to degen_mergeset
  4715. */
  4716. void qh_test_redundant_neighbors(qhT *qh, facetT *facet) {
  4717. vertexT *vertex, **vertexp;
  4718. facetT *neighbor, **neighborp;
  4719. int size;
  4720. trace4((qh, qh->ferr, 4022, "qh_test_redundant_neighbors: test neighbors of f%d vertex_visit %d\n",
  4721. facet->id, qh->vertex_visit+1));
  4722. if ((size= qh_setsize(qh, facet->neighbors)) < qh->hull_dim) {
  4723. qh_appendmergeset(qh, facet, facet, MRGdegen, 0.0, 1.0);
  4724. trace2((qh, qh->ferr, 2017, "qh_test_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
  4725. }else {
  4726. qh->vertex_visit++;
  4727. FOREACHvertex_(facet->vertices)
  4728. vertex->visitid= qh->vertex_visit;
  4729. FOREACHneighbor_(facet) {
  4730. if (neighbor->visible) {
  4731. qh_fprintf(qh, qh->ferr, 6360, "qhull internal error (qh_test_redundant_neighbors): facet f%d has deleted neighbor f%d (qh.visible_list)\n",
  4732. facet->id, neighbor->id);
  4733. qh_errexit2(qh, qh_ERRqhull, facet, neighbor);
  4734. }
  4735. if (neighbor->degenerate || neighbor->redundant || neighbor->dupridge) /* will merge or delete */
  4736. continue;
  4737. if (facet->flipped && !neighbor->flipped) /* do not merge non-flipped into flipped */
  4738. continue;
  4739. /* merge redundant-flipped facet first */
  4740. /* uses early out instead of checking vertex count */
  4741. FOREACHvertex_(neighbor->vertices) {
  4742. if (vertex->visitid != qh->vertex_visit)
  4743. break;
  4744. }
  4745. if (!vertex) {
  4746. qh_appendmergeset(qh, neighbor, facet, MRGredundant, 0.0, 1.0);
  4747. trace2((qh, qh->ferr, 2018, "qh_test_redundant_neighbors: f%d is contained in f%d. merge\n", neighbor->id, facet->id));
  4748. }
  4749. }
  4750. }
  4751. } /* test_redundant_neighbors */
  4752. /*-<a href="qh-merge_r.htm#TOC"
  4753. >-------------------------------</a><a name="test_vneighbors">-</a>
  4754. qh_test_vneighbors(qh)
  4755. test vertex neighbors for convexity
  4756. tests all facets on qh.newfacet_list
  4757. returns:
  4758. true if non-convex vneighbors appended to qh.facet_mergeset
  4759. initializes vertex neighbors if needed
  4760. notes:
  4761. called by qh_all_merges from qh_postmerge if qh.TESTvneighbors ('Qv')
  4762. assumes all facet neighbors have been tested
  4763. this can be expensive
  4764. this does not guarantee that a centrum is below all facets
  4765. but it is unlikely
  4766. uses qh.visit_id
  4767. design:
  4768. build vertex neighbors if necessary
  4769. for all new facets
  4770. for all vertices
  4771. for each unvisited facet neighbor of the vertex
  4772. test new facet and neighbor for convexity
  4773. */
  4774. boolT qh_test_vneighbors(qhT *qh /* qh.newfacet_list */) {
  4775. facetT *newfacet, *neighbor, **neighborp;
  4776. vertexT *vertex, **vertexp;
  4777. int nummerges= 0;
  4778. trace1((qh, qh->ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
  4779. if (!qh->VERTEXneighbors)
  4780. qh_vertexneighbors(qh);
  4781. FORALLnew_facets
  4782. newfacet->seen= False;
  4783. FORALLnew_facets {
  4784. newfacet->seen= True;
  4785. newfacet->visitid= qh->visit_id++;
  4786. FOREACHneighbor_(newfacet)
  4787. newfacet->visitid= qh->visit_id;
  4788. FOREACHvertex_(newfacet->vertices) {
  4789. FOREACHneighbor_(vertex) {
  4790. if (neighbor->seen || neighbor->visitid == qh->visit_id)
  4791. continue;
  4792. if (qh_test_appendmerge(qh, newfacet, neighbor, False)) /* ignores optimization for simplicial ridges */
  4793. nummerges++;
  4794. }
  4795. }
  4796. }
  4797. zadd_(Ztestvneighbor, nummerges);
  4798. trace1((qh, qh->ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
  4799. nummerges));
  4800. return (nummerges > 0);
  4801. } /* test_vneighbors */
  4802. /*-<a href="qh-merge_r.htm#TOC"
  4803. >-------------------------------</a><a name="tracemerge">-</a>
  4804. qh_tracemerge(qh, facet1, facet2 )
  4805. print trace message after merge
  4806. */
  4807. void qh_tracemerge(qhT *qh, facetT *facet1, facetT *facet2, mergeType mergetype) {
  4808. boolT waserror= False;
  4809. const char *mergename;
  4810. #ifndef qh_NOtrace
  4811. if(mergetype > 0 && mergetype < sizeof(mergetypes)/sizeof(char *))
  4812. mergename= mergetypes[mergetype];
  4813. else
  4814. mergename= mergetypes[MRGnone];
  4815. if (qh->IStracing >= 4)
  4816. qh_errprint(qh, "MERGED", facet2, NULL, NULL, NULL);
  4817. if (facet2 == qh->tracefacet || (qh->tracevertex && qh->tracevertex->newfacet)) {
  4818. qh_fprintf(qh, qh->ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d into f%d type %d (%s), furthest p%d\n",
  4819. facet1->id, facet2->id, mergetype, mergename, qh->furthest_id);
  4820. if (facet2 != qh->tracefacet)
  4821. qh_errprint(qh, "TRACE", qh->tracefacet,
  4822. (qh->tracevertex && qh->tracevertex->neighbors) ?
  4823. SETfirstt_(qh->tracevertex->neighbors, facetT) : NULL,
  4824. NULL, qh->tracevertex);
  4825. }
  4826. if (qh->tracevertex) {
  4827. if (qh->tracevertex->deleted)
  4828. qh_fprintf(qh, qh->ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
  4829. qh->furthest_id);
  4830. else
  4831. qh_checkvertex(qh, qh->tracevertex, qh_ALL, &waserror);
  4832. }
  4833. if (qh->tracefacet && qh->tracefacet->normal && !qh->tracefacet->visible)
  4834. qh_checkfacet(qh, qh->tracefacet, True /* newmerge */, &waserror);
  4835. #endif /* !qh_NOtrace */
  4836. if (qh->CHECKfrequently || qh->IStracing >= 4) { /* can't check polygon here */
  4837. if (qh->IStracing >= 4 && qh->num_facets < 500) {
  4838. qh_printlists(qh);
  4839. }
  4840. qh_checkfacet(qh, facet2, True /* newmerge */, &waserror);
  4841. }
  4842. if (waserror)
  4843. qh_errexit(qh, qh_ERRqhull, NULL, NULL); /* erroneous facet logged by qh_checkfacet */
  4844. } /* tracemerge */
  4845. /*-<a href="qh-merge_r.htm#TOC"
  4846. >-------------------------------</a><a name="tracemerging">-</a>
  4847. qh_tracemerging(qh)
  4848. print trace message during POSTmerging
  4849. returns:
  4850. updates qh.mergereport
  4851. notes:
  4852. called from qh_mergecycle() and qh_mergefacet()
  4853. see:
  4854. qh_buildtracing()
  4855. */
  4856. void qh_tracemerging(qhT *qh) {
  4857. realT cpu;
  4858. int total;
  4859. time_t timedata;
  4860. struct tm *tp;
  4861. qh->mergereport= zzval_(Ztotmerge);
  4862. time(&timedata);
  4863. tp= localtime(&timedata);
  4864. cpu= qh_CPUclock;
  4865. cpu /= qh_SECticks;
  4866. total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
  4867. qh_fprintf(qh, qh->ferr, 8087, "\n\
  4868. At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets with max_outside %2.2g, min_vertex %2.2g.\n\
  4869. The hull contains %d facets and %d vertices.\n",
  4870. tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, total, qh->max_outside, qh->min_vertex,
  4871. qh->num_facets - qh->num_visible,
  4872. qh->num_vertices-qh_setsize(qh, qh->del_vertices));
  4873. } /* tracemerging */
  4874. /*-<a href="qh-merge_r.htm#TOC"
  4875. >-------------------------------</a><a name="updatetested">-</a>
  4876. qh_updatetested(qh, facet1, facet2 )
  4877. clear facet2->tested and facet1->ridge->tested for merge
  4878. returns:
  4879. deletes facet2->center unless it's already large
  4880. if so, clears facet2->ridge->tested
  4881. notes:
  4882. only called by qh_mergefacet
  4883. design:
  4884. clear facet2->tested
  4885. clear ridge->tested for facet1's ridges
  4886. if facet2 has a centrum
  4887. if facet2 is large
  4888. set facet2->keepcentrum
  4889. else if facet2 has 3 vertices due to many merges, or not large and post merging
  4890. clear facet2->keepcentrum
  4891. unless facet2->keepcentrum
  4892. clear facet2->center to recompute centrum later
  4893. clear ridge->tested for facet2's ridges
  4894. */
  4895. void qh_updatetested(qhT *qh, facetT *facet1, facetT *facet2) {
  4896. ridgeT *ridge, **ridgep;
  4897. int size;
  4898. facet2->tested= False;
  4899. FOREACHridge_(facet1->ridges)
  4900. ridge->tested= False;
  4901. if (!facet2->center)
  4902. return;
  4903. size= qh_setsize(qh, facet2->vertices);
  4904. if (!facet2->keepcentrum) {
  4905. if (size > qh->hull_dim + qh_MAXnewcentrum) {
  4906. facet2->keepcentrum= True;
  4907. zinc_(Zwidevertices);
  4908. }
  4909. }else if (size <= qh->hull_dim + qh_MAXnewcentrum) {
  4910. /* center and keepcentrum was set */
  4911. if (size == qh->hull_dim || qh->POSTmerging)
  4912. facet2->keepcentrum= False; /* if many merges need to recompute centrum */
  4913. }
  4914. if (!facet2->keepcentrum) {
  4915. qh_memfree(qh, facet2->center, qh->normal_size);
  4916. facet2->center= NULL;
  4917. FOREACHridge_(facet2->ridges)
  4918. ridge->tested= False;
  4919. }
  4920. } /* updatetested */
  4921. /*-<a href="qh-merge_r.htm#TOC"
  4922. >-------------------------------</a><a name="vertexridges">-</a>
  4923. qh_vertexridges(qh, vertex, allneighbors )
  4924. return temporary set of ridges adjacent to a vertex
  4925. vertex->neighbors defined (qh_vertexneighbors)
  4926. notes:
  4927. uses qh.visit_id
  4928. does not include implicit ridges for simplicial facets
  4929. skips last neighbor, unless allneighbors. For new facets, the last neighbor shares ridges with adjacent neighbors
  4930. if the last neighbor is not simplicial, it will have ridges for its simplicial neighbors
  4931. Use allneighbors when a new cone is attached to an existing convex hull
  4932. similar to qh_neighbor_vertices
  4933. design:
  4934. for each neighbor of vertex
  4935. add ridges that include the vertex to ridges
  4936. */
  4937. setT *qh_vertexridges(qhT *qh, vertexT *vertex, boolT allneighbors) {
  4938. facetT *neighbor, **neighborp;
  4939. setT *ridges= qh_settemp(qh, qh->TEMPsize);
  4940. int size;
  4941. qh->visit_id += 2; /* visit_id for vertex neighbors, visit_id-1 for facets of visited ridges */
  4942. FOREACHneighbor_(vertex)
  4943. neighbor->visitid= qh->visit_id;
  4944. FOREACHneighbor_(vertex) {
  4945. if (*neighborp || allneighbors) /* no new ridges in last neighbor */
  4946. qh_vertexridges_facet(qh, vertex, neighbor, &ridges);
  4947. }
  4948. if (qh->PRINTstatistics || qh->IStracing) {
  4949. size= qh_setsize(qh, ridges);
  4950. zinc_(Zvertexridge);
  4951. zadd_(Zvertexridgetot, size);
  4952. zmax_(Zvertexridgemax, size);
  4953. trace3((qh, qh->ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n",
  4954. size, vertex->id));
  4955. }
  4956. return ridges;
  4957. } /* vertexridges */
  4958. /*-<a href="qh-merge_r.htm#TOC"
  4959. >-------------------------------</a><a name="vertexridges_facet">-</a>
  4960. qh_vertexridges_facet(qh, vertex, facet, ridges )
  4961. add adjacent ridges for vertex in facet
  4962. neighbor->visitid==qh.visit_id if it hasn't been visited
  4963. returns:
  4964. ridges updated
  4965. sets facet->visitid to qh.visit_id-1
  4966. design:
  4967. for each ridge of facet
  4968. if ridge of visited neighbor (i.e., unprocessed)
  4969. if vertex in ridge
  4970. append ridge
  4971. mark facet processed
  4972. */
  4973. void qh_vertexridges_facet(qhT *qh, vertexT *vertex, facetT *facet, setT **ridges) {
  4974. ridgeT *ridge, **ridgep;
  4975. facetT *neighbor;
  4976. int last_i= qh->hull_dim-2;
  4977. vertexT *second, *last;
  4978. FOREACHridge_(facet->ridges) {
  4979. neighbor= otherfacet_(ridge, facet);
  4980. if (neighbor->visitid == qh->visit_id) {
  4981. if (SETfirst_(ridge->vertices) == vertex) {
  4982. qh_setappend(qh, ridges, ridge);
  4983. }else if (last_i > 2) {
  4984. second= SETsecondt_(ridge->vertices, vertexT);
  4985. last= SETelemt_(ridge->vertices, last_i, vertexT);
  4986. if (second->id >= vertex->id && last->id <= vertex->id) { /* vertices inverse sorted by id */
  4987. if (second == vertex || last == vertex)
  4988. qh_setappend(qh, ridges, ridge);
  4989. else if (qh_setin(ridge->vertices, vertex))
  4990. qh_setappend(qh, ridges, ridge);
  4991. }
  4992. }else if (SETelem_(ridge->vertices, last_i) == vertex
  4993. || (last_i > 1 && SETsecond_(ridge->vertices) == vertex)) {
  4994. qh_setappend(qh, ridges, ridge);
  4995. }
  4996. }
  4997. }
  4998. facet->visitid= qh->visit_id-1;
  4999. } /* vertexridges_facet */
  5000. /*-<a href="qh-merge_r.htm#TOC"
  5001. >-------------------------------</a><a name="willdelete">-</a>
  5002. qh_willdelete(qh, facet, replace )
  5003. moves facet to visible list for qh_deletevisible
  5004. sets facet->f.replace to replace (may be NULL)
  5005. clears f.ridges and f.neighbors -- no longer valid
  5006. returns:
  5007. bumps qh.num_visible
  5008. */
  5009. void qh_willdelete(qhT *qh, facetT *facet, facetT *replace) {
  5010. trace4((qh, qh->ferr, 4081, "qh_willdelete: move f%d to visible list, set its replacement as f%d, and clear f.neighbors and f.ridges\n", facet->id, getid_(replace)));
  5011. if (!qh->visible_list && qh->newfacet_list) {
  5012. qh_fprintf(qh, qh->ferr, 6378, "qhull internal error (qh_willdelete): expecting qh.visible_list at before qh.newfacet_list f%d. Got NULL\n",
  5013. qh->newfacet_list->id);
  5014. qh_errexit2(qh, qh_ERRqhull, NULL, NULL);
  5015. }
  5016. qh_removefacet(qh, facet);
  5017. qh_prependfacet(qh, facet, &qh->visible_list);
  5018. qh->num_visible++;
  5019. facet->visible= True;
  5020. facet->f.replace= replace;
  5021. if (facet->ridges)
  5022. SETfirst_(facet->ridges)= NULL;
  5023. if (facet->neighbors)
  5024. SETfirst_(facet->neighbors)= NULL;
  5025. } /* willdelete */
  5026. #else /* qh_NOmerge */
  5027. void qh_all_vertexmerges(qhT *qh, int apexpointid, facetT *facet, facetT **retryfacet) {
  5028. QHULL_UNUSED(qh)
  5029. QHULL_UNUSED(apexpointid)
  5030. QHULL_UNUSED(facet)
  5031. QHULL_UNUSED(retryfacet)
  5032. }
  5033. void qh_premerge(qhT *qh, int apexpointid, realT maxcentrum, realT maxangle) {
  5034. QHULL_UNUSED(qh)
  5035. QHULL_UNUSED(apexpointid)
  5036. QHULL_UNUSED(maxcentrum)
  5037. QHULL_UNUSED(maxangle)
  5038. }
  5039. void qh_postmerge(qhT *qh, const char *reason, realT maxcentrum, realT maxangle,
  5040. boolT vneighbors) {
  5041. QHULL_UNUSED(qh)
  5042. QHULL_UNUSED(reason)
  5043. QHULL_UNUSED(maxcentrum)
  5044. QHULL_UNUSED(maxangle)
  5045. QHULL_UNUSED(vneighbors)
  5046. }
  5047. void qh_checkdelfacet(qhT *qh, facetT *facet, setT *mergeset) {
  5048. QHULL_UNUSED(qh)
  5049. QHULL_UNUSED(facet)
  5050. QHULL_UNUSED(mergeset)
  5051. }
  5052. void qh_checkdelridge(qhT *qh /* qh.visible_facets, vertex_mergeset */) {
  5053. QHULL_UNUSED(qh)
  5054. }
  5055. boolT qh_checkzero(qhT *qh, boolT testall) {
  5056. QHULL_UNUSED(qh)
  5057. QHULL_UNUSED(testall)
  5058. return True;
  5059. }
  5060. void qh_freemergesets(qhT *qh) {
  5061. QHULL_UNUSED(qh)
  5062. }
  5063. void qh_initmergesets(qhT *qh) {
  5064. QHULL_UNUSED(qh)
  5065. }
  5066. void qh_merge_pinchedvertices(qhT *qh, int apexpointid /* qh.newfacet_list */) {
  5067. QHULL_UNUSED(qh)
  5068. QHULL_UNUSED(apexpointid)
  5069. }
  5070. #endif /* qh_NOmerge */