VHACD.h 253 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364
  1. /* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
  2. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  4. 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  5. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  6. 3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
  7. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  8. */
  9. #pragma once
  10. #ifndef VHACD_H
  11. # define VHACD_H
  12. // Please view this slide deck which describes usage and how the algorithm works.
  13. // https://docs.google.com/presentation/d/1OZ4mtZYrGEC8qffqb8F7Le2xzufiqvaPpRbLHKKgTIM/edit?usp=sharing
  14. // VHACD is now a header only library.
  15. // In just *one* of your CPP files *before* you include 'VHACD.h' you must declare
  16. // #define ENABLE_VHACD_IMPLEMENTATION 1
  17. // This will compile the implementation code into your project. If you don't
  18. // have this define, you will get link errors since the implementation code will
  19. // not be present. If you define it more than once in your code base, you will get
  20. // link errors due to a duplicate implementation. This is the same pattern used by
  21. // ImGui and StbLib and other popular open source libraries.
  22. # define VHACD_VERSION_MAJOR 4
  23. # define VHACD_VERSION_MINOR 1
  24. // Changes for version 4.1
  25. //
  26. // Various minor tweaks mostly to the test application and some default values.
  27. // Changes for version 4.0
  28. //
  29. // * The code has been significantly refactored to be cleaner and easier to maintain
  30. // * All OpenCL related code removed
  31. // * All Bullet code removed
  32. // * All SIMD code removed
  33. // * Old plane splitting code removed
  34. //
  35. // * The code is now delivered as a single header file 'VHACD.h' which has both the API
  36. // * declaration as well as the implementation. Simply add '#define ENABLE_VHACD_IMPLEMENTATION 1'
  37. // * to any CPP in your application prior to including 'VHACD.h'. Only do this in one CPP though.
  38. // * If you do not have this define once, you will get link errors since the implementation code
  39. // * will not be compiled in. If you have this define more than once, you are likely to get
  40. // * duplicate symbol link errors.
  41. //
  42. // * Since the library is now delivered as a single header file, we do not provide binaries
  43. // * or build scripts as these are not needed.
  44. //
  45. // * The old DebugView and test code has all been removed and replaced with a much smaller and
  46. // * simpler test console application with some test meshes to work with.
  47. //
  48. // * The convex hull generation code has changed. The previous version came from Bullet.
  49. // * However, the new version is courtesy of Julio Jerez, the author of the Newton
  50. // * physics engine. His new version is faster and more numerically stable.
  51. //
  52. // * The code can now detect if the input mesh is, itself, already a convex object and
  53. // * can early out.
  54. //
  55. // * Significant performance improvements have been made to the code and it is now much
  56. // * faster, stable, and is easier to tune than previous versions.
  57. //
  58. // * A bug was fixed with the shrink wrapping code (project hull vertices) that could
  59. // * sometime produce artifacts in the results. The new version uses a 'closest point'
  60. // * algorithm that is more reliable.
  61. //
  62. // * You can now select which 'fill mode' to use. For perfectly closed meshes, the default
  63. // * behavior using a flood fill generally works fine. However, some meshes have small
  64. // * holes in them and therefore the flood fill will fail, treating the mesh as being
  65. // * hollow. In these cases, you can use the 'raycast' fill option to determine which
  66. // * parts of the voxelized mesh are 'inside' versus being 'outside'. Finally, there
  67. // * are some rare instances where a user might actually want the mesh to be treated as
  68. // * hollow, in which case you can pass in 'surface' only.
  69. // *
  70. // * A new optional virtual interface called 'IUserProfiler' was provided.
  71. // * This allows the user to provide an optional profiling callback interface to assist in
  72. // * diagnosing performance issues. This change was made by Danny Couture at Epic for the UE4 integration.
  73. // * Some profiling macros were also declared in support of this feature.
  74. // *
  75. // * Another new optional virtual interface called 'IUserTaskRunner' was provided.
  76. // * This interface is used to run logical 'tasks' in a background thread. If none is provided
  77. // * then a default implementation using std::thread will be executed.
  78. // * This change was made by Danny Couture at Epic to speed up the voxelization step.
  79. // *
  80. // The history of V-HACD:
  81. //
  82. // The initial version was written by John W. Ratcliff and was called 'ACD'
  83. // This version did not perform CSG operations on the source mesh, so if you
  84. // recursed too deeply it would produce hollow results.
  85. //
  86. // The next version was written by Khaled Mamou and was called 'HACD'
  87. // In this version Khaled tried to perform a CSG operation on the source
  88. // mesh to produce more robust results. However, Khaled learned that the
  89. // CSG library he was using had licensing issues so he started work on the
  90. // next version.
  91. //
  92. // The next version was called 'V-HACD' because Khaled made the observation
  93. // that plane splitting would be far easier to implement working in voxel space.
  94. //
  95. // V-HACD has been integrated into UE4, Blender, and a number of other projects.
  96. // This new release, version4, is a significant refactor of the code to fix
  97. // some bugs, improve performance, and to make the codebase easier to maintain
  98. // going forward.
  99. #include <stdint.h>
  100. #include <functional>
  101. #include <vector>
  102. #include <array>
  103. #include <cmath>
  104. #include <algorithm>
  105. namespace VHACD {
  106. struct Vertex
  107. {
  108. double mX;
  109. double mY;
  110. double mZ;
  111. Vertex() = default;
  112. Vertex(double x, double y, double z) : mX(x), mY(y), mZ(z) {}
  113. const double& operator[](size_t idx) const
  114. {
  115. switch(idx)
  116. {
  117. case 0: return mX;
  118. case 1: return mY;
  119. case 2: return mZ;
  120. };
  121. return mX;
  122. }
  123. };
  124. struct Triangle
  125. {
  126. uint32_t mI0;
  127. uint32_t mI1;
  128. uint32_t mI2;
  129. Triangle() = default;
  130. Triangle(uint32_t i0, uint32_t i1, uint32_t i2) : mI0(i0), mI1(i1), mI2(i2) {}
  131. };
  132. template <typename T>
  133. class Vector3
  134. {
  135. public:
  136. /*
  137. * Getters
  138. */
  139. T& operator[](size_t i);
  140. const T& operator[](size_t i) const;
  141. T& GetX();
  142. T& GetY();
  143. T& GetZ();
  144. const T& GetX() const;
  145. const T& GetY() const;
  146. const T& GetZ() const;
  147. /*
  148. * Normalize and norming
  149. */
  150. T Normalize();
  151. Vector3 Normalized();
  152. T GetNorm() const;
  153. T GetNormSquared() const;
  154. int LongestAxis() const;
  155. /*
  156. * Vector-vector operations
  157. */
  158. Vector3& operator=(const Vector3& rhs);
  159. Vector3& operator+=(const Vector3& rhs);
  160. Vector3& operator-=(const Vector3& rhs);
  161. Vector3 CWiseMul(const Vector3& rhs) const;
  162. Vector3 Cross(const Vector3& rhs) const;
  163. T Dot(const Vector3& rhs) const;
  164. Vector3 operator+(const Vector3& rhs) const;
  165. Vector3 operator-(const Vector3& rhs) const;
  166. /*
  167. * Vector-scalar operations
  168. */
  169. Vector3& operator-=(T a);
  170. Vector3& operator+=(T a);
  171. Vector3& operator/=(T a);
  172. Vector3& operator*=(T a);
  173. Vector3 operator*(T rhs) const;
  174. Vector3 operator/(T rhs) const;
  175. /*
  176. * Unary operations
  177. */
  178. Vector3 operator-() const;
  179. /*
  180. * Comparison operators
  181. */
  182. bool operator<(const Vector3& rhs) const;
  183. bool operator>(const Vector3& rhs) const;
  184. /*
  185. * Returns true if all elements of *this are greater than or equal to all elements of rhs, coefficient wise
  186. * LE is less than or equal
  187. */
  188. bool CWiseAllGE(const Vector3<T>& rhs) const;
  189. bool CWiseAllLE(const Vector3<T>& rhs) const;
  190. Vector3 CWiseMin(const Vector3& rhs) const;
  191. Vector3 CWiseMax(const Vector3& rhs) const;
  192. T MinCoeff() const;
  193. T MaxCoeff() const;
  194. T MinCoeff(uint32_t& idx) const;
  195. T MaxCoeff(uint32_t& idx) const;
  196. /*
  197. * Constructors
  198. */
  199. Vector3() = default;
  200. Vector3(T a);
  201. Vector3(T x, T y, T z);
  202. Vector3(const Vector3& rhs);
  203. ~Vector3() = default;
  204. template <typename U>
  205. Vector3(const Vector3<U>& rhs);
  206. Vector3(const VHACD::Vertex&);
  207. Vector3(const VHACD::Triangle&);
  208. operator VHACD::Vertex() const;
  209. private:
  210. std::array<T, 3> m_data{ T(0.0) };
  211. };
  212. typedef VHACD::Vector3<double> Vect3;
  213. struct BoundsAABB
  214. {
  215. BoundsAABB() = default;
  216. BoundsAABB(const std::vector<VHACD::Vertex>& points);
  217. BoundsAABB(const Vect3& min,
  218. const Vect3& max);
  219. BoundsAABB Union(const BoundsAABB& b);
  220. bool Intersects(const BoundsAABB& b) const;
  221. double SurfaceArea() const;
  222. double Volume() const;
  223. BoundsAABB Inflate(double ratio) const;
  224. VHACD::Vect3 ClosestPoint(const VHACD::Vect3& p) const;
  225. VHACD::Vect3& GetMin();
  226. VHACD::Vect3& GetMax();
  227. const VHACD::Vect3& GetMin() const;
  228. const VHACD::Vect3& GetMax() const;
  229. VHACD::Vect3 GetSize() const;
  230. VHACD::Vect3 GetCenter() const;
  231. VHACD::Vect3 m_min{ double(0.0) };
  232. VHACD::Vect3 m_max{ double(0.0) };
  233. };
  234. /**
  235. * This enumeration determines how the voxels as filled to create a solid
  236. * object. The default should be 'FLOOD_FILL' which generally works fine
  237. * for closed meshes. However, if the mesh is not watertight, then using
  238. * RAYCAST_FILL may be preferable as it will determine if a voxel is part
  239. * of the interior of the source mesh by raycasting around it.
  240. *
  241. * Finally, there are some cases where you might actually want a convex
  242. * decomposition to treat the source mesh as being hollow. If that is the
  243. * case you can pass in 'SURFACE_ONLY' and then the convex decomposition
  244. * will converge only onto the 'skin' of the surface mesh.
  245. */
  246. enum class FillMode
  247. {
  248. FLOOD_FILL, // This is the default behavior, after the voxelization step it uses a flood fill to determine 'inside'
  249. // from 'outside'. However, meshes with holes can fail and create hollow results.
  250. SURFACE_ONLY, // Only consider the 'surface', will create 'skins' with hollow centers.
  251. RAYCAST_FILL, // Uses raycasting to determine inside from outside.
  252. };
  253. class IVHACD
  254. {
  255. public:
  256. /**
  257. * This optional pure virtual interface is used to notify the caller of the progress
  258. * of convex decomposition as well as a signal when it is complete when running in
  259. * a background thread
  260. */
  261. class IUserCallback
  262. {
  263. public:
  264. virtual ~IUserCallback(){};
  265. /**
  266. * Notifies the application of the current state of the convex decomposition operation
  267. *
  268. * @param overallProgress : Total progress from 0-100%
  269. * @param stageProgress : Progress of the current stage 0-100%
  270. * @param stage : A text description of the current stage we are in
  271. * @param operation : A text description of what operation is currently being performed.
  272. */
  273. virtual void Update(const double overallProgress,
  274. const double stageProgress,
  275. const char* const stage,
  276. const char* operation) = 0;
  277. // This is an optional user callback which is only called when running V-HACD asynchronously.
  278. // This is a callback performed to notify the user that the
  279. // convex decomposition background process is completed. This call back will occur from
  280. // a different thread so the user should take that into account.
  281. virtual void NotifyVHACDComplete()
  282. {
  283. }
  284. };
  285. /**
  286. * Optional user provided pure virtual interface to be notified of warning or informational messages
  287. */
  288. class IUserLogger
  289. {
  290. public:
  291. virtual ~IUserLogger(){};
  292. virtual void Log(const char* const msg) = 0;
  293. };
  294. /**
  295. * An optional user provided pure virtual interface to perform a background task.
  296. * This was added by Danny Couture at Epic as they wanted to use their own
  297. * threading system instead of the standard library version which is the default.
  298. */
  299. class IUserTaskRunner
  300. {
  301. public:
  302. virtual ~IUserTaskRunner(){};
  303. virtual void* StartTask(std::function<void()> func) = 0;
  304. virtual void JoinTask(void* Task) = 0;
  305. };
  306. /**
  307. * A simple class that represents a convex hull as a triangle mesh with
  308. * double precision vertices. Polygons are not currently provided.
  309. */
  310. class ConvexHull
  311. {
  312. public:
  313. std::vector<VHACD::Vertex> m_points;
  314. std::vector<VHACD::Triangle> m_triangles;
  315. double m_volume{ 0 }; // The volume of the convex hull
  316. VHACD::Vect3 m_center{ 0, 0, 0 }; // The centroid of the convex hull
  317. uint32_t m_meshId{ 0 }; // A unique id for this convex hull
  318. VHACD::Vect3 mBmin; // Bounding box minimum of the AABB
  319. VHACD::Vect3 mBmax; // Bounding box maximum of the AABB
  320. };
  321. /**
  322. * This class provides the parameters controlling the convex decomposition operation
  323. */
  324. class Parameters
  325. {
  326. public:
  327. IUserCallback* m_callback{nullptr}; // Optional user provided callback interface for progress
  328. IUserLogger* m_logger{nullptr}; // Optional user provided callback interface for log messages
  329. IUserTaskRunner* m_taskRunner{nullptr}; // Optional user provided interface for creating tasks
  330. uint32_t m_maxConvexHulls{ 64 }; // The maximum number of convex hulls to produce
  331. uint32_t m_resolution{ 400000 }; // The voxel resolution to use
  332. double m_minimumVolumePercentErrorAllowed{ 1 }; // if the voxels are within 1% of the volume of the hull, we consider this a close enough approximation
  333. uint32_t m_maxRecursionDepth{ 10 }; // The maximum recursion depth
  334. bool m_shrinkWrap{true}; // Whether or not to shrinkwrap the voxel positions to the source mesh on output
  335. FillMode m_fillMode{ FillMode::FLOOD_FILL }; // How to fill the interior of the voxelized mesh
  336. uint32_t m_maxNumVerticesPerCH{ 64 }; // The maximum number of vertices allowed in any output convex hull
  337. bool m_asyncACD{ true }; // Whether or not to run asynchronously, taking advantage of additional cores
  338. uint32_t m_minEdgeLength{ 2 }; // Once a voxel patch has an edge length of less than 4 on all 3 sides, we don't keep recursing
  339. bool m_findBestPlane{ false }; // Whether or not to attempt to split planes along the best location. Experimental feature. False by default.
  340. };
  341. /**
  342. * Will cause the convex decomposition operation to be canceled early. No results will be produced but the background operation will end as soon as it can.
  343. */
  344. virtual void Cancel() = 0;
  345. /**
  346. * Compute a convex decomposition of a triangle mesh using float vertices and the provided user parameters.
  347. *
  348. * @param points : The vertices of the source mesh as floats in the form of X1,Y1,Z1, X2,Y2,Z2,.. etc.
  349. * @param countPoints : The number of vertices in the source mesh.
  350. * @param triangles : The indices of triangles in the source mesh in the form of I1,I2,I3, ....
  351. * @param countTriangles : The number of triangles in the source mesh
  352. * @param params : The convex decomposition parameters to apply
  353. * @return : Returns true if the convex decomposition operation can be started
  354. */
  355. virtual bool Compute(const float* const points,
  356. const uint32_t countPoints,
  357. const uint32_t* const triangles,
  358. const uint32_t countTriangles,
  359. const Parameters& params) = 0;
  360. /**
  361. * Compute a convex decomposition of a triangle mesh using double vertices and the provided user parameters.
  362. *
  363. * @param points : The vertices of the source mesh as floats in the form of X1,Y1,Z1, X2,Y2,Z2,.. etc.
  364. * @param countPoints : The number of vertices in the source mesh.
  365. * @param triangles : The indices of triangles in the source mesh in the form of I1,I2,I3, ....
  366. * @param countTriangles : The number of triangles in the source mesh
  367. * @param params : The convex decomposition parameters to apply
  368. * @return : Returns true if the convex decomposition operation can be started
  369. */
  370. virtual bool Compute(const double* const points,
  371. const uint32_t countPoints,
  372. const uint32_t* const triangles,
  373. const uint32_t countTriangles,
  374. const Parameters& params) = 0;
  375. /**
  376. * Returns the number of convex hulls that were produced.
  377. *
  378. * @return : Returns the number of convex hulls produced, or zero if it failed or was canceled
  379. */
  380. virtual uint32_t GetNConvexHulls() const = 0;
  381. /**
  382. * Retrieves one of the convex hulls in the solution set
  383. *
  384. * @param index : Which convex hull to retrieve
  385. * @param ch : The convex hull descriptor to return
  386. * @return : Returns true if the convex hull exists and could be retrieved
  387. */
  388. virtual bool GetConvexHull(const uint32_t index,
  389. ConvexHull& ch) const = 0;
  390. /**
  391. * Releases any memory allocated by the V-HACD class
  392. */
  393. virtual void Clean() = 0; // release internally allocated memory
  394. /**
  395. * Releases this instance of the V-HACD class
  396. */
  397. virtual void Release() = 0; // release IVHACD
  398. // Will compute the center of mass of the convex hull decomposition results and return it
  399. // in 'centerOfMass'. Returns false if the center of mass could not be computed.
  400. virtual bool ComputeCenterOfMass(double centerOfMass[3]) const = 0;
  401. // In synchronous mode (non-multi-threaded) the state is always 'ready'
  402. // In asynchronous mode, this returns true if the background thread is not still actively computing
  403. // a new solution. In an asynchronous config the 'IsReady' call will report any update or log
  404. // messages in the caller's current thread.
  405. virtual bool IsReady() const
  406. {
  407. return true;
  408. }
  409. /**
  410. * At the request of LegionFu : [email protected]
  411. * This method will return which convex hull is closest to the source position.
  412. * You can use this method to figure out, for example, which vertices in the original
  413. * source mesh are best associated with which convex hull.
  414. *
  415. * @param pos : The input 3d position to test against
  416. *
  417. * @return : Returns which convex hull this position is closest to.
  418. */
  419. virtual uint32_t findNearestConvexHull(const double pos[3],
  420. double& distanceToHull) = 0;
  421. protected:
  422. virtual ~IVHACD()
  423. {
  424. }
  425. };
  426. /*
  427. * Out of line definitions
  428. */
  429. template <typename T>
  430. T clamp(const T& v, const T& lo, const T& hi)
  431. {
  432. if (v < lo)
  433. {
  434. return lo;
  435. }
  436. if (v > hi)
  437. {
  438. return hi;
  439. }
  440. return v ;
  441. }
  442. /*
  443. * Getters
  444. */
  445. template <typename T>
  446. inline T& Vector3<T>::operator[](size_t i)
  447. {
  448. return m_data[i];
  449. }
  450. template <typename T>
  451. inline const T& Vector3<T>::operator[](size_t i) const
  452. {
  453. return m_data[i];
  454. }
  455. template <typename T>
  456. inline T& Vector3<T>::GetX()
  457. {
  458. return m_data[0];
  459. }
  460. template <typename T>
  461. inline T& Vector3<T>::GetY()
  462. {
  463. return m_data[1];
  464. }
  465. template <typename T>
  466. inline T& Vector3<T>::GetZ()
  467. {
  468. return m_data[2];
  469. }
  470. template <typename T>
  471. inline const T& Vector3<T>::GetX() const
  472. {
  473. return m_data[0];
  474. }
  475. template <typename T>
  476. inline const T& Vector3<T>::GetY() const
  477. {
  478. return m_data[1];
  479. }
  480. template <typename T>
  481. inline const T& Vector3<T>::GetZ() const
  482. {
  483. return m_data[2];
  484. }
  485. /*
  486. * Normalize and norming
  487. */
  488. template <typename T>
  489. inline T Vector3<T>::Normalize()
  490. {
  491. T n = GetNorm();
  492. if (n != T(0.0)) (*this) /= n;
  493. return n;
  494. }
  495. template <typename T>
  496. inline Vector3<T> Vector3<T>::Normalized()
  497. {
  498. Vector3<T> ret = *this;
  499. T n = GetNorm();
  500. if (n != T(0.0)) ret /= n;
  501. return ret;
  502. }
  503. template <typename T>
  504. inline T Vector3<T>::GetNorm() const
  505. {
  506. return std::sqrt(GetNormSquared());
  507. }
  508. template <typename T>
  509. inline T Vector3<T>::GetNormSquared() const
  510. {
  511. return this->Dot(*this);
  512. }
  513. template <typename T>
  514. inline int Vector3<T>::LongestAxis() const
  515. {
  516. auto it = std::max_element(m_data.begin(), m_data.end());
  517. return int(std::distance(m_data.begin(), it));
  518. }
  519. /*
  520. * Vector-vector operations
  521. */
  522. template <typename T>
  523. inline Vector3<T>& Vector3<T>::operator=(const Vector3<T>& rhs)
  524. {
  525. GetX() = rhs.GetX();
  526. GetY() = rhs.GetY();
  527. GetZ() = rhs.GetZ();
  528. return *this;
  529. }
  530. template <typename T>
  531. inline Vector3<T>& Vector3<T>::operator+=(const Vector3<T>& rhs)
  532. {
  533. GetX() += rhs.GetX();
  534. GetY() += rhs.GetY();
  535. GetZ() += rhs.GetZ();
  536. return *this;
  537. }
  538. template <typename T>
  539. inline Vector3<T>& Vector3<T>::operator-=(const Vector3<T>& rhs)
  540. {
  541. GetX() -= rhs.GetX();
  542. GetY() -= rhs.GetY();
  543. GetZ() -= rhs.GetZ();
  544. return *this;
  545. }
  546. template <typename T>
  547. inline Vector3<T> Vector3<T>::CWiseMul(const Vector3<T>& rhs) const
  548. {
  549. return Vector3<T>(GetX() * rhs.GetX(),
  550. GetY() * rhs.GetY(),
  551. GetZ() * rhs.GetZ());
  552. }
  553. template <typename T>
  554. inline Vector3<T> Vector3<T>::Cross(const Vector3<T>& rhs) const
  555. {
  556. return Vector3<T>(GetY() * rhs.GetZ() - GetZ() * rhs.GetY(),
  557. GetZ() * rhs.GetX() - GetX() * rhs.GetZ(),
  558. GetX() * rhs.GetY() - GetY() * rhs.GetX());
  559. }
  560. template <typename T>
  561. inline T Vector3<T>::Dot(const Vector3<T>& rhs) const
  562. {
  563. return GetX() * rhs.GetX()
  564. + GetY() * rhs.GetY()
  565. + GetZ() * rhs.GetZ();
  566. }
  567. template <typename T>
  568. inline Vector3<T> Vector3<T>::operator+(const Vector3<T>& rhs) const
  569. {
  570. return Vector3<T>(GetX() + rhs.GetX(),
  571. GetY() + rhs.GetY(),
  572. GetZ() + rhs.GetZ());
  573. }
  574. template <typename T>
  575. inline Vector3<T> Vector3<T>::operator-(const Vector3<T>& rhs) const
  576. {
  577. return Vector3<T>(GetX() - rhs.GetX(),
  578. GetY() - rhs.GetY(),
  579. GetZ() - rhs.GetZ());
  580. }
  581. template <typename T>
  582. inline Vector3<T> operator*(T lhs, const Vector3<T>& rhs)
  583. {
  584. return Vector3<T>(lhs * rhs.GetX(),
  585. lhs * rhs.GetY(),
  586. lhs * rhs.GetZ());
  587. }
  588. /*
  589. * Vector-scalar operations
  590. */
  591. template <typename T>
  592. inline Vector3<T>& Vector3<T>::operator-=(T a)
  593. {
  594. GetX() -= a;
  595. GetY() -= a;
  596. GetZ() -= a;
  597. return *this;
  598. }
  599. template <typename T>
  600. inline Vector3<T>& Vector3<T>::operator+=(T a)
  601. {
  602. GetX() += a;
  603. GetY() += a;
  604. GetZ() += a;
  605. return *this;
  606. }
  607. template <typename T>
  608. inline Vector3<T>& Vector3<T>::operator/=(T a)
  609. {
  610. GetX() /= a;
  611. GetY() /= a;
  612. GetZ() /= a;
  613. return *this;
  614. }
  615. template <typename T>
  616. inline Vector3<T>& Vector3<T>::operator*=(T a)
  617. {
  618. GetX() *= a;
  619. GetY() *= a;
  620. GetZ() *= a;
  621. return *this;
  622. }
  623. template <typename T>
  624. inline Vector3<T> Vector3<T>::operator*(T rhs) const
  625. {
  626. return Vector3<T>(GetX() * rhs,
  627. GetY() * rhs,
  628. GetZ() * rhs);
  629. }
  630. template <typename T>
  631. inline Vector3<T> Vector3<T>::operator/(T rhs) const
  632. {
  633. return Vector3<T>(GetX() / rhs,
  634. GetY() / rhs,
  635. GetZ() / rhs);
  636. }
  637. /*
  638. * Unary operations
  639. */
  640. template <typename T>
  641. inline Vector3<T> Vector3<T>::operator-() const
  642. {
  643. return Vector3<T>(-GetX(),
  644. -GetY(),
  645. -GetZ());
  646. }
  647. /*
  648. * Comparison operators
  649. */
  650. template <typename T>
  651. inline bool Vector3<T>::operator<(const Vector3<T>& rhs) const
  652. {
  653. if (GetX() == rhs.GetX())
  654. {
  655. if (GetY() == rhs.GetY())
  656. {
  657. return (GetZ() < rhs.GetZ());
  658. }
  659. return (GetY() < rhs.GetY());
  660. }
  661. return (GetX() < rhs.GetX());
  662. }
  663. template <typename T>
  664. inline bool Vector3<T>::operator>(const Vector3<T>& rhs) const
  665. {
  666. if (GetX() == rhs.GetX())
  667. {
  668. if (GetY() == rhs.GetY())
  669. {
  670. return (GetZ() > rhs.GetZ());
  671. }
  672. return (GetY() > rhs.GetY());
  673. }
  674. return (GetX() > rhs.GetZ());
  675. }
  676. template <typename T>
  677. inline bool Vector3<T>::CWiseAllGE(const Vector3<T>& rhs) const
  678. {
  679. return GetX() >= rhs.GetX()
  680. && GetY() >= rhs.GetY()
  681. && GetZ() >= rhs.GetZ();
  682. }
  683. template <typename T>
  684. inline bool Vector3<T>::CWiseAllLE(const Vector3<T>& rhs) const
  685. {
  686. return GetX() <= rhs.GetX()
  687. && GetY() <= rhs.GetY()
  688. && GetZ() <= rhs.GetZ();
  689. }
  690. template <typename T>
  691. inline Vector3<T> Vector3<T>::CWiseMin(const Vector3<T>& rhs) const
  692. {
  693. return Vector3<T>(std::min(GetX(), rhs.GetX()),
  694. std::min(GetY(), rhs.GetY()),
  695. std::min(GetZ(), rhs.GetZ()));
  696. }
  697. template <typename T>
  698. inline Vector3<T> Vector3<T>::CWiseMax(const Vector3<T>& rhs) const
  699. {
  700. return Vector3<T>(std::max(GetX(), rhs.GetX()),
  701. std::max(GetY(), rhs.GetY()),
  702. std::max(GetZ(), rhs.GetZ()));
  703. }
  704. template <typename T>
  705. inline T Vector3<T>::MinCoeff() const
  706. {
  707. return *std::min_element(m_data.begin(), m_data.end());
  708. }
  709. template <typename T>
  710. inline T Vector3<T>::MaxCoeff() const
  711. {
  712. return *std::max_element(m_data.begin(), m_data.end());
  713. }
  714. template <typename T>
  715. inline T Vector3<T>::MinCoeff(uint32_t& idx) const
  716. {
  717. auto it = std::min_element(m_data.begin(), m_data.end());
  718. idx = uint32_t(std::distance(m_data.begin(), it));
  719. return *it;
  720. }
  721. template <typename T>
  722. inline T Vector3<T>::MaxCoeff(uint32_t& idx) const
  723. {
  724. auto it = std::max_element(m_data.begin(), m_data.end());
  725. idx = uint32_t(std::distance(m_data.begin(), it));
  726. return *it;
  727. }
  728. /*
  729. * Constructors
  730. */
  731. template <typename T>
  732. inline Vector3<T>::Vector3(T a)
  733. : m_data{a, a, a}
  734. {
  735. }
  736. template <typename T>
  737. inline Vector3<T>::Vector3(T x, T y, T z)
  738. : m_data{x, y, z}
  739. {
  740. }
  741. template <typename T>
  742. inline Vector3<T>::Vector3(const Vector3& rhs)
  743. : m_data{rhs.m_data}
  744. {
  745. }
  746. template <typename T>
  747. template <typename U>
  748. inline Vector3<T>::Vector3(const Vector3<U>& rhs)
  749. : m_data{T(rhs.GetX()), T(rhs.GetY()), T(rhs.GetZ())}
  750. {
  751. }
  752. template <typename T>
  753. inline Vector3<T>::Vector3(const VHACD::Vertex& rhs)
  754. : Vector3<T>(rhs.mX, rhs.mY, rhs.mZ)
  755. {
  756. static_assert(std::is_same<T, double>::value, "Vertex to Vector3 constructor only enabled for double");
  757. }
  758. template <typename T>
  759. inline Vector3<T>::Vector3(const VHACD::Triangle& rhs)
  760. : Vector3<T>(rhs.mI0, rhs.mI1, rhs.mI2)
  761. {
  762. static_assert(std::is_same<T, uint32_t>::value, "Triangle to Vector3 constructor only enabled for uint32_t");
  763. }
  764. template <typename T>
  765. inline Vector3<T>::operator VHACD::Vertex() const
  766. {
  767. static_assert(std::is_same<T, double>::value, "Vector3 to Vertex conversion only enable for double");
  768. return ::VHACD::Vertex( GetX(), GetY(), GetZ());
  769. }
  770. IVHACD* CreateVHACD(); // Create a synchronous (blocking) implementation of V-HACD
  771. IVHACD* CreateVHACD_ASYNC(); // Create an asynchronous (non-blocking) implementation of V-HACD
  772. } // namespace VHACD
  773. #if ENABLE_VHACD_IMPLEMENTATION
  774. #include <assert.h>
  775. #include <math.h>
  776. #include <stdlib.h>
  777. #include <string.h>
  778. #include <float.h>
  779. #include <limits.h>
  780. #include <array>
  781. #include <atomic>
  782. #include <chrono>
  783. #include <condition_variable>
  784. #include <deque>
  785. #include <future>
  786. #include <iostream>
  787. #include <list>
  788. #include <memory>
  789. #include <mutex>
  790. #include <queue>
  791. #include <thread>
  792. #include <unordered_map>
  793. #include <unordered_set>
  794. #include <utility>
  795. #include <vector>
  796. #ifdef _MSC_VER
  797. #pragma warning(push)
  798. #pragma warning(disable:4100 4127 4189 4244 4456 4701 4702 4996)
  799. #endif // _MSC_VER
  800. #ifdef __GNUC__
  801. #pragma GCC diagnostic push
  802. // Minimum set of warnings used for cleanup
  803. // #pragma GCC diagnostic warning "-Wall"
  804. // #pragma GCC diagnostic warning "-Wextra"
  805. // #pragma GCC diagnostic warning "-Wpedantic"
  806. // #pragma GCC diagnostic warning "-Wold-style-cast"
  807. // #pragma GCC diagnostic warning "-Wnon-virtual-dtor"
  808. // #pragma GCC diagnostic warning "-Wshadow"
  809. #endif // __GNUC__
  810. // Scoped Timer
  811. namespace VHACD {
  812. class Timer
  813. {
  814. public:
  815. Timer()
  816. : m_startTime(std::chrono::high_resolution_clock::now())
  817. {
  818. }
  819. void Reset()
  820. {
  821. m_startTime = std::chrono::high_resolution_clock::now();
  822. }
  823. double GetElapsedSeconds()
  824. {
  825. auto s = PeekElapsedSeconds();
  826. Reset();
  827. return s;
  828. }
  829. double PeekElapsedSeconds()
  830. {
  831. auto now = std::chrono::high_resolution_clock::now();
  832. std::chrono::duration<double> diff = now - m_startTime;
  833. return diff.count();
  834. }
  835. private:
  836. std::chrono::time_point<std::chrono::high_resolution_clock> m_startTime;
  837. };
  838. class ScopedTime
  839. {
  840. public:
  841. ScopedTime(const char* action,
  842. VHACD::IVHACD::IUserLogger* logger)
  843. : m_action(action)
  844. , m_logger(logger)
  845. {
  846. m_timer.Reset();
  847. }
  848. ~ScopedTime()
  849. {
  850. double dtime = m_timer.GetElapsedSeconds();
  851. if( m_logger )
  852. {
  853. char scratch[512];
  854. snprintf(scratch,
  855. sizeof(scratch),"%s took %0.5f seconds",
  856. m_action,
  857. dtime);
  858. m_logger->Log(scratch);
  859. }
  860. }
  861. const char* m_action{ nullptr };
  862. Timer m_timer;
  863. VHACD::IVHACD::IUserLogger* m_logger{ nullptr };
  864. };
  865. BoundsAABB::BoundsAABB(const std::vector<VHACD::Vertex>& points)
  866. : m_min(points[0])
  867. , m_max(points[0])
  868. {
  869. for (uint32_t i = 1; i < points.size(); ++i)
  870. {
  871. const VHACD::Vertex& p = points[i];
  872. m_min = m_min.CWiseMin(p);
  873. m_max = m_max.CWiseMax(p);
  874. }
  875. }
  876. BoundsAABB::BoundsAABB(const VHACD::Vect3& min,
  877. const VHACD::Vect3& max)
  878. : m_min(min)
  879. , m_max(max)
  880. {
  881. }
  882. BoundsAABB BoundsAABB::Union(const BoundsAABB& b)
  883. {
  884. return BoundsAABB(GetMin().CWiseMin(b.GetMin()),
  885. GetMax().CWiseMax(b.GetMax()));
  886. }
  887. bool VHACD::BoundsAABB::Intersects(const VHACD::BoundsAABB& b) const
  888. {
  889. if ( ( GetMin().GetX() > b.GetMax().GetX())
  890. || (b.GetMin().GetX() > GetMax().GetX()))
  891. return false;
  892. if ( ( GetMin().GetY() > b.GetMax().GetY())
  893. || (b.GetMin().GetY() > GetMax().GetY()))
  894. return false;
  895. if ( ( GetMin().GetZ() > b.GetMax().GetZ())
  896. || (b.GetMin().GetZ() > GetMax().GetZ()))
  897. return false;
  898. return true;
  899. }
  900. double BoundsAABB::SurfaceArea() const
  901. {
  902. VHACD::Vect3 d = GetMax() - GetMin();
  903. return double(2.0) * (d.GetX() * d.GetY() + d.GetX() * d.GetZ() + d.GetY() * d.GetZ());
  904. }
  905. double VHACD::BoundsAABB::Volume() const
  906. {
  907. VHACD::Vect3 d = GetMax() - GetMin();
  908. return d.GetX() * d.GetY() * d.GetZ();
  909. }
  910. BoundsAABB VHACD::BoundsAABB::Inflate(double ratio) const
  911. {
  912. double inflate = (GetMin() - GetMax()).GetNorm() * double(0.5) * ratio;
  913. return BoundsAABB(GetMin() - inflate,
  914. GetMax() + inflate);
  915. }
  916. VHACD::Vect3 VHACD::BoundsAABB::ClosestPoint(const VHACD::Vect3& p) const
  917. {
  918. return p.CWiseMax(GetMin()).CWiseMin(GetMax());
  919. }
  920. VHACD::Vect3& VHACD::BoundsAABB::GetMin()
  921. {
  922. return m_min;
  923. }
  924. VHACD::Vect3& VHACD::BoundsAABB::GetMax()
  925. {
  926. return m_max;
  927. }
  928. inline const VHACD::Vect3& VHACD::BoundsAABB::GetMin() const
  929. {
  930. return m_min;
  931. }
  932. const VHACD::Vect3& VHACD::BoundsAABB::GetMax() const
  933. {
  934. return m_max;
  935. }
  936. VHACD::Vect3 VHACD::BoundsAABB::GetSize() const
  937. {
  938. return GetMax() - GetMin();
  939. }
  940. VHACD::Vect3 VHACD::BoundsAABB::GetCenter() const
  941. {
  942. return (GetMin() + GetMax()) * double(0.5);
  943. }
  944. /*
  945. * Relies on three way comparison, which std::sort doesn't use
  946. */
  947. template <class T, class dCompareKey>
  948. void Sort(T* const array, int elements)
  949. {
  950. const int batchSize = 8;
  951. int stack[1024][2];
  952. stack[0][0] = 0;
  953. stack[0][1] = elements - 1;
  954. int stackIndex = 1;
  955. const dCompareKey comparator;
  956. while (stackIndex)
  957. {
  958. stackIndex--;
  959. int lo = stack[stackIndex][0];
  960. int hi = stack[stackIndex][1];
  961. if ((hi - lo) > batchSize)
  962. {
  963. int mid = (lo + hi) >> 1;
  964. if (comparator.Compare(array[lo], array[mid]) > 0)
  965. {
  966. std::swap(array[lo],
  967. array[mid]);
  968. }
  969. if (comparator.Compare(array[mid], array[hi]) > 0)
  970. {
  971. std::swap(array[mid],
  972. array[hi]);
  973. }
  974. if (comparator.Compare(array[lo], array[mid]) > 0)
  975. {
  976. std::swap(array[lo],
  977. array[mid]);
  978. }
  979. int i = lo + 1;
  980. int j = hi - 1;
  981. const T pivot(array[mid]);
  982. do
  983. {
  984. while (comparator.Compare(array[i], pivot) < 0)
  985. {
  986. i++;
  987. }
  988. while (comparator.Compare(array[j], pivot) > 0)
  989. {
  990. j--;
  991. }
  992. if (i <= j)
  993. {
  994. std::swap(array[i],
  995. array[j]);
  996. i++;
  997. j--;
  998. }
  999. } while (i <= j);
  1000. if (i < hi)
  1001. {
  1002. stack[stackIndex][0] = i;
  1003. stack[stackIndex][1] = hi;
  1004. stackIndex++;
  1005. }
  1006. if (lo < j)
  1007. {
  1008. stack[stackIndex][0] = lo;
  1009. stack[stackIndex][1] = j;
  1010. stackIndex++;
  1011. }
  1012. assert(stackIndex < int(sizeof(stack) / (2 * sizeof(stack[0][0]))));
  1013. }
  1014. }
  1015. int stride = batchSize + 1;
  1016. if (elements < stride)
  1017. {
  1018. stride = elements;
  1019. }
  1020. for (int i = 1; i < stride; ++i)
  1021. {
  1022. if (comparator.Compare(array[0], array[i]) > 0)
  1023. {
  1024. std::swap(array[0],
  1025. array[i]);
  1026. }
  1027. }
  1028. for (int i = 1; i < elements; ++i)
  1029. {
  1030. int j = i;
  1031. const T tmp(array[i]);
  1032. for (; comparator.Compare(array[j - 1], tmp) > 0; --j)
  1033. {
  1034. assert(j > 0);
  1035. array[j] = array[j - 1];
  1036. }
  1037. array[j] = tmp;
  1038. }
  1039. }
  1040. /*
  1041. Maintaining comment due to attribution
  1042. Purpose:
  1043. TRIANGLE_AREA_3D computes the area of a triangle in 3D.
  1044. Modified:
  1045. 22 April 1999
  1046. Author:
  1047. John Burkardt
  1048. Parameters:
  1049. Input, double X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, the (getX,getY,getZ)
  1050. coordinates of the corners of the triangle.
  1051. Output, double TRIANGLE_AREA_3D, the area of the triangle.
  1052. */
  1053. double ComputeArea(const VHACD::Vect3& p1,
  1054. const VHACD::Vect3& p2,
  1055. const VHACD::Vect3& p3)
  1056. {
  1057. /*
  1058. Find the projection of (P3-P1) onto (P2-P1).
  1059. */
  1060. double base = (p2 - p1).GetNorm();
  1061. /*
  1062. The height of the triangle is the length of (P3-P1) after its
  1063. projection onto (P2-P1) has been subtracted.
  1064. */
  1065. double height;
  1066. if (base == double(0.0))
  1067. {
  1068. height = double(0.0);
  1069. }
  1070. else
  1071. {
  1072. double dot = (p3 - p1).Dot(p2 - p1);
  1073. double alpha = dot / (base * base);
  1074. VHACD::Vect3 a = p3 - p1 - alpha * (p2 - p1);
  1075. height = a.GetNorm();
  1076. }
  1077. return double(0.5) * base * height;
  1078. }
  1079. bool ComputeCentroid(const std::vector<VHACD::Vertex>& points,
  1080. const std::vector<VHACD::Triangle>& indices,
  1081. VHACD::Vect3& center)
  1082. {
  1083. bool ret = false;
  1084. if (points.size())
  1085. {
  1086. center = VHACD::Vect3(0);
  1087. VHACD::Vect3 numerator(0);
  1088. double denominator = 0;
  1089. for (uint32_t i = 0; i < indices.size(); i++)
  1090. {
  1091. uint32_t i1 = indices[i].mI0;
  1092. uint32_t i2 = indices[i].mI1;
  1093. uint32_t i3 = indices[i].mI2;
  1094. const VHACD::Vect3& p1 = points[i1];
  1095. const VHACD::Vect3& p2 = points[i2];
  1096. const VHACD::Vect3& p3 = points[i3];
  1097. // Compute the average of the sum of the three positions
  1098. VHACD::Vect3 sum = (p1 + p2 + p3) / 3;
  1099. // Compute the area of this triangle
  1100. double area = ComputeArea(p1,
  1101. p2,
  1102. p3);
  1103. numerator += (sum * area);
  1104. denominator += area;
  1105. }
  1106. double recip = 1 / denominator;
  1107. center = numerator * recip;
  1108. ret = true;
  1109. }
  1110. return ret;
  1111. }
  1112. double Determinant3x3(const std::array<VHACD::Vect3, 3>& matrix,
  1113. double& error)
  1114. {
  1115. double det = double(0.0);
  1116. error = double(0.0);
  1117. double a01xa12 = matrix[0].GetY() * matrix[1].GetZ();
  1118. double a02xa11 = matrix[0].GetZ() * matrix[1].GetY();
  1119. error += (std::abs(a01xa12) + std::abs(a02xa11)) * std::abs(matrix[2].GetX());
  1120. det += (a01xa12 - a02xa11) * matrix[2].GetX();
  1121. double a00xa12 = matrix[0].GetX() * matrix[1].GetZ();
  1122. double a02xa10 = matrix[0].GetZ() * matrix[1].GetX();
  1123. error += (std::abs(a00xa12) + std::abs(a02xa10)) * std::abs(matrix[2].GetY());
  1124. det -= (a00xa12 - a02xa10) * matrix[2].GetY();
  1125. double a00xa11 = matrix[0].GetX() * matrix[1].GetY();
  1126. double a01xa10 = matrix[0].GetY() * matrix[1].GetX();
  1127. error += (std::abs(a00xa11) + std::abs(a01xa10)) * std::abs(matrix[2].GetZ());
  1128. det += (a00xa11 - a01xa10) * matrix[2].GetZ();
  1129. return det;
  1130. }
  1131. double ComputeMeshVolume(const std::vector<VHACD::Vertex>& vertices,
  1132. const std::vector<VHACD::Triangle>& indices)
  1133. {
  1134. double volume = 0;
  1135. for (uint32_t i = 0; i < indices.size(); i++)
  1136. {
  1137. const std::array<VHACD::Vect3, 3> m = {
  1138. vertices[indices[i].mI0],
  1139. vertices[indices[i].mI1],
  1140. vertices[indices[i].mI2]
  1141. };
  1142. double placeholder;
  1143. volume += Determinant3x3(m,
  1144. placeholder);
  1145. }
  1146. volume *= (double(1.0) / double(6.0));
  1147. if (volume < 0)
  1148. volume *= -1;
  1149. return volume;
  1150. }
  1151. /*
  1152. * To minimize memory allocations while maintaining pointer stability.
  1153. * Used in KdTreeNode and ConvexHull, as both use tree data structures that rely on pointer stability
  1154. * Neither rely on random access or iteration
  1155. * They just dump elements into a memory pool, then refer to pointers to the elements
  1156. * All elements are default constructed in NodeStorage's m_nodes array
  1157. */
  1158. template <typename T, std::size_t MaxBundleSize = 1024>
  1159. class NodeBundle
  1160. {
  1161. struct NodeStorage {
  1162. bool IsFull() const;
  1163. T& GetNextNode();
  1164. std::size_t m_index;
  1165. std::array<T, MaxBundleSize> m_nodes;
  1166. };
  1167. std::list<NodeStorage> m_list;
  1168. typename std::list<NodeStorage>::iterator m_head{ m_list.end() };
  1169. public:
  1170. T& GetNextNode();
  1171. T& GetFirstNode();
  1172. void Clear();
  1173. };
  1174. template <typename T, std::size_t MaxBundleSize>
  1175. bool NodeBundle<T, MaxBundleSize>::NodeStorage::IsFull() const
  1176. {
  1177. return m_index == MaxBundleSize;
  1178. }
  1179. template <typename T, std::size_t MaxBundleSize>
  1180. T& NodeBundle<T, MaxBundleSize>::NodeStorage::GetNextNode()
  1181. {
  1182. assert(m_index < MaxBundleSize);
  1183. T& ret = m_nodes[m_index];
  1184. m_index++;
  1185. return ret;
  1186. }
  1187. template <typename T, std::size_t MaxBundleSize>
  1188. T& NodeBundle<T, MaxBundleSize>::GetNextNode()
  1189. {
  1190. /*
  1191. * || short circuits, so doesn't dereference if m_bundle == m_bundleHead.end()
  1192. */
  1193. if ( m_head == m_list.end()
  1194. || m_head->IsFull())
  1195. {
  1196. m_head = m_list.emplace(m_list.end());
  1197. }
  1198. return m_head->GetNextNode();
  1199. }
  1200. template <typename T, std::size_t MaxBundleSize>
  1201. T& NodeBundle<T, MaxBundleSize>::GetFirstNode()
  1202. {
  1203. assert(m_head != m_list.end());
  1204. return m_list.front().m_nodes[0];
  1205. }
  1206. template <typename T, std::size_t MaxBundleSize>
  1207. void NodeBundle<T, MaxBundleSize>::Clear()
  1208. {
  1209. m_list.clear();
  1210. }
  1211. /*
  1212. * Returns index of highest set bit in x
  1213. */
  1214. inline int dExp2(int x)
  1215. {
  1216. int exp;
  1217. for (exp = -1; x; x >>= 1)
  1218. {
  1219. exp++;
  1220. }
  1221. return exp;
  1222. }
  1223. /*
  1224. * Reverses the order of the bits in v and returns the result
  1225. * Does not put fill any of the bits higher than the highest bit in v
  1226. * Only used to calculate index of ndNormalMap::m_normal when tessellating a triangle
  1227. */
  1228. inline int dBitReversal(int v,
  1229. int base)
  1230. {
  1231. int x = 0;
  1232. int power = dExp2(base) - 1;
  1233. do
  1234. {
  1235. x += (v & 1) << power;
  1236. v >>= 1;
  1237. power--;
  1238. } while (v);
  1239. return x;
  1240. }
  1241. class Googol
  1242. {
  1243. #define VHACD_GOOGOL_SIZE 4
  1244. public:
  1245. Googol() = default;
  1246. Googol(double value);
  1247. operator double() const;
  1248. Googol operator+(const Googol &A) const;
  1249. Googol operator-(const Googol &A) const;
  1250. Googol operator*(const Googol &A) const;
  1251. Googol operator/ (const Googol &A) const;
  1252. Googol& operator+= (const Googol &A);
  1253. Googol& operator-= (const Googol &A);
  1254. bool operator>(const Googol &A) const;
  1255. bool operator>=(const Googol &A) const;
  1256. bool operator<(const Googol &A) const;
  1257. bool operator<=(const Googol &A) const;
  1258. bool operator==(const Googol &A) const;
  1259. bool operator!=(const Googol &A) const;
  1260. Googol Abs() const;
  1261. Googol Floor() const;
  1262. Googol InvSqrt() const;
  1263. Googol Sqrt() const;
  1264. void ToString(char* const string) const;
  1265. private:
  1266. void NegateMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const;
  1267. void CopySignedMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const;
  1268. int NormalizeMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const;
  1269. void ShiftRightMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa,
  1270. int bits) const;
  1271. uint64_t CheckCarrier(uint64_t a, uint64_t b) const;
  1272. int LeadingZeros(uint64_t a) const;
  1273. void ExtendedMultiply(uint64_t a,
  1274. uint64_t b,
  1275. uint64_t& high,
  1276. uint64_t& low) const;
  1277. void ScaleMantissa(uint64_t* out,
  1278. uint64_t scale) const;
  1279. int m_sign{ 0 };
  1280. int m_exponent{ 0 };
  1281. std::array<uint64_t, VHACD_GOOGOL_SIZE> m_mantissa{ 0 };
  1282. public:
  1283. static Googol m_zero;
  1284. static Googol m_one;
  1285. static Googol m_two;
  1286. static Googol m_three;
  1287. static Googol m_half;
  1288. };
  1289. Googol Googol::m_zero(double(0.0));
  1290. Googol Googol::m_one(double(1.0));
  1291. Googol Googol::m_two(double(2.0));
  1292. Googol Googol::m_three(double(3.0));
  1293. Googol Googol::m_half(double(0.5));
  1294. Googol::Googol(double value)
  1295. {
  1296. int exp;
  1297. double mantissa = fabs(frexp(value, &exp));
  1298. m_exponent = exp;
  1299. m_sign = (value >= 0) ? 0 : 1;
  1300. m_mantissa[0] = uint64_t(double(uint64_t(1) << 62) * mantissa);
  1301. }
  1302. Googol::operator double() const
  1303. {
  1304. double mantissa = (double(1.0) / double(uint64_t(1) << 62)) * double(m_mantissa[0]);
  1305. mantissa = ldexp(mantissa, m_exponent) * (m_sign ? double(-1.0) : double(1.0));
  1306. return mantissa;
  1307. }
  1308. Googol Googol::operator+(const Googol &A) const
  1309. {
  1310. Googol tmp;
  1311. if (m_mantissa[0] && A.m_mantissa[0])
  1312. {
  1313. std::array<uint64_t, VHACD_GOOGOL_SIZE> mantissa0;
  1314. std::array<uint64_t, VHACD_GOOGOL_SIZE> mantissa1;
  1315. std::array<uint64_t, VHACD_GOOGOL_SIZE> mantissa;
  1316. CopySignedMantissa(mantissa0);
  1317. A.CopySignedMantissa(mantissa1);
  1318. int exponentDiff = m_exponent - A.m_exponent;
  1319. int exponent = m_exponent;
  1320. if (exponentDiff > 0)
  1321. {
  1322. ShiftRightMantissa(mantissa1,
  1323. exponentDiff);
  1324. }
  1325. else if (exponentDiff < 0)
  1326. {
  1327. exponent = A.m_exponent;
  1328. ShiftRightMantissa(mantissa0,
  1329. -exponentDiff);
  1330. }
  1331. uint64_t carrier = 0;
  1332. for (int i = VHACD_GOOGOL_SIZE - 1; i >= 0; i--)
  1333. {
  1334. uint64_t m0 = mantissa0[i];
  1335. uint64_t m1 = mantissa1[i];
  1336. mantissa[i] = m0 + m1 + carrier;
  1337. carrier = CheckCarrier(m0, m1) | CheckCarrier(m0 + m1, carrier);
  1338. }
  1339. int sign = 0;
  1340. if (int64_t(mantissa[0]) < 0)
  1341. {
  1342. sign = 1;
  1343. NegateMantissa(mantissa);
  1344. }
  1345. int bits = NormalizeMantissa(mantissa);
  1346. if (bits <= (-64 * VHACD_GOOGOL_SIZE))
  1347. {
  1348. tmp.m_sign = 0;
  1349. tmp.m_exponent = 0;
  1350. }
  1351. else
  1352. {
  1353. tmp.m_sign = sign;
  1354. tmp.m_exponent = int(exponent + bits);
  1355. }
  1356. tmp.m_mantissa = mantissa;
  1357. }
  1358. else if (A.m_mantissa[0])
  1359. {
  1360. tmp = A;
  1361. }
  1362. else
  1363. {
  1364. tmp = *this;
  1365. }
  1366. return tmp;
  1367. }
  1368. Googol Googol::operator-(const Googol &A) const
  1369. {
  1370. Googol tmp(A);
  1371. tmp.m_sign = !tmp.m_sign;
  1372. return *this + tmp;
  1373. }
  1374. Googol Googol::operator*(const Googol &A) const
  1375. {
  1376. if (m_mantissa[0] && A.m_mantissa[0])
  1377. {
  1378. std::array<uint64_t, VHACD_GOOGOL_SIZE * 2> mantissaAcc{ 0 };
  1379. for (int i = VHACD_GOOGOL_SIZE - 1; i >= 0; i--)
  1380. {
  1381. uint64_t a = m_mantissa[i];
  1382. if (a)
  1383. {
  1384. uint64_t mantissaScale[2 * VHACD_GOOGOL_SIZE] = { 0 };
  1385. A.ScaleMantissa(&mantissaScale[i], a);
  1386. uint64_t carrier = 0;
  1387. for (int j = 0; j < 2 * VHACD_GOOGOL_SIZE; j++)
  1388. {
  1389. const int k = 2 * VHACD_GOOGOL_SIZE - 1 - j;
  1390. uint64_t m0 = mantissaAcc[k];
  1391. uint64_t m1 = mantissaScale[k];
  1392. mantissaAcc[k] = m0 + m1 + carrier;
  1393. carrier = CheckCarrier(m0, m1) | CheckCarrier(m0 + m1, carrier);
  1394. }
  1395. }
  1396. }
  1397. uint64_t carrier = 0;
  1398. int bits = LeadingZeros(mantissaAcc[0]) - 2;
  1399. for (int i = 0; i < 2 * VHACD_GOOGOL_SIZE; i++)
  1400. {
  1401. const int k = 2 * VHACD_GOOGOL_SIZE - 1 - i;
  1402. uint64_t a = mantissaAcc[k];
  1403. mantissaAcc[k] = (a << uint64_t(bits)) | carrier;
  1404. carrier = a >> uint64_t(64 - bits);
  1405. }
  1406. int exp = m_exponent + A.m_exponent - (bits - 2);
  1407. Googol tmp;
  1408. tmp.m_sign = m_sign ^ A.m_sign;
  1409. tmp.m_exponent = exp;
  1410. for (std::size_t i = 0; i < tmp.m_mantissa.size(); ++i)
  1411. {
  1412. tmp.m_mantissa[i] = mantissaAcc[i];
  1413. }
  1414. return tmp;
  1415. }
  1416. return Googol(double(0.0));
  1417. }
  1418. Googol Googol::operator/(const Googol &A) const
  1419. {
  1420. Googol tmp(double(1.0) / A);
  1421. tmp = tmp * (m_two - A * tmp);
  1422. tmp = tmp * (m_two - A * tmp);
  1423. bool test = false;
  1424. int passes = 0;
  1425. do
  1426. {
  1427. passes++;
  1428. Googol tmp0(tmp);
  1429. tmp = tmp * (m_two - A * tmp);
  1430. test = tmp0 == tmp;
  1431. } while (test && (passes < (2 * VHACD_GOOGOL_SIZE)));
  1432. return (*this) * tmp;
  1433. }
  1434. Googol& Googol::operator+=(const Googol &A)
  1435. {
  1436. *this = *this + A;
  1437. return *this;
  1438. }
  1439. Googol& Googol::operator-=(const Googol &A)
  1440. {
  1441. *this = *this - A;
  1442. return *this;
  1443. }
  1444. bool Googol::operator>(const Googol &A) const
  1445. {
  1446. Googol tmp(*this - A);
  1447. return double(tmp) > double(0.0);
  1448. }
  1449. bool Googol::operator>=(const Googol &A) const
  1450. {
  1451. Googol tmp(*this - A);
  1452. return double(tmp) >= double(0.0);
  1453. }
  1454. bool Googol::operator<(const Googol &A) const
  1455. {
  1456. Googol tmp(*this - A);
  1457. return double(tmp) < double(0.0);
  1458. }
  1459. bool Googol::operator<=(const Googol &A) const
  1460. {
  1461. Googol tmp(*this - A);
  1462. return double(tmp) <= double(0.0);
  1463. }
  1464. bool Googol::operator==(const Googol &A) const
  1465. {
  1466. return m_sign == A.m_sign
  1467. && m_exponent == A.m_exponent
  1468. && m_mantissa == A.m_mantissa;
  1469. }
  1470. bool Googol::operator!=(const Googol &A) const
  1471. {
  1472. return !(*this == A);
  1473. }
  1474. Googol Googol::Abs() const
  1475. {
  1476. Googol tmp(*this);
  1477. tmp.m_sign = 0;
  1478. return tmp;
  1479. }
  1480. Googol Googol::Floor() const
  1481. {
  1482. if (m_exponent < 1)
  1483. {
  1484. return Googol(double(0.0));
  1485. }
  1486. int bits = m_exponent + 2;
  1487. int start = 0;
  1488. while (bits >= 64)
  1489. {
  1490. bits -= 64;
  1491. start++;
  1492. }
  1493. Googol tmp(*this);
  1494. for (int i = VHACD_GOOGOL_SIZE - 1; i > start; i--)
  1495. {
  1496. tmp.m_mantissa[i] = 0;
  1497. }
  1498. // some compilers do no like this and I do not know why is that
  1499. //uint64_t mask = (-1LL) << (64 - bits);
  1500. uint64_t mask(~0ULL);
  1501. mask <<= (64 - bits);
  1502. tmp.m_mantissa[start] &= mask;
  1503. return tmp;
  1504. }
  1505. Googol Googol::InvSqrt() const
  1506. {
  1507. const Googol& me = *this;
  1508. Googol x(double(1.0) / sqrt(me));
  1509. int test = 0;
  1510. int passes = 0;
  1511. do
  1512. {
  1513. passes++;
  1514. Googol tmp(x);
  1515. x = m_half * x * (m_three - me * x * x);
  1516. test = (x != tmp);
  1517. } while (test && (passes < (2 * VHACD_GOOGOL_SIZE)));
  1518. return x;
  1519. }
  1520. Googol Googol::Sqrt() const
  1521. {
  1522. return *this * InvSqrt();
  1523. }
  1524. void Googol::ToString(char* const string) const
  1525. {
  1526. Googol tmp(*this);
  1527. Googol base(double(10.0));
  1528. while (double(tmp) > double(1.0))
  1529. {
  1530. tmp = tmp / base;
  1531. }
  1532. int index = 0;
  1533. while (tmp.m_mantissa[0])
  1534. {
  1535. tmp = tmp * base;
  1536. Googol digit(tmp.Floor());
  1537. tmp -= digit;
  1538. double val = digit;
  1539. string[index] = char(val) + '0';
  1540. index++;
  1541. }
  1542. string[index] = 0;
  1543. }
  1544. void Googol::NegateMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const
  1545. {
  1546. uint64_t carrier = 1;
  1547. for (size_t i = mantissa.size() - 1; i < mantissa.size(); i--)
  1548. {
  1549. uint64_t a = ~mantissa[i] + carrier;
  1550. if (a)
  1551. {
  1552. carrier = 0;
  1553. }
  1554. mantissa[i] = a;
  1555. }
  1556. }
  1557. void Googol::CopySignedMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const
  1558. {
  1559. mantissa = m_mantissa;
  1560. if (m_sign)
  1561. {
  1562. NegateMantissa(mantissa);
  1563. }
  1564. }
  1565. int Googol::NormalizeMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa) const
  1566. {
  1567. int bits = 0;
  1568. if (int64_t(mantissa[0] * 2) < 0)
  1569. {
  1570. bits = 1;
  1571. ShiftRightMantissa(mantissa, 1);
  1572. }
  1573. else
  1574. {
  1575. while (!mantissa[0] && bits > (-64 * VHACD_GOOGOL_SIZE))
  1576. {
  1577. bits -= 64;
  1578. for (int i = 1; i < VHACD_GOOGOL_SIZE; i++) {
  1579. mantissa[i - 1] = mantissa[i];
  1580. }
  1581. mantissa[VHACD_GOOGOL_SIZE - 1] = 0;
  1582. }
  1583. if (bits > (-64 * VHACD_GOOGOL_SIZE))
  1584. {
  1585. int n = LeadingZeros(mantissa[0]) - 2;
  1586. if (n > 0)
  1587. {
  1588. uint64_t carrier = 0;
  1589. for (int i = VHACD_GOOGOL_SIZE - 1; i >= 0; i--)
  1590. {
  1591. uint64_t a = mantissa[i];
  1592. mantissa[i] = (a << n) | carrier;
  1593. carrier = a >> (64 - n);
  1594. }
  1595. bits -= n;
  1596. }
  1597. else if (n < 0)
  1598. {
  1599. // this is very rare but it does happens, whee the leading zeros of the mantissa is an exact multiple of 64
  1600. uint64_t carrier = 0;
  1601. int shift = -n;
  1602. for (int i = 0; i < VHACD_GOOGOL_SIZE; i++)
  1603. {
  1604. uint64_t a = mantissa[i];
  1605. mantissa[i] = (a >> shift) | carrier;
  1606. carrier = a << (64 - shift);
  1607. }
  1608. bits -= n;
  1609. }
  1610. }
  1611. }
  1612. return bits;
  1613. }
  1614. void Googol::ShiftRightMantissa(std::array<uint64_t, VHACD_GOOGOL_SIZE>& mantissa,
  1615. int bits) const
  1616. {
  1617. uint64_t carrier = 0;
  1618. if (int64_t(mantissa[0]) < int64_t(0))
  1619. {
  1620. carrier = uint64_t(-1);
  1621. }
  1622. while (bits >= 64)
  1623. {
  1624. for (int i = VHACD_GOOGOL_SIZE - 2; i >= 0; i--)
  1625. {
  1626. mantissa[i + 1] = mantissa[i];
  1627. }
  1628. mantissa[0] = carrier;
  1629. bits -= 64;
  1630. }
  1631. if (bits > 0)
  1632. {
  1633. carrier <<= (64 - bits);
  1634. for (int i = 0; i < VHACD_GOOGOL_SIZE; i++)
  1635. {
  1636. uint64_t a = mantissa[i];
  1637. mantissa[i] = (a >> bits) | carrier;
  1638. carrier = a << (64 - bits);
  1639. }
  1640. }
  1641. }
  1642. uint64_t Googol::CheckCarrier(uint64_t a, uint64_t b) const
  1643. {
  1644. return ((uint64_t(-1) - b) < a) ? uint64_t(1) : 0;
  1645. }
  1646. int Googol::LeadingZeros(uint64_t a) const
  1647. {
  1648. #define VHACD_COUNTBIT(mask, add) \
  1649. do { \
  1650. uint64_t test = a & mask; \
  1651. n += test ? 0 : add; \
  1652. a = test ? test : (a & ~mask); \
  1653. } while (false)
  1654. int n = 0;
  1655. VHACD_COUNTBIT(0xffffffff00000000LL, 32);
  1656. VHACD_COUNTBIT(0xffff0000ffff0000LL, 16);
  1657. VHACD_COUNTBIT(0xff00ff00ff00ff00LL, 8);
  1658. VHACD_COUNTBIT(0xf0f0f0f0f0f0f0f0LL, 4);
  1659. VHACD_COUNTBIT(0xccccccccccccccccLL, 2);
  1660. VHACD_COUNTBIT(0xaaaaaaaaaaaaaaaaLL, 1);
  1661. return n;
  1662. }
  1663. void Googol::ExtendedMultiply(uint64_t a,
  1664. uint64_t b,
  1665. uint64_t& high,
  1666. uint64_t& low) const
  1667. {
  1668. uint64_t bLow = b & 0xffffffff;
  1669. uint64_t bHigh = b >> 32;
  1670. uint64_t aLow = a & 0xffffffff;
  1671. uint64_t aHigh = a >> 32;
  1672. uint64_t l = bLow * aLow;
  1673. uint64_t c1 = bHigh * aLow;
  1674. uint64_t c2 = bLow * aHigh;
  1675. uint64_t m = c1 + c2;
  1676. uint64_t carrier = CheckCarrier(c1, c2) << 32;
  1677. uint64_t h = bHigh * aHigh + carrier;
  1678. uint64_t ml = m << 32;
  1679. uint64_t ll = l + ml;
  1680. uint64_t mh = (m >> 32) + CheckCarrier(l, ml);
  1681. uint64_t hh = h + mh;
  1682. low = ll;
  1683. high = hh;
  1684. }
  1685. void Googol::ScaleMantissa(uint64_t* dst,
  1686. uint64_t scale) const
  1687. {
  1688. uint64_t carrier = 0;
  1689. for (int i = VHACD_GOOGOL_SIZE - 1; i >= 0; i--)
  1690. {
  1691. if (m_mantissa[i])
  1692. {
  1693. uint64_t low;
  1694. uint64_t high;
  1695. ExtendedMultiply(scale,
  1696. m_mantissa[i],
  1697. high,
  1698. low);
  1699. uint64_t acc = low + carrier;
  1700. carrier = CheckCarrier(low,
  1701. carrier);
  1702. carrier += high;
  1703. dst[i + 1] = acc;
  1704. }
  1705. else
  1706. {
  1707. dst[i + 1] = carrier;
  1708. carrier = 0;
  1709. }
  1710. }
  1711. dst[0] = carrier;
  1712. }
  1713. Googol Determinant3x3(const std::array<VHACD::Vector3<Googol>, 3>& matrix)
  1714. {
  1715. Googol det = double(0.0);
  1716. Googol a01xa12 = matrix[0].GetY() * matrix[1].GetZ();
  1717. Googol a02xa11 = matrix[0].GetZ() * matrix[1].GetY();
  1718. det += (a01xa12 - a02xa11) * matrix[2].GetX();
  1719. Googol a00xa12 = matrix[0].GetX() * matrix[1].GetZ();
  1720. Googol a02xa10 = matrix[0].GetZ() * matrix[1].GetX();
  1721. det -= (a00xa12 - a02xa10) * matrix[2].GetY();
  1722. Googol a00xa11 = matrix[0].GetX() * matrix[1].GetY();
  1723. Googol a01xa10 = matrix[0].GetY() * matrix[1].GetX();
  1724. det += (a00xa11 - a01xa10) * matrix[2].GetZ();
  1725. return det;
  1726. }
  1727. class HullPlane : public VHACD::Vect3
  1728. {
  1729. public:
  1730. HullPlane(const HullPlane&) = default;
  1731. HullPlane(double x,
  1732. double y,
  1733. double z,
  1734. double w);
  1735. HullPlane(const VHACD::Vect3& p,
  1736. double w);
  1737. HullPlane(const VHACD::Vect3& p0,
  1738. const VHACD::Vect3& p1,
  1739. const VHACD::Vect3& p2);
  1740. HullPlane Scale(double s) const;
  1741. HullPlane& operator=(const HullPlane& rhs);
  1742. double Evalue(const VHACD::Vect3 &point) const;
  1743. double& GetW();
  1744. const double& GetW() const;
  1745. private:
  1746. double m_w;
  1747. };
  1748. HullPlane::HullPlane(double x,
  1749. double y,
  1750. double z,
  1751. double w)
  1752. : VHACD::Vect3(x, y, z)
  1753. , m_w(w)
  1754. {
  1755. }
  1756. HullPlane::HullPlane(const VHACD::Vect3& p,
  1757. double w)
  1758. : VHACD::Vect3(p)
  1759. , m_w(w)
  1760. {
  1761. }
  1762. HullPlane::HullPlane(const VHACD::Vect3& p0,
  1763. const VHACD::Vect3& p1,
  1764. const VHACD::Vect3& p2)
  1765. : VHACD::Vect3((p1 - p0).Cross(p2 - p0))
  1766. , m_w(-Dot(p0))
  1767. {
  1768. }
  1769. HullPlane HullPlane::Scale(double s) const
  1770. {
  1771. return HullPlane(*this * s,
  1772. m_w * s);
  1773. }
  1774. HullPlane& HullPlane::operator=(const HullPlane& rhs)
  1775. {
  1776. GetX() = rhs.GetX();
  1777. GetY() = rhs.GetY();
  1778. GetZ() = rhs.GetZ();
  1779. m_w = rhs.m_w;
  1780. return *this;
  1781. }
  1782. double HullPlane::Evalue(const VHACD::Vect3& point) const
  1783. {
  1784. return Dot(point) + m_w;
  1785. }
  1786. double& HullPlane::GetW()
  1787. {
  1788. return m_w;
  1789. }
  1790. const double& HullPlane::GetW() const
  1791. {
  1792. return m_w;
  1793. }
  1794. class ConvexHullFace
  1795. {
  1796. public:
  1797. ConvexHullFace() = default;
  1798. double Evalue(const std::vector<VHACD::Vect3>& pointArray,
  1799. const VHACD::Vect3& point) const;
  1800. HullPlane GetPlaneEquation(const std::vector<VHACD::Vect3>& pointArray,
  1801. bool& isValid) const;
  1802. std::array<int, 3> m_index;
  1803. private:
  1804. int m_mark{ 0 };
  1805. std::array<std::list<ConvexHullFace>::iterator, 3> m_twin;
  1806. friend class ConvexHull;
  1807. };
  1808. double ConvexHullFace::Evalue(const std::vector<VHACD::Vect3>& pointArray,
  1809. const VHACD::Vect3& point) const
  1810. {
  1811. const VHACD::Vect3& p0 = pointArray[m_index[0]];
  1812. const VHACD::Vect3& p1 = pointArray[m_index[1]];
  1813. const VHACD::Vect3& p2 = pointArray[m_index[2]];
  1814. std::array<VHACD::Vect3, 3> matrix = { p2 - p0, p1 - p0, point - p0 };
  1815. double error;
  1816. double det = Determinant3x3(matrix,
  1817. error);
  1818. // the code use double, however the threshold for accuracy test is the machine precision of a float.
  1819. // by changing this to a smaller number, the code should run faster since many small test will be considered valid
  1820. // the precision must be a power of two no smaller than the machine precision of a double, (1<<48)
  1821. // float64(1<<30) can be a good value
  1822. // double precision = double (1.0f) / double (1<<30);
  1823. double precision = double(1.0) / double(1 << 24);
  1824. double errbound = error * precision;
  1825. if (fabs(det) > errbound)
  1826. {
  1827. return det;
  1828. }
  1829. const VHACD::Vector3<Googol> p0g = pointArray[m_index[0]];
  1830. const VHACD::Vector3<Googol> p1g = pointArray[m_index[1]];
  1831. const VHACD::Vector3<Googol> p2g = pointArray[m_index[2]];
  1832. const VHACD::Vector3<Googol> pointg = point;
  1833. std::array<VHACD::Vector3<Googol>, 3> exactMatrix = { p2g - p0g, p1g - p0g, pointg - p0g };
  1834. return Determinant3x3(exactMatrix);
  1835. }
  1836. HullPlane ConvexHullFace::GetPlaneEquation(const std::vector<VHACD::Vect3>& pointArray,
  1837. bool& isvalid) const
  1838. {
  1839. const VHACD::Vect3& p0 = pointArray[m_index[0]];
  1840. const VHACD::Vect3& p1 = pointArray[m_index[1]];
  1841. const VHACD::Vect3& p2 = pointArray[m_index[2]];
  1842. HullPlane plane(p0, p1, p2);
  1843. isvalid = false;
  1844. double mag2 = plane.Dot(plane);
  1845. if (mag2 > double(1.0e-16))
  1846. {
  1847. isvalid = true;
  1848. plane = plane.Scale(double(1.0) / sqrt(mag2));
  1849. }
  1850. return plane;
  1851. }
  1852. class ConvexHullVertex : public VHACD::Vect3
  1853. {
  1854. public:
  1855. ConvexHullVertex() = default;
  1856. ConvexHullVertex(const ConvexHullVertex&) = default;
  1857. ConvexHullVertex& operator=(const ConvexHullVertex& rhs) = default;
  1858. using VHACD::Vect3::operator=;
  1859. int m_mark{ 0 };
  1860. };
  1861. class ConvexHullAABBTreeNode
  1862. {
  1863. #define VHACD_CONVEXHULL_3D_VERTEX_CLUSTER_SIZE 8
  1864. public:
  1865. ConvexHullAABBTreeNode() = default;
  1866. ConvexHullAABBTreeNode(ConvexHullAABBTreeNode* parent);
  1867. VHACD::Vect3 m_box[2];
  1868. ConvexHullAABBTreeNode* m_left{ nullptr };
  1869. ConvexHullAABBTreeNode* m_right{ nullptr };
  1870. ConvexHullAABBTreeNode* m_parent{ nullptr };
  1871. size_t m_count;
  1872. std::array<size_t, VHACD_CONVEXHULL_3D_VERTEX_CLUSTER_SIZE> m_indices;
  1873. };
  1874. ConvexHullAABBTreeNode::ConvexHullAABBTreeNode(ConvexHullAABBTreeNode* parent)
  1875. : m_parent(parent)
  1876. {
  1877. }
  1878. class ConvexHull
  1879. {
  1880. class ndNormalMap;
  1881. public:
  1882. ConvexHull(const ConvexHull& source);
  1883. ConvexHull(const std::vector<::VHACD::Vertex>& vertexCloud,
  1884. double distTol,
  1885. int maxVertexCount = 0x7fffffff);
  1886. ~ConvexHull() = default;
  1887. const std::vector<VHACD::Vect3>& GetVertexPool() const;
  1888. const std::list<ConvexHullFace>& GetList() const { return m_list; }
  1889. private:
  1890. void BuildHull(const std::vector<::VHACD::Vertex>& vertexCloud,
  1891. double distTol,
  1892. int maxVertexCount);
  1893. void GetUniquePoints(std::vector<ConvexHullVertex>& points);
  1894. int InitVertexArray(std::vector<ConvexHullVertex>& points,
  1895. NodeBundle<ConvexHullAABBTreeNode>& memoryPool);
  1896. ConvexHullAABBTreeNode* BuildTreeNew(std::vector<ConvexHullVertex>& points,
  1897. std::vector<ConvexHullAABBTreeNode>& memoryPool) const;
  1898. ConvexHullAABBTreeNode* BuildTreeOld(std::vector<ConvexHullVertex>& points,
  1899. NodeBundle<ConvexHullAABBTreeNode>& memoryPool);
  1900. ConvexHullAABBTreeNode* BuildTreeRecurse(ConvexHullAABBTreeNode* const parent,
  1901. ConvexHullVertex* const points,
  1902. int count,
  1903. int baseIndex,
  1904. NodeBundle<ConvexHullAABBTreeNode>& memoryPool) const;
  1905. std::list<ConvexHullFace>::iterator AddFace(int i0,
  1906. int i1,
  1907. int i2);
  1908. void CalculateConvexHull3D(ConvexHullAABBTreeNode* vertexTree,
  1909. std::vector<ConvexHullVertex>& points,
  1910. int count,
  1911. double distTol,
  1912. int maxVertexCount);
  1913. int SupportVertex(ConvexHullAABBTreeNode** const tree,
  1914. const std::vector<ConvexHullVertex>& points,
  1915. const VHACD::Vect3& dir,
  1916. const bool removeEntry = true) const;
  1917. double TetrahedrumVolume(const VHACD::Vect3& p0,
  1918. const VHACD::Vect3& p1,
  1919. const VHACD::Vect3& p2,
  1920. const VHACD::Vect3& p3) const;
  1921. std::list<ConvexHullFace> m_list;
  1922. VHACD::Vect3 m_aabbP0{ 0 };
  1923. VHACD::Vect3 m_aabbP1{ 0 };
  1924. double m_diag{ 0.0 };
  1925. std::vector<VHACD::Vect3> m_points;
  1926. };
  1927. class ConvexHull::ndNormalMap
  1928. {
  1929. public:
  1930. ndNormalMap();
  1931. static const ndNormalMap& GetNormalMap();
  1932. void TessellateTriangle(int level,
  1933. const VHACD::Vect3& p0,
  1934. const VHACD::Vect3& p1,
  1935. const VHACD::Vect3& p2,
  1936. int& count);
  1937. std::array<VHACD::Vect3, 128> m_normal;
  1938. int m_count{ 128 };
  1939. };
  1940. const ConvexHull::ndNormalMap& ConvexHull::ndNormalMap::GetNormalMap()
  1941. {
  1942. static ndNormalMap normalMap;
  1943. return normalMap;
  1944. }
  1945. void ConvexHull::ndNormalMap::TessellateTriangle(int level,
  1946. const VHACD::Vect3& p0,
  1947. const VHACD::Vect3& p1,
  1948. const VHACD::Vect3& p2,
  1949. int& count)
  1950. {
  1951. if (level)
  1952. {
  1953. assert(fabs(p0.Dot(p0) - double(1.0)) < double(1.0e-4));
  1954. assert(fabs(p1.Dot(p1) - double(1.0)) < double(1.0e-4));
  1955. assert(fabs(p2.Dot(p2) - double(1.0)) < double(1.0e-4));
  1956. VHACD::Vect3 p01(p0 + p1);
  1957. VHACD::Vect3 p12(p1 + p2);
  1958. VHACD::Vect3 p20(p2 + p0);
  1959. p01 = p01 * (double(1.0) / p01.GetNorm());
  1960. p12 = p12 * (double(1.0) / p12.GetNorm());
  1961. p20 = p20 * (double(1.0) / p20.GetNorm());
  1962. assert(fabs(p01.GetNormSquared() - double(1.0)) < double(1.0e-4));
  1963. assert(fabs(p12.GetNormSquared() - double(1.0)) < double(1.0e-4));
  1964. assert(fabs(p20.GetNormSquared() - double(1.0)) < double(1.0e-4));
  1965. TessellateTriangle(level - 1, p0, p01, p20, count);
  1966. TessellateTriangle(level - 1, p1, p12, p01, count);
  1967. TessellateTriangle(level - 1, p2, p20, p12, count);
  1968. TessellateTriangle(level - 1, p01, p12, p20, count);
  1969. }
  1970. else
  1971. {
  1972. /*
  1973. * This is just m_normal[index] = n.Normalized(), but due to tiny floating point errors, causes
  1974. * different outputs, so I'm leaving it
  1975. */
  1976. HullPlane n(p0, p1, p2);
  1977. n = n.Scale(double(1.0) / n.GetNorm());
  1978. n.GetW() = double(0.0);
  1979. int index = dBitReversal(count,
  1980. int(m_normal.size()));
  1981. m_normal[index] = n;
  1982. count++;
  1983. assert(count <= int(m_normal.size()));
  1984. }
  1985. }
  1986. ConvexHull::ndNormalMap::ndNormalMap()
  1987. {
  1988. VHACD::Vect3 p0(double( 1.0), double( 0.0), double( 0.0));
  1989. VHACD::Vect3 p1(double(-1.0), double( 0.0), double( 0.0));
  1990. VHACD::Vect3 p2(double( 0.0), double( 1.0), double( 0.0));
  1991. VHACD::Vect3 p3(double( 0.0), double(-1.0), double( 0.0));
  1992. VHACD::Vect3 p4(double( 0.0), double( 0.0), double( 1.0));
  1993. VHACD::Vect3 p5(double( 0.0), double( 0.0), double(-1.0));
  1994. int count = 0;
  1995. int subdivisions = 2;
  1996. TessellateTriangle(subdivisions, p4, p0, p2, count);
  1997. TessellateTriangle(subdivisions, p0, p5, p2, count);
  1998. TessellateTriangle(subdivisions, p5, p1, p2, count);
  1999. TessellateTriangle(subdivisions, p1, p4, p2, count);
  2000. TessellateTriangle(subdivisions, p0, p4, p3, count);
  2001. TessellateTriangle(subdivisions, p5, p0, p3, count);
  2002. TessellateTriangle(subdivisions, p1, p5, p3, count);
  2003. TessellateTriangle(subdivisions, p4, p1, p3, count);
  2004. }
  2005. ConvexHull::ConvexHull(const std::vector<::VHACD::Vertex>& vertexCloud,
  2006. double distTol,
  2007. int maxVertexCount)
  2008. {
  2009. if (vertexCloud.size() >= 4)
  2010. {
  2011. BuildHull(vertexCloud,
  2012. distTol,
  2013. maxVertexCount);
  2014. }
  2015. }
  2016. const std::vector<VHACD::Vect3>& ConvexHull::GetVertexPool() const
  2017. {
  2018. return m_points;
  2019. }
  2020. void ConvexHull::BuildHull(const std::vector<::VHACD::Vertex>& vertexCloud,
  2021. double distTol,
  2022. int maxVertexCount)
  2023. {
  2024. size_t treeCount = vertexCloud.size() / (VHACD_CONVEXHULL_3D_VERTEX_CLUSTER_SIZE >> 1);
  2025. treeCount = std::max(treeCount, size_t(4)) * 2;
  2026. std::vector<ConvexHullVertex> points(vertexCloud.size());
  2027. /*
  2028. * treePool provides a memory pool for the AABB tree
  2029. * Each node is either a leaf or non-leaf node
  2030. * Non-leaf nodes have up to 8 vertices
  2031. * Vertices are specified by the m_indices array and are accessed via the points array
  2032. *
  2033. * Later on in ConvexHull::SupportVertex, the tree is used directly
  2034. * It differentiates between ConvexHullAABBTreeNode and ConvexHull3DPointCluster by whether the m_left and m_right
  2035. * pointers are null or not
  2036. *
  2037. * Pointers have to be stable
  2038. */
  2039. NodeBundle<ConvexHullAABBTreeNode> treePool;
  2040. for (size_t i = 0; i < vertexCloud.size(); ++i)
  2041. {
  2042. points[i] = VHACD::Vect3(vertexCloud[i]);
  2043. }
  2044. int count = InitVertexArray(points,
  2045. treePool);
  2046. if (m_points.size() >= 4)
  2047. {
  2048. CalculateConvexHull3D(&treePool.GetFirstNode(),
  2049. points,
  2050. count,
  2051. distTol,
  2052. maxVertexCount);
  2053. }
  2054. }
  2055. void ConvexHull::GetUniquePoints(std::vector<ConvexHullVertex>& points)
  2056. {
  2057. class CompareVertex
  2058. {
  2059. public:
  2060. int Compare(const ConvexHullVertex& elementA, const ConvexHullVertex& elementB) const
  2061. {
  2062. for (int i = 0; i < 3; i++)
  2063. {
  2064. if (elementA[i] < elementB[i])
  2065. {
  2066. return -1;
  2067. }
  2068. else if (elementA[i] > elementB[i])
  2069. {
  2070. return 1;
  2071. }
  2072. }
  2073. return 0;
  2074. }
  2075. };
  2076. int count = int(points.size());
  2077. Sort<ConvexHullVertex, CompareVertex>(points.data(),
  2078. count);
  2079. int indexCount = 0;
  2080. CompareVertex compareVertex;
  2081. for (int i = 1; i < count; ++i)
  2082. {
  2083. for (; i < count; ++i)
  2084. {
  2085. if (compareVertex.Compare(points[indexCount], points[i]))
  2086. {
  2087. indexCount++;
  2088. points[indexCount] = points[i];
  2089. break;
  2090. }
  2091. }
  2092. }
  2093. points.resize(indexCount + 1);
  2094. }
  2095. ConvexHullAABBTreeNode* ConvexHull::BuildTreeRecurse(ConvexHullAABBTreeNode* const parent,
  2096. ConvexHullVertex* const points,
  2097. int count,
  2098. int baseIndex,
  2099. NodeBundle<ConvexHullAABBTreeNode>& memoryPool) const
  2100. {
  2101. ConvexHullAABBTreeNode* tree = nullptr;
  2102. assert(count);
  2103. VHACD::Vect3 minP( double(1.0e15));
  2104. VHACD::Vect3 maxP(-double(1.0e15));
  2105. if (count <= VHACD_CONVEXHULL_3D_VERTEX_CLUSTER_SIZE)
  2106. {
  2107. ConvexHullAABBTreeNode& clump = memoryPool.GetNextNode();
  2108. clump.m_count = count;
  2109. for (int i = 0; i < count; ++i)
  2110. {
  2111. clump.m_indices[i] = i + baseIndex;
  2112. const VHACD::Vect3& p = points[i];
  2113. minP = minP.CWiseMin(p);
  2114. maxP = maxP.CWiseMax(p);
  2115. }
  2116. clump.m_left = nullptr;
  2117. clump.m_right = nullptr;
  2118. tree = &clump;
  2119. }
  2120. else
  2121. {
  2122. VHACD::Vect3 median(0);
  2123. VHACD::Vect3 varian(0);
  2124. for (int i = 0; i < count; ++i)
  2125. {
  2126. const VHACD::Vect3& p = points[i];
  2127. minP = minP.CWiseMin(p);
  2128. maxP = maxP.CWiseMax(p);
  2129. median += p;
  2130. varian += p.CWiseMul(p);
  2131. }
  2132. varian = varian * double(count) - median.CWiseMul(median);
  2133. int index = 0;
  2134. double maxVarian = double(-1.0e10);
  2135. for (int i = 0; i < 3; ++i)
  2136. {
  2137. if (varian[i] > maxVarian)
  2138. {
  2139. index = i;
  2140. maxVarian = varian[i];
  2141. }
  2142. }
  2143. VHACD::Vect3 center(median * (double(1.0) / double(count)));
  2144. double test = center[index];
  2145. int i0 = 0;
  2146. int i1 = count - 1;
  2147. do
  2148. {
  2149. for (; i0 <= i1; i0++)
  2150. {
  2151. double val = points[i0][index];
  2152. if (val > test)
  2153. {
  2154. break;
  2155. }
  2156. }
  2157. for (; i1 >= i0; i1--)
  2158. {
  2159. double val = points[i1][index];
  2160. if (val < test)
  2161. {
  2162. break;
  2163. }
  2164. }
  2165. if (i0 < i1)
  2166. {
  2167. std::swap(points[i0],
  2168. points[i1]);
  2169. i0++;
  2170. i1--;
  2171. }
  2172. } while (i0 <= i1);
  2173. if (i0 == 0)
  2174. {
  2175. i0 = count / 2;
  2176. }
  2177. if (i0 >= (count - 1))
  2178. {
  2179. i0 = count / 2;
  2180. }
  2181. tree = &memoryPool.GetNextNode();
  2182. assert(i0);
  2183. assert(count - i0);
  2184. tree->m_left = BuildTreeRecurse(tree,
  2185. points,
  2186. i0,
  2187. baseIndex,
  2188. memoryPool);
  2189. tree->m_right = BuildTreeRecurse(tree,
  2190. &points[i0],
  2191. count - i0,
  2192. i0 + baseIndex,
  2193. memoryPool);
  2194. }
  2195. assert(tree);
  2196. tree->m_parent = parent;
  2197. /*
  2198. * WARNING: Changing the compiler conversion of 1.0e-3f changes the results of the convex decomposition
  2199. * Inflate the tree's bounding box slightly
  2200. */
  2201. tree->m_box[0] = minP - VHACD::Vect3(double(1.0e-3f));
  2202. tree->m_box[1] = maxP + VHACD::Vect3(double(1.0e-3f));
  2203. return tree;
  2204. }
  2205. ConvexHullAABBTreeNode* ConvexHull::BuildTreeOld(std::vector<ConvexHullVertex>& points,
  2206. NodeBundle<ConvexHullAABBTreeNode>& memoryPool)
  2207. {
  2208. GetUniquePoints(points);
  2209. int count = int(points.size());
  2210. if (count < 4)
  2211. {
  2212. return nullptr;
  2213. }
  2214. return BuildTreeRecurse(nullptr,
  2215. points.data(),
  2216. count,
  2217. 0,
  2218. memoryPool);
  2219. }
  2220. ConvexHullAABBTreeNode* ConvexHull::BuildTreeNew(std::vector<ConvexHullVertex>& points,
  2221. std::vector<ConvexHullAABBTreeNode>& memoryPool) const
  2222. {
  2223. class dCluster
  2224. {
  2225. public:
  2226. VHACD::Vect3 m_sum{ double(0.0) };
  2227. VHACD::Vect3 m_sum2{ double(0.0) };
  2228. int m_start{ 0 };
  2229. int m_count{ 0 };
  2230. };
  2231. dCluster firstCluster;
  2232. firstCluster.m_count = int(points.size());
  2233. for (int i = 0; i < firstCluster.m_count; ++i)
  2234. {
  2235. const VHACD::Vect3& p = points[i];
  2236. firstCluster.m_sum += p;
  2237. firstCluster.m_sum2 += p.CWiseMul(p);
  2238. }
  2239. int baseCount = 0;
  2240. const int clusterSize = 16;
  2241. if (firstCluster.m_count > clusterSize)
  2242. {
  2243. dCluster spliteStack[128];
  2244. spliteStack[0] = firstCluster;
  2245. size_t stack = 1;
  2246. while (stack)
  2247. {
  2248. stack--;
  2249. dCluster cluster (spliteStack[stack]);
  2250. const VHACD::Vect3 origin(cluster.m_sum * (double(1.0) / cluster.m_count));
  2251. const VHACD::Vect3 variance2(cluster.m_sum2 * (double(1.0) / cluster.m_count) - origin.CWiseMul(origin));
  2252. double maxVariance2 = variance2.MaxCoeff();
  2253. if ( (cluster.m_count <= clusterSize)
  2254. || (stack > (sizeof(spliteStack) / sizeof(spliteStack[0]) - 4))
  2255. || (maxVariance2 < 1.e-4f))
  2256. {
  2257. // no sure if this is beneficial,
  2258. // the array is so small that seem too much overhead
  2259. //int maxIndex = 0;
  2260. //double min_x = 1.0e20f;
  2261. //for (int i = 0; i < cluster.m_count; ++i)
  2262. //{
  2263. // if (points[cluster.m_start + i].getX() < min_x)
  2264. // {
  2265. // maxIndex = i;
  2266. // min_x = points[cluster.m_start + i].getX();
  2267. // }
  2268. //}
  2269. //Swap(points[cluster.m_start], points[cluster.m_start + maxIndex]);
  2270. //
  2271. //for (int i = 2; i < cluster.m_count; ++i)
  2272. //{
  2273. // int j = i;
  2274. // ConvexHullVertex tmp(points[cluster.m_start + i]);
  2275. // for (; points[cluster.m_start + j - 1].getX() > tmp.getX(); --j)
  2276. // {
  2277. // assert(j > 0);
  2278. // points[cluster.m_start + j] = points[cluster.m_start + j - 1];
  2279. // }
  2280. // points[cluster.m_start + j] = tmp;
  2281. //}
  2282. int count = cluster.m_count;
  2283. for (int i = cluster.m_count - 1; i > 0; --i)
  2284. {
  2285. for (int j = i - 1; j >= 0; --j)
  2286. {
  2287. VHACD::Vect3 error(points[cluster.m_start + j] - points[cluster.m_start + i]);
  2288. double mag2 = error.Dot(error);
  2289. if (mag2 < double(1.0e-6))
  2290. {
  2291. points[cluster.m_start + j] = points[cluster.m_start + i];
  2292. count--;
  2293. break;
  2294. }
  2295. }
  2296. }
  2297. assert(baseCount <= cluster.m_start);
  2298. for (int i = 0; i < count; ++i)
  2299. {
  2300. points[baseCount] = points[cluster.m_start + i];
  2301. baseCount++;
  2302. }
  2303. }
  2304. else
  2305. {
  2306. const int firstSortAxis = variance2.LongestAxis();
  2307. double axisVal = origin[firstSortAxis];
  2308. int i0 = 0;
  2309. int i1 = cluster.m_count - 1;
  2310. const int start = cluster.m_start;
  2311. while (i0 < i1)
  2312. {
  2313. while ( (points[start + i0][firstSortAxis] <= axisVal)
  2314. && (i0 < i1))
  2315. {
  2316. ++i0;
  2317. };
  2318. while ( (points[start + i1][firstSortAxis] > axisVal)
  2319. && (i0 < i1))
  2320. {
  2321. --i1;
  2322. }
  2323. assert(i0 <= i1);
  2324. if (i0 < i1)
  2325. {
  2326. std::swap(points[start + i0],
  2327. points[start + i1]);
  2328. ++i0;
  2329. --i1;
  2330. }
  2331. }
  2332. while ( (points[start + i0][firstSortAxis] <= axisVal)
  2333. && (i0 < cluster.m_count))
  2334. {
  2335. ++i0;
  2336. };
  2337. #ifdef _DEBUG
  2338. for (int i = 0; i < i0; ++i)
  2339. {
  2340. assert(points[start + i][firstSortAxis] <= axisVal);
  2341. }
  2342. for (int i = i0; i < cluster.m_count; ++i)
  2343. {
  2344. assert(points[start + i][firstSortAxis] > axisVal);
  2345. }
  2346. #endif
  2347. VHACD::Vect3 xc(0);
  2348. VHACD::Vect3 x2c(0);
  2349. for (int i = 0; i < i0; ++i)
  2350. {
  2351. const VHACD::Vect3& x = points[start + i];
  2352. xc += x;
  2353. x2c += x.CWiseMul(x);
  2354. }
  2355. dCluster cluster_i1(cluster);
  2356. cluster_i1.m_start = start + i0;
  2357. cluster_i1.m_count = cluster.m_count - i0;
  2358. cluster_i1.m_sum -= xc;
  2359. cluster_i1.m_sum2 -= x2c;
  2360. spliteStack[stack] = cluster_i1;
  2361. assert(cluster_i1.m_count > 0);
  2362. stack++;
  2363. dCluster cluster_i0(cluster);
  2364. cluster_i0.m_start = start;
  2365. cluster_i0.m_count = i0;
  2366. cluster_i0.m_sum = xc;
  2367. cluster_i0.m_sum2 = x2c;
  2368. assert(cluster_i0.m_count > 0);
  2369. spliteStack[stack] = cluster_i0;
  2370. stack++;
  2371. }
  2372. }
  2373. }
  2374. points.resize(baseCount);
  2375. if (baseCount < 4)
  2376. {
  2377. return nullptr;
  2378. }
  2379. VHACD::Vect3 sum(0);
  2380. VHACD::Vect3 sum2(0);
  2381. VHACD::Vect3 minP(double( 1.0e15));
  2382. VHACD::Vect3 maxP(double(-1.0e15));
  2383. class dTreeBox
  2384. {
  2385. public:
  2386. VHACD::Vect3 m_min;
  2387. VHACD::Vect3 m_max;
  2388. VHACD::Vect3 m_sum;
  2389. VHACD::Vect3 m_sum2;
  2390. ConvexHullAABBTreeNode* m_parent;
  2391. ConvexHullAABBTreeNode** m_child;
  2392. int m_start;
  2393. int m_count;
  2394. };
  2395. for (int i = 0; i < baseCount; ++i)
  2396. {
  2397. const VHACD::Vect3& p = points[i];
  2398. sum += p;
  2399. sum2 += p.CWiseMul(p);
  2400. minP = minP.CWiseMin(p);
  2401. maxP = maxP.CWiseMax(p);
  2402. }
  2403. dTreeBox treeBoxStack[128];
  2404. treeBoxStack[0].m_start = 0;
  2405. treeBoxStack[0].m_count = baseCount;
  2406. treeBoxStack[0].m_sum = sum;
  2407. treeBoxStack[0].m_sum2 = sum2;
  2408. treeBoxStack[0].m_min = minP;
  2409. treeBoxStack[0].m_max = maxP;
  2410. treeBoxStack[0].m_child = nullptr;
  2411. treeBoxStack[0].m_parent = nullptr;
  2412. int stack = 1;
  2413. ConvexHullAABBTreeNode* root = nullptr;
  2414. while (stack)
  2415. {
  2416. stack--;
  2417. dTreeBox box(treeBoxStack[stack]);
  2418. if (box.m_count <= VHACD_CONVEXHULL_3D_VERTEX_CLUSTER_SIZE)
  2419. {
  2420. assert(memoryPool.size() != memoryPool.capacity()
  2421. && "memoryPool is going to be reallocated, pointers will be invalid");
  2422. memoryPool.emplace_back();
  2423. ConvexHullAABBTreeNode& clump = memoryPool.back();
  2424. clump.m_count = box.m_count;
  2425. for (int i = 0; i < box.m_count; ++i)
  2426. {
  2427. clump.m_indices[i] = i + box.m_start;
  2428. }
  2429. clump.m_box[0] = box.m_min;
  2430. clump.m_box[1] = box.m_max;
  2431. if (box.m_child)
  2432. {
  2433. *box.m_child = &clump;
  2434. }
  2435. if (!root)
  2436. {
  2437. root = &clump;
  2438. }
  2439. }
  2440. else
  2441. {
  2442. const VHACD::Vect3 origin(box.m_sum * (double(1.0) / box.m_count));
  2443. const VHACD::Vect3 variance2(box.m_sum2 * (double(1.0) / box.m_count) - origin.CWiseMul(origin));
  2444. int firstSortAxis = 0;
  2445. if ((variance2.GetY() >= variance2.GetX()) && (variance2.GetY() >= variance2.GetZ()))
  2446. {
  2447. firstSortAxis = 1;
  2448. }
  2449. else if ((variance2.GetZ() >= variance2.GetX()) && (variance2.GetZ() >= variance2.GetY()))
  2450. {
  2451. firstSortAxis = 2;
  2452. }
  2453. double axisVal = origin[firstSortAxis];
  2454. int i0 = 0;
  2455. int i1 = box.m_count - 1;
  2456. const int start = box.m_start;
  2457. while (i0 < i1)
  2458. {
  2459. while ((points[start + i0][firstSortAxis] <= axisVal) && (i0 < i1))
  2460. {
  2461. ++i0;
  2462. };
  2463. while ((points[start + i1][firstSortAxis] > axisVal) && (i0 < i1))
  2464. {
  2465. --i1;
  2466. }
  2467. assert(i0 <= i1);
  2468. if (i0 < i1)
  2469. {
  2470. std::swap(points[start + i0],
  2471. points[start + i1]);
  2472. ++i0;
  2473. --i1;
  2474. }
  2475. }
  2476. while ((points[start + i0][firstSortAxis] <= axisVal) && (i0 < box.m_count))
  2477. {
  2478. ++i0;
  2479. };
  2480. #ifdef _DEBUG
  2481. for (int i = 0; i < i0; ++i)
  2482. {
  2483. assert(points[start + i][firstSortAxis] <= axisVal);
  2484. }
  2485. for (int i = i0; i < box.m_count; ++i)
  2486. {
  2487. assert(points[start + i][firstSortAxis] > axisVal);
  2488. }
  2489. #endif
  2490. assert(memoryPool.size() != memoryPool.capacity()
  2491. && "memoryPool is going to be reallocated, pointers will be invalid");
  2492. memoryPool.emplace_back();
  2493. ConvexHullAABBTreeNode& node = memoryPool.back();
  2494. node.m_box[0] = box.m_min;
  2495. node.m_box[1] = box.m_max;
  2496. if (box.m_child)
  2497. {
  2498. *box.m_child = &node;
  2499. }
  2500. if (!root)
  2501. {
  2502. root = &node;
  2503. }
  2504. {
  2505. VHACD::Vect3 xc(0);
  2506. VHACD::Vect3 x2c(0);
  2507. VHACD::Vect3 p0(double( 1.0e15));
  2508. VHACD::Vect3 p1(double(-1.0e15));
  2509. for (int i = i0; i < box.m_count; ++i)
  2510. {
  2511. const VHACD::Vect3& p = points[start + i];
  2512. xc += p;
  2513. x2c += p.CWiseMul(p);
  2514. p0 = p0.CWiseMin(p);
  2515. p1 = p1.CWiseMax(p);
  2516. }
  2517. dTreeBox cluster_i1(box);
  2518. cluster_i1.m_start = start + i0;
  2519. cluster_i1.m_count = box.m_count - i0;
  2520. cluster_i1.m_sum = xc;
  2521. cluster_i1.m_sum2 = x2c;
  2522. cluster_i1.m_min = p0;
  2523. cluster_i1.m_max = p1;
  2524. cluster_i1.m_parent = &node;
  2525. cluster_i1.m_child = &node.m_right;
  2526. treeBoxStack[stack] = cluster_i1;
  2527. assert(cluster_i1.m_count > 0);
  2528. stack++;
  2529. }
  2530. {
  2531. VHACD::Vect3 xc(0);
  2532. VHACD::Vect3 x2c(0);
  2533. VHACD::Vect3 p0(double( 1.0e15));
  2534. VHACD::Vect3 p1(double(-1.0e15));
  2535. for (int i = 0; i < i0; ++i)
  2536. {
  2537. const VHACD::Vect3& p = points[start + i];
  2538. xc += p;
  2539. x2c += p.CWiseMul(p);
  2540. p0 = p0.CWiseMin(p);
  2541. p1 = p1.CWiseMax(p);
  2542. }
  2543. dTreeBox cluster_i0(box);
  2544. cluster_i0.m_start = start;
  2545. cluster_i0.m_count = i0;
  2546. cluster_i0.m_min = p0;
  2547. cluster_i0.m_max = p1;
  2548. cluster_i0.m_sum = xc;
  2549. cluster_i0.m_sum2 = x2c;
  2550. cluster_i0.m_parent = &node;
  2551. cluster_i0.m_child = &node.m_left;
  2552. assert(cluster_i0.m_count > 0);
  2553. treeBoxStack[stack] = cluster_i0;
  2554. stack++;
  2555. }
  2556. }
  2557. }
  2558. return root;
  2559. }
  2560. int ConvexHull::SupportVertex(ConvexHullAABBTreeNode** const treePointer,
  2561. const std::vector<ConvexHullVertex>& points,
  2562. const VHACD::Vect3& dirPlane,
  2563. const bool removeEntry) const
  2564. {
  2565. #define VHACD_STACK_DEPTH_3D 64
  2566. double aabbProjection[VHACD_STACK_DEPTH_3D];
  2567. ConvexHullAABBTreeNode* stackPool[VHACD_STACK_DEPTH_3D];
  2568. VHACD::Vect3 dir(dirPlane);
  2569. int index = -1;
  2570. int stack = 1;
  2571. stackPool[0] = *treePointer;
  2572. aabbProjection[0] = double(1.0e20);
  2573. double maxProj = double(-1.0e20);
  2574. int ix = (dir[0] > double(0.0)) ? 1 : 0;
  2575. int iy = (dir[1] > double(0.0)) ? 1 : 0;
  2576. int iz = (dir[2] > double(0.0)) ? 1 : 0;
  2577. while (stack)
  2578. {
  2579. stack--;
  2580. double boxSupportValue = aabbProjection[stack];
  2581. if (boxSupportValue > maxProj)
  2582. {
  2583. ConvexHullAABBTreeNode* me = stackPool[stack];
  2584. /*
  2585. * If the node is not a leaf node...
  2586. */
  2587. if (me->m_left && me->m_right)
  2588. {
  2589. const VHACD::Vect3 leftSupportPoint(me->m_left->m_box[ix].GetX(),
  2590. me->m_left->m_box[iy].GetY(),
  2591. me->m_left->m_box[iz].GetZ());
  2592. double leftSupportDist = leftSupportPoint.Dot(dir);
  2593. const VHACD::Vect3 rightSupportPoint(me->m_right->m_box[ix].GetX(),
  2594. me->m_right->m_box[iy].GetY(),
  2595. me->m_right->m_box[iz].GetZ());
  2596. double rightSupportDist = rightSupportPoint.Dot(dir);
  2597. /*
  2598. * ...push the shorter side first
  2599. * So we can explore the tree in the larger side first
  2600. */
  2601. if (rightSupportDist >= leftSupportDist)
  2602. {
  2603. aabbProjection[stack] = leftSupportDist;
  2604. stackPool[stack] = me->m_left;
  2605. stack++;
  2606. assert(stack < VHACD_STACK_DEPTH_3D);
  2607. aabbProjection[stack] = rightSupportDist;
  2608. stackPool[stack] = me->m_right;
  2609. stack++;
  2610. assert(stack < VHACD_STACK_DEPTH_3D);
  2611. }
  2612. else
  2613. {
  2614. aabbProjection[stack] = rightSupportDist;
  2615. stackPool[stack] = me->m_right;
  2616. stack++;
  2617. assert(stack < VHACD_STACK_DEPTH_3D);
  2618. aabbProjection[stack] = leftSupportDist;
  2619. stackPool[stack] = me->m_left;
  2620. stack++;
  2621. assert(stack < VHACD_STACK_DEPTH_3D);
  2622. }
  2623. }
  2624. /*
  2625. * If it is a node...
  2626. */
  2627. else
  2628. {
  2629. ConvexHullAABBTreeNode* cluster = me;
  2630. for (size_t i = 0; i < cluster->m_count; ++i)
  2631. {
  2632. const ConvexHullVertex& p = points[cluster->m_indices[i]];
  2633. assert(p.GetX() >= cluster->m_box[0].GetX());
  2634. assert(p.GetX() <= cluster->m_box[1].GetX());
  2635. assert(p.GetY() >= cluster->m_box[0].GetY());
  2636. assert(p.GetY() <= cluster->m_box[1].GetY());
  2637. assert(p.GetZ() >= cluster->m_box[0].GetZ());
  2638. assert(p.GetZ() <= cluster->m_box[1].GetZ());
  2639. if (!p.m_mark)
  2640. {
  2641. //assert(p.m_w == double(0.0f));
  2642. double dist = p.Dot(dir);
  2643. if (dist > maxProj)
  2644. {
  2645. maxProj = dist;
  2646. index = cluster->m_indices[i];
  2647. }
  2648. }
  2649. else if (removeEntry)
  2650. {
  2651. cluster->m_indices[i] = cluster->m_indices[cluster->m_count - 1];
  2652. cluster->m_count = cluster->m_count - 1;
  2653. i--;
  2654. }
  2655. }
  2656. if (cluster->m_count == 0)
  2657. {
  2658. ConvexHullAABBTreeNode* const parent = cluster->m_parent;
  2659. if (parent)
  2660. {
  2661. ConvexHullAABBTreeNode* const sibling = (parent->m_left != cluster) ? parent->m_left : parent->m_right;
  2662. assert(sibling != cluster);
  2663. ConvexHullAABBTreeNode* const grandParent = parent->m_parent;
  2664. if (grandParent)
  2665. {
  2666. sibling->m_parent = grandParent;
  2667. if (grandParent->m_right == parent)
  2668. {
  2669. grandParent->m_right = sibling;
  2670. }
  2671. else
  2672. {
  2673. grandParent->m_left = sibling;
  2674. }
  2675. }
  2676. else
  2677. {
  2678. sibling->m_parent = nullptr;
  2679. *treePointer = sibling;
  2680. }
  2681. }
  2682. }
  2683. }
  2684. }
  2685. }
  2686. assert(index != -1);
  2687. return index;
  2688. }
  2689. double ConvexHull::TetrahedrumVolume(const VHACD::Vect3& p0,
  2690. const VHACD::Vect3& p1,
  2691. const VHACD::Vect3& p2,
  2692. const VHACD::Vect3& p3) const
  2693. {
  2694. const VHACD::Vect3 p1p0(p1 - p0);
  2695. const VHACD::Vect3 p2p0(p2 - p0);
  2696. const VHACD::Vect3 p3p0(p3 - p0);
  2697. return p3p0.Dot(p1p0.Cross(p2p0));
  2698. }
  2699. int ConvexHull::InitVertexArray(std::vector<ConvexHullVertex>& points,
  2700. NodeBundle<ConvexHullAABBTreeNode>& memoryPool)
  2701. // std::vector<ConvexHullAABBTreeNode>& memoryPool)
  2702. {
  2703. #if 1
  2704. ConvexHullAABBTreeNode* tree = BuildTreeOld(points,
  2705. memoryPool);
  2706. #else
  2707. ConvexHullAABBTreeNode* tree = BuildTreeNew(points, (char**)&memoryPool, maxMemSize);
  2708. #endif
  2709. int count = int(points.size());
  2710. if (count < 4)
  2711. {
  2712. m_points.resize(0);
  2713. return 0;
  2714. }
  2715. m_points.resize(count);
  2716. m_aabbP0 = tree->m_box[0];
  2717. m_aabbP1 = tree->m_box[1];
  2718. VHACD::Vect3 boxSize(tree->m_box[1] - tree->m_box[0]);
  2719. m_diag = boxSize.GetNorm();
  2720. const ndNormalMap& normalMap = ndNormalMap::GetNormalMap();
  2721. int index0 = SupportVertex(&tree,
  2722. points,
  2723. normalMap.m_normal[0]);
  2724. m_points[0] = points[index0];
  2725. points[index0].m_mark = 1;
  2726. bool validTetrahedrum = false;
  2727. VHACD::Vect3 e1(double(0.0));
  2728. for (int i = 1; i < normalMap.m_count; ++i)
  2729. {
  2730. int index = SupportVertex(&tree,
  2731. points,
  2732. normalMap.m_normal[i]);
  2733. assert(index >= 0);
  2734. e1 = points[index] - m_points[0];
  2735. double error2 = e1.GetNormSquared();
  2736. if (error2 > (double(1.0e-4) * m_diag * m_diag))
  2737. {
  2738. m_points[1] = points[index];
  2739. points[index].m_mark = 1;
  2740. validTetrahedrum = true;
  2741. break;
  2742. }
  2743. }
  2744. if (!validTetrahedrum)
  2745. {
  2746. m_points.resize(0);
  2747. assert(0);
  2748. return count;
  2749. }
  2750. validTetrahedrum = false;
  2751. VHACD::Vect3 e2(double(0.0));
  2752. VHACD::Vect3 normal(double(0.0));
  2753. for (int i = 2; i < normalMap.m_count; ++i)
  2754. {
  2755. int index = SupportVertex(&tree,
  2756. points,
  2757. normalMap.m_normal[i]);
  2758. assert(index >= 0);
  2759. e2 = points[index] - m_points[0];
  2760. normal = e1.Cross(e2);
  2761. double error2 = normal.GetNorm();
  2762. if (error2 > (double(1.0e-4) * m_diag * m_diag))
  2763. {
  2764. m_points[2] = points[index];
  2765. points[index].m_mark = 1;
  2766. validTetrahedrum = true;
  2767. break;
  2768. }
  2769. }
  2770. if (!validTetrahedrum)
  2771. {
  2772. m_points.resize(0);
  2773. assert(0);
  2774. return count;
  2775. }
  2776. // find the largest possible tetrahedron
  2777. validTetrahedrum = false;
  2778. VHACD::Vect3 e3(double(0.0));
  2779. index0 = SupportVertex(&tree,
  2780. points,
  2781. normal);
  2782. e3 = points[index0] - m_points[0];
  2783. double err2 = normal.Dot(e3);
  2784. if (fabs(err2) > (double(1.0e-6) * m_diag * m_diag))
  2785. {
  2786. // we found a valid tetrahedral, about and start build the hull by adding the rest of the points
  2787. m_points[3] = points[index0];
  2788. points[index0].m_mark = 1;
  2789. validTetrahedrum = true;
  2790. }
  2791. if (!validTetrahedrum)
  2792. {
  2793. VHACD::Vect3 n(-normal);
  2794. int index = SupportVertex(&tree,
  2795. points,
  2796. n);
  2797. e3 = points[index] - m_points[0];
  2798. double error2 = normal.Dot(e3);
  2799. if (fabs(error2) > (double(1.0e-6) * m_diag * m_diag))
  2800. {
  2801. // we found a valid tetrahedral, about and start build the hull by adding the rest of the points
  2802. m_points[3] = points[index];
  2803. points[index].m_mark = 1;
  2804. validTetrahedrum = true;
  2805. }
  2806. }
  2807. if (!validTetrahedrum)
  2808. {
  2809. for (int i = 3; i < normalMap.m_count; ++i)
  2810. {
  2811. int index = SupportVertex(&tree,
  2812. points,
  2813. normalMap.m_normal[i]);
  2814. assert(index >= 0);
  2815. //make sure the volume of the fist tetrahedral is no negative
  2816. e3 = points[index] - m_points[0];
  2817. double error2 = normal.Dot(e3);
  2818. if (fabs(error2) > (double(1.0e-6) * m_diag * m_diag))
  2819. {
  2820. // we found a valid tetrahedral, about and start build the hull by adding the rest of the points
  2821. m_points[3] = points[index];
  2822. points[index].m_mark = 1;
  2823. validTetrahedrum = true;
  2824. break;
  2825. }
  2826. }
  2827. }
  2828. if (!validTetrahedrum)
  2829. {
  2830. // the points do not form a convex hull
  2831. m_points.resize(0);
  2832. return count;
  2833. }
  2834. m_points.resize(4);
  2835. double volume = TetrahedrumVolume(m_points[0],
  2836. m_points[1],
  2837. m_points[2],
  2838. m_points[3]);
  2839. if (volume > double(0.0))
  2840. {
  2841. std::swap(m_points[2],
  2842. m_points[3]);
  2843. }
  2844. assert(TetrahedrumVolume(m_points[0], m_points[1], m_points[2], m_points[3]) < double(0.0));
  2845. return count;
  2846. }
  2847. std::list<ConvexHullFace>::iterator ConvexHull::AddFace(int i0,
  2848. int i1,
  2849. int i2)
  2850. {
  2851. ConvexHullFace face;
  2852. face.m_index[0] = i0;
  2853. face.m_index[1] = i1;
  2854. face.m_index[2] = i2;
  2855. std::list<ConvexHullFace>::iterator node = m_list.emplace(m_list.end(), face);
  2856. return node;
  2857. }
  2858. void ConvexHull::CalculateConvexHull3D(ConvexHullAABBTreeNode* vertexTree,
  2859. std::vector<ConvexHullVertex>& points,
  2860. int count,
  2861. double distTol,
  2862. int maxVertexCount)
  2863. {
  2864. distTol = fabs(distTol) * m_diag;
  2865. std::list<ConvexHullFace>::iterator f0Node = AddFace(0, 1, 2);
  2866. std::list<ConvexHullFace>::iterator f1Node = AddFace(0, 2, 3);
  2867. std::list<ConvexHullFace>::iterator f2Node = AddFace(2, 1, 3);
  2868. std::list<ConvexHullFace>::iterator f3Node = AddFace(1, 0, 3);
  2869. ConvexHullFace& f0 = *f0Node;
  2870. ConvexHullFace& f1 = *f1Node;
  2871. ConvexHullFace& f2 = *f2Node;
  2872. ConvexHullFace& f3 = *f3Node;
  2873. f0.m_twin[0] = f3Node;
  2874. f0.m_twin[1] = f2Node;
  2875. f0.m_twin[2] = f1Node;
  2876. f1.m_twin[0] = f0Node;
  2877. f1.m_twin[1] = f2Node;
  2878. f1.m_twin[2] = f3Node;
  2879. f2.m_twin[0] = f0Node;
  2880. f2.m_twin[1] = f3Node;
  2881. f2.m_twin[2] = f1Node;
  2882. f3.m_twin[0] = f0Node;
  2883. f3.m_twin[1] = f1Node;
  2884. f3.m_twin[2] = f2Node;
  2885. std::list<std::list<ConvexHullFace>::iterator> boundaryFaces;
  2886. boundaryFaces.push_back(f0Node);
  2887. boundaryFaces.push_back(f1Node);
  2888. boundaryFaces.push_back(f2Node);
  2889. boundaryFaces.push_back(f3Node);
  2890. m_points.resize(count);
  2891. count -= 4;
  2892. maxVertexCount -= 4;
  2893. int currentIndex = 4;
  2894. /*
  2895. * Some are iterators into boundaryFaces, others into m_list
  2896. */
  2897. std::vector<std::list<ConvexHullFace>::iterator> stack;
  2898. std::vector<std::list<ConvexHullFace>::iterator> coneList;
  2899. std::vector<std::list<ConvexHullFace>::iterator> deleteList;
  2900. stack.reserve(1024 + count);
  2901. coneList.reserve(1024 + count);
  2902. deleteList.reserve(1024 + count);
  2903. while (boundaryFaces.size() && count && (maxVertexCount > 0))
  2904. {
  2905. // my definition of the optimal convex hull of a given vertex count,
  2906. // is the convex hull formed by a subset of the input vertex that minimizes the volume difference
  2907. // between the perfect hull formed from all input vertex and the hull of the sub set of vertex.
  2908. // When using a priority heap this algorithms will generate the an optimal of a fix vertex count.
  2909. // Since all Newton's tools do not have a limit on the point count of a convex hull, I can use either a stack or a queue.
  2910. // a stack maximize construction speed, a Queue tend to maximize the volume of the generated Hull approaching a perfect Hull.
  2911. // For now we use a queue.
  2912. // For general hulls it does not make a difference if we use a stack, queue, or a priority heap.
  2913. // perfect optimal hull only apply for when build hull of a limited vertex count.
  2914. //
  2915. // Also when building Hulls of a limited vertex count, this function runs in constant time.
  2916. // yes that is correct, it does not makes a difference if you build a N point hull from 100 vertex
  2917. // or from 100000 vertex input array.
  2918. // using a queue (some what slower by better hull when reduced vertex count is desired)
  2919. bool isvalid;
  2920. std::list<ConvexHullFace>::iterator faceNode = boundaryFaces.back();
  2921. ConvexHullFace& face = *faceNode;
  2922. HullPlane planeEquation(face.GetPlaneEquation(m_points, isvalid));
  2923. int index = 0;
  2924. double dist = 0;
  2925. VHACD::Vect3 p;
  2926. if (isvalid)
  2927. {
  2928. index = SupportVertex(&vertexTree,
  2929. points,
  2930. planeEquation);
  2931. p = points[index];
  2932. dist = planeEquation.Evalue(p);
  2933. }
  2934. if ( isvalid
  2935. && (dist >= distTol)
  2936. && (face.Evalue(m_points, p) < double(0.0)))
  2937. {
  2938. stack.push_back(faceNode);
  2939. deleteList.clear();
  2940. while (stack.size())
  2941. {
  2942. std::list<ConvexHullFace>::iterator node1 = stack.back();
  2943. ConvexHullFace& face1 = *node1;
  2944. stack.pop_back();
  2945. if (!face1.m_mark && (face1.Evalue(m_points, p) < double(0.0)))
  2946. {
  2947. #ifdef _DEBUG
  2948. for (const auto node : deleteList)
  2949. {
  2950. assert(node != node1);
  2951. }
  2952. #endif
  2953. deleteList.push_back(node1);
  2954. face1.m_mark = 1;
  2955. for (std::list<ConvexHullFace>::iterator& twinNode : face1.m_twin)
  2956. {
  2957. ConvexHullFace& twinFace = *twinNode;
  2958. if (!twinFace.m_mark)
  2959. {
  2960. stack.push_back(twinNode);
  2961. }
  2962. }
  2963. }
  2964. }
  2965. m_points[currentIndex] = points[index];
  2966. points[index].m_mark = 1;
  2967. coneList.clear();
  2968. for (std::list<ConvexHullFace>::iterator node1 : deleteList)
  2969. {
  2970. ConvexHullFace& face1 = *node1;
  2971. assert(face1.m_mark == 1);
  2972. for (std::size_t j0 = 0; j0 < face1.m_twin.size(); ++j0)
  2973. {
  2974. std::list<ConvexHullFace>::iterator twinNode = face1.m_twin[j0];
  2975. ConvexHullFace& twinFace = *twinNode;
  2976. if (!twinFace.m_mark)
  2977. {
  2978. std::size_t j1 = (j0 == 2) ? 0 : j0 + 1;
  2979. std::list<ConvexHullFace>::iterator newNode = AddFace(currentIndex,
  2980. face1.m_index[j0],
  2981. face1.m_index[j1]);
  2982. boundaryFaces.push_front(newNode);
  2983. ConvexHullFace& newFace = *newNode;
  2984. newFace.m_twin[1] = twinNode;
  2985. for (std::size_t k = 0; k < twinFace.m_twin.size(); ++k)
  2986. {
  2987. if (twinFace.m_twin[k] == node1)
  2988. {
  2989. twinFace.m_twin[k] = newNode;
  2990. }
  2991. }
  2992. coneList.push_back(newNode);
  2993. }
  2994. }
  2995. }
  2996. for (std::size_t i = 0; i < coneList.size() - 1; ++i)
  2997. {
  2998. std::list<ConvexHullFace>::iterator nodeA = coneList[i];
  2999. ConvexHullFace& faceA = *nodeA;
  3000. assert(faceA.m_mark == 0);
  3001. for (std::size_t j = i + 1; j < coneList.size(); j++)
  3002. {
  3003. std::list<ConvexHullFace>::iterator nodeB = coneList[j];
  3004. ConvexHullFace& faceB = *nodeB;
  3005. assert(faceB.m_mark == 0);
  3006. if (faceA.m_index[2] == faceB.m_index[1])
  3007. {
  3008. faceA.m_twin[2] = nodeB;
  3009. faceB.m_twin[0] = nodeA;
  3010. break;
  3011. }
  3012. }
  3013. for (std::size_t j = i + 1; j < coneList.size(); j++)
  3014. {
  3015. std::list<ConvexHullFace>::iterator nodeB = coneList[j];
  3016. ConvexHullFace& faceB = *nodeB;
  3017. assert(faceB.m_mark == 0);
  3018. if (faceA.m_index[1] == faceB.m_index[2])
  3019. {
  3020. faceA.m_twin[0] = nodeB;
  3021. faceB.m_twin[2] = nodeA;
  3022. break;
  3023. }
  3024. }
  3025. }
  3026. for (std::list<ConvexHullFace>::iterator node : deleteList)
  3027. {
  3028. auto it = std::find(boundaryFaces.begin(),
  3029. boundaryFaces.end(),
  3030. node);
  3031. if (it != boundaryFaces.end())
  3032. {
  3033. boundaryFaces.erase(it);
  3034. }
  3035. m_list.erase(node);
  3036. }
  3037. maxVertexCount--;
  3038. currentIndex++;
  3039. count--;
  3040. }
  3041. else
  3042. {
  3043. auto it = std::find(boundaryFaces.begin(),
  3044. boundaryFaces.end(),
  3045. faceNode);
  3046. if (it != boundaryFaces.end())
  3047. {
  3048. boundaryFaces.erase(it);
  3049. }
  3050. }
  3051. }
  3052. m_points.resize(currentIndex);
  3053. }
  3054. //***********************************************************************************************
  3055. // End of ConvexHull generation code by Julio Jerez <[email protected]>
  3056. //***********************************************************************************************
  3057. class KdTreeNode;
  3058. enum Axes
  3059. {
  3060. X_AXIS = 0,
  3061. Y_AXIS = 1,
  3062. Z_AXIS = 2
  3063. };
  3064. class KdTreeFindNode
  3065. {
  3066. public:
  3067. KdTreeFindNode() = default;
  3068. KdTreeNode* m_node{ nullptr };
  3069. double m_distance{ 0.0 };
  3070. };
  3071. class KdTree
  3072. {
  3073. public:
  3074. KdTree() = default;
  3075. const VHACD::Vertex& GetPosition(uint32_t index) const;
  3076. uint32_t Search(const VHACD::Vect3& pos,
  3077. double radius,
  3078. uint32_t maxObjects,
  3079. KdTreeFindNode* found) const;
  3080. uint32_t Add(const VHACD::Vertex& v);
  3081. KdTreeNode& GetNewNode(uint32_t index);
  3082. uint32_t GetNearest(const VHACD::Vect3& pos,
  3083. double radius,
  3084. bool& _found) const; // returns the nearest possible neighbor's index.
  3085. const std::vector<VHACD::Vertex>& GetVertices() const;
  3086. std::vector<VHACD::Vertex>&& TakeVertices();
  3087. uint32_t GetVCount() const;
  3088. private:
  3089. KdTreeNode* m_root{ nullptr };
  3090. NodeBundle<KdTreeNode> m_bundle;
  3091. std::vector<VHACD::Vertex> m_vertices;
  3092. };
  3093. class KdTreeNode
  3094. {
  3095. public:
  3096. KdTreeNode() = default;
  3097. KdTreeNode(uint32_t index);
  3098. void Add(KdTreeNode& node,
  3099. Axes dim,
  3100. const KdTree& iface);
  3101. uint32_t GetIndex() const;
  3102. void Search(Axes axis,
  3103. const VHACD::Vect3& pos,
  3104. double radius,
  3105. uint32_t& count,
  3106. uint32_t maxObjects,
  3107. KdTreeFindNode* found,
  3108. const KdTree& iface);
  3109. private:
  3110. uint32_t m_index = 0;
  3111. KdTreeNode* m_left = nullptr;
  3112. KdTreeNode* m_right = nullptr;
  3113. };
  3114. const VHACD::Vertex& KdTree::GetPosition(uint32_t index) const
  3115. {
  3116. assert(index < m_vertices.size());
  3117. return m_vertices[index];
  3118. }
  3119. uint32_t KdTree::Search(const VHACD::Vect3& pos,
  3120. double radius,
  3121. uint32_t maxObjects,
  3122. KdTreeFindNode* found) const
  3123. {
  3124. if (!m_root)
  3125. return 0;
  3126. uint32_t count = 0;
  3127. m_root->Search(X_AXIS, pos, radius, count, maxObjects, found, *this);
  3128. return count;
  3129. }
  3130. uint32_t KdTree::Add(const VHACD::Vertex& v)
  3131. {
  3132. uint32_t ret = uint32_t(m_vertices.size());
  3133. m_vertices.emplace_back(v);
  3134. KdTreeNode& node = GetNewNode(ret);
  3135. if (m_root)
  3136. {
  3137. m_root->Add(node,
  3138. X_AXIS,
  3139. *this);
  3140. }
  3141. else
  3142. {
  3143. m_root = &node;
  3144. }
  3145. return ret;
  3146. }
  3147. KdTreeNode& KdTree::GetNewNode(uint32_t index)
  3148. {
  3149. KdTreeNode& node = m_bundle.GetNextNode();
  3150. node = KdTreeNode(index);
  3151. return node;
  3152. }
  3153. uint32_t KdTree::GetNearest(const VHACD::Vect3& pos,
  3154. double radius,
  3155. bool& _found) const // returns the nearest possible neighbor's index.
  3156. {
  3157. uint32_t ret = 0;
  3158. _found = false;
  3159. KdTreeFindNode found;
  3160. uint32_t count = Search(pos, radius, 1, &found);
  3161. if (count)
  3162. {
  3163. KdTreeNode* node = found.m_node;
  3164. ret = node->GetIndex();
  3165. _found = true;
  3166. }
  3167. return ret;
  3168. }
  3169. const std::vector<VHACD::Vertex>& KdTree::GetVertices() const
  3170. {
  3171. return m_vertices;
  3172. }
  3173. std::vector<VHACD::Vertex>&& KdTree::TakeVertices()
  3174. {
  3175. return std::move(m_vertices);
  3176. }
  3177. uint32_t KdTree::GetVCount() const
  3178. {
  3179. return uint32_t(m_vertices.size());
  3180. }
  3181. KdTreeNode::KdTreeNode(uint32_t index)
  3182. : m_index(index)
  3183. {
  3184. }
  3185. void KdTreeNode::Add(KdTreeNode& node,
  3186. Axes dim,
  3187. const KdTree& tree)
  3188. {
  3189. Axes axis = X_AXIS;
  3190. uint32_t idx = 0;
  3191. switch (dim)
  3192. {
  3193. case X_AXIS:
  3194. idx = 0;
  3195. axis = Y_AXIS;
  3196. break;
  3197. case Y_AXIS:
  3198. idx = 1;
  3199. axis = Z_AXIS;
  3200. break;
  3201. case Z_AXIS:
  3202. idx = 2;
  3203. axis = X_AXIS;
  3204. break;
  3205. }
  3206. const VHACD::Vertex& nodePosition = tree.GetPosition(node.m_index);
  3207. const VHACD::Vertex& position = tree.GetPosition(m_index);
  3208. if (nodePosition[idx] <= position[idx])
  3209. {
  3210. if (m_left)
  3211. m_left->Add(node, axis, tree);
  3212. else
  3213. m_left = &node;
  3214. }
  3215. else
  3216. {
  3217. if (m_right)
  3218. m_right->Add(node, axis, tree);
  3219. else
  3220. m_right = &node;
  3221. }
  3222. }
  3223. uint32_t KdTreeNode::GetIndex() const
  3224. {
  3225. return m_index;
  3226. }
  3227. void KdTreeNode::Search(Axes axis,
  3228. const VHACD::Vect3& pos,
  3229. double radius,
  3230. uint32_t& count,
  3231. uint32_t maxObjects,
  3232. KdTreeFindNode* found,
  3233. const KdTree& iface)
  3234. {
  3235. const VHACD::Vect3 position = iface.GetPosition(m_index);
  3236. const VHACD::Vect3 d = pos - position;
  3237. KdTreeNode* search1 = 0;
  3238. KdTreeNode* search2 = 0;
  3239. uint32_t idx = 0;
  3240. switch (axis)
  3241. {
  3242. case X_AXIS:
  3243. idx = 0;
  3244. axis = Y_AXIS;
  3245. break;
  3246. case Y_AXIS:
  3247. idx = 1;
  3248. axis = Z_AXIS;
  3249. break;
  3250. case Z_AXIS:
  3251. idx = 2;
  3252. axis = X_AXIS;
  3253. break;
  3254. }
  3255. if (d[idx] <= 0) // JWR if we are to the left
  3256. {
  3257. search1 = m_left; // JWR then search to the left
  3258. if (-d[idx] < radius) // JWR if distance to the right is less than our search radius, continue on the right
  3259. // as well.
  3260. search2 = m_right;
  3261. }
  3262. else
  3263. {
  3264. search1 = m_right; // JWR ok, we go down the left tree
  3265. if (d[idx] < radius) // JWR if the distance from the right is less than our search radius
  3266. search2 = m_left;
  3267. }
  3268. double r2 = radius * radius;
  3269. double m = d.GetNormSquared();
  3270. if (m < r2)
  3271. {
  3272. switch (count)
  3273. {
  3274. case 0:
  3275. {
  3276. found[count].m_node = this;
  3277. found[count].m_distance = m;
  3278. break;
  3279. }
  3280. case 1:
  3281. {
  3282. if (m < found[0].m_distance)
  3283. {
  3284. if (maxObjects == 1)
  3285. {
  3286. found[0].m_node = this;
  3287. found[0].m_distance = m;
  3288. }
  3289. else
  3290. {
  3291. found[1] = found[0];
  3292. found[0].m_node = this;
  3293. found[0].m_distance = m;
  3294. }
  3295. }
  3296. else if (maxObjects > 1)
  3297. {
  3298. found[1].m_node = this;
  3299. found[1].m_distance = m;
  3300. }
  3301. break;
  3302. }
  3303. default:
  3304. {
  3305. bool inserted = false;
  3306. for (uint32_t i = 0; i < count; i++)
  3307. {
  3308. if (m < found[i].m_distance) // if this one is closer than a pre-existing one...
  3309. {
  3310. // insertion sort...
  3311. uint32_t scan = count;
  3312. if (scan >= maxObjects)
  3313. scan = maxObjects - 1;
  3314. for (uint32_t j = scan; j > i; j--)
  3315. {
  3316. found[j] = found[j - 1];
  3317. }
  3318. found[i].m_node = this;
  3319. found[i].m_distance = m;
  3320. inserted = true;
  3321. break;
  3322. }
  3323. }
  3324. if (!inserted && count < maxObjects)
  3325. {
  3326. found[count].m_node = this;
  3327. found[count].m_distance = m;
  3328. }
  3329. }
  3330. break;
  3331. }
  3332. count++;
  3333. if (count > maxObjects)
  3334. {
  3335. count = maxObjects;
  3336. }
  3337. }
  3338. if (search1)
  3339. search1->Search(axis, pos, radius, count, maxObjects, found, iface);
  3340. if (search2)
  3341. search2->Search(axis, pos, radius, count, maxObjects, found, iface);
  3342. }
  3343. class VertexIndex
  3344. {
  3345. public:
  3346. VertexIndex(double granularity,
  3347. bool snapToGrid);
  3348. VHACD::Vect3 SnapToGrid(VHACD::Vect3 p);
  3349. uint32_t GetIndex(VHACD::Vect3 p,
  3350. bool& newPos);
  3351. const std::vector<VHACD::Vertex>& GetVertices() const;
  3352. std::vector<VHACD::Vertex>&& TakeVertices();
  3353. uint32_t GetVCount() const;
  3354. bool SaveAsObj(const char* fname,
  3355. uint32_t tcount,
  3356. uint32_t* indices)
  3357. {
  3358. bool ret = false;
  3359. FILE* fph = fopen(fname, "wb");
  3360. if (fph)
  3361. {
  3362. ret = true;
  3363. const std::vector<VHACD::Vertex>& v = GetVertices();
  3364. for (uint32_t i = 0; i < v.size(); ++i)
  3365. {
  3366. fprintf(fph, "v %0.9f %0.9f %0.9f\r\n",
  3367. v[i].mX,
  3368. v[i].mY,
  3369. v[i].mZ);
  3370. }
  3371. for (uint32_t i = 0; i < tcount; i++)
  3372. {
  3373. uint32_t i1 = *indices++;
  3374. uint32_t i2 = *indices++;
  3375. uint32_t i3 = *indices++;
  3376. fprintf(fph, "f %d %d %d\r\n",
  3377. i1 + 1,
  3378. i2 + 1,
  3379. i3 + 1);
  3380. }
  3381. fclose(fph);
  3382. }
  3383. return ret;
  3384. }
  3385. private:
  3386. bool m_snapToGrid : 1;
  3387. double m_granularity;
  3388. KdTree m_KdTree;
  3389. };
  3390. VertexIndex::VertexIndex(double granularity,
  3391. bool snapToGrid)
  3392. : m_snapToGrid(snapToGrid)
  3393. , m_granularity(granularity)
  3394. {
  3395. }
  3396. VHACD::Vect3 VertexIndex::SnapToGrid(VHACD::Vect3 p)
  3397. {
  3398. for (int i = 0; i < 3; ++i)
  3399. {
  3400. double m = fmod(p[i], m_granularity);
  3401. p[i] -= m;
  3402. }
  3403. return p;
  3404. }
  3405. uint32_t VertexIndex::GetIndex(VHACD::Vect3 p,
  3406. bool& newPos)
  3407. {
  3408. uint32_t ret;
  3409. newPos = false;
  3410. if (m_snapToGrid)
  3411. {
  3412. p = SnapToGrid(p);
  3413. }
  3414. bool found;
  3415. ret = m_KdTree.GetNearest(p, m_granularity, found);
  3416. if (!found)
  3417. {
  3418. newPos = true;
  3419. ret = m_KdTree.Add(VHACD::Vertex(p.GetX(), p.GetY(), p.GetZ()));
  3420. }
  3421. return ret;
  3422. }
  3423. const std::vector<VHACD::Vertex>& VertexIndex::GetVertices() const
  3424. {
  3425. return m_KdTree.GetVertices();
  3426. }
  3427. std::vector<VHACD::Vertex>&& VertexIndex::TakeVertices()
  3428. {
  3429. return std::move(m_KdTree.TakeVertices());
  3430. }
  3431. uint32_t VertexIndex::GetVCount() const
  3432. {
  3433. return m_KdTree.GetVCount();
  3434. }
  3435. /*
  3436. * A wrapper class for 3 10 bit integers packed into a 32 bit integer
  3437. * Layout is [PAD][X][Y][Z]
  3438. * Pad is bits 31-30, X is 29-20, Y is 19-10, and Z is 9-0
  3439. */
  3440. class Voxel
  3441. {
  3442. /*
  3443. * Specify all of them for consistency
  3444. */
  3445. static constexpr int VoxelBitsZStart = 0;
  3446. static constexpr int VoxelBitsYStart = 10;
  3447. static constexpr int VoxelBitsXStart = 20;
  3448. static constexpr int VoxelBitMask = 0x03FF; // bits 0 through 9 inclusive
  3449. public:
  3450. Voxel() = default;
  3451. Voxel(uint32_t index);
  3452. Voxel(uint32_t x,
  3453. uint32_t y,
  3454. uint32_t z);
  3455. bool operator==(const Voxel &v) const;
  3456. VHACD::Vector3<uint32_t> GetVoxel() const;
  3457. uint32_t GetX() const;
  3458. uint32_t GetY() const;
  3459. uint32_t GetZ() const;
  3460. uint32_t GetVoxelAddress() const;
  3461. private:
  3462. uint32_t m_voxel{ 0 };
  3463. };
  3464. Voxel::Voxel(uint32_t index)
  3465. : m_voxel(index)
  3466. {
  3467. }
  3468. Voxel::Voxel(uint32_t x,
  3469. uint32_t y,
  3470. uint32_t z)
  3471. : m_voxel((x << VoxelBitsXStart) | (y << VoxelBitsYStart) | (z << VoxelBitsZStart))
  3472. {
  3473. assert(x < 1024 && "Voxel constructed with X outside of range");
  3474. assert(y < 1024 && "Voxel constructed with Y outside of range");
  3475. assert(z < 1024 && "Voxel constructed with Z outside of range");
  3476. }
  3477. bool Voxel::operator==(const Voxel& v) const
  3478. {
  3479. return m_voxel == v.m_voxel;
  3480. }
  3481. VHACD::Vector3<uint32_t> Voxel::GetVoxel() const
  3482. {
  3483. return VHACD::Vector3<uint32_t>(GetX(), GetY(), GetZ());
  3484. }
  3485. uint32_t Voxel::GetX() const
  3486. {
  3487. return (m_voxel >> VoxelBitsXStart) & VoxelBitMask;
  3488. }
  3489. uint32_t Voxel::GetY() const
  3490. {
  3491. return (m_voxel >> VoxelBitsYStart) & VoxelBitMask;
  3492. }
  3493. uint32_t Voxel::GetZ() const
  3494. {
  3495. return (m_voxel >> VoxelBitsZStart) & VoxelBitMask;
  3496. }
  3497. uint32_t Voxel::GetVoxelAddress() const
  3498. {
  3499. return m_voxel;
  3500. }
  3501. struct SimpleMesh
  3502. {
  3503. std::vector<VHACD::Vertex> m_vertices;
  3504. std::vector<VHACD::Triangle> m_indices;
  3505. };
  3506. /*======================== 0-tests ========================*/
  3507. inline bool IntersectRayAABB(const VHACD::Vect3& start,
  3508. const VHACD::Vect3& dir,
  3509. const VHACD::BoundsAABB& bounds,
  3510. double& t)
  3511. {
  3512. //! calculate candidate plane on each axis
  3513. bool inside = true;
  3514. VHACD::Vect3 ta(double(-1.0));
  3515. //! use unrolled loops
  3516. for (uint32_t i = 0; i < 3; ++i)
  3517. {
  3518. if (start[i] < bounds.GetMin()[i])
  3519. {
  3520. if (dir[i] != double(0.0))
  3521. ta[i] = (bounds.GetMin()[i] - start[i]) / dir[i];
  3522. inside = false;
  3523. }
  3524. else if (start[i] > bounds.GetMax()[i])
  3525. {
  3526. if (dir[i] != double(0.0))
  3527. ta[i] = (bounds.GetMax()[i] - start[i]) / dir[i];
  3528. inside = false;
  3529. }
  3530. }
  3531. //! if point inside all planes
  3532. if (inside)
  3533. {
  3534. t = double(0.0);
  3535. return true;
  3536. }
  3537. //! we now have t values for each of possible intersection planes
  3538. //! find the maximum to get the intersection point
  3539. uint32_t taxis;
  3540. double tmax = ta.MaxCoeff(taxis);
  3541. if (tmax < double(0.0))
  3542. return false;
  3543. //! check that the intersection point lies on the plane we picked
  3544. //! we don't test the axis of closest intersection for precision reasons
  3545. //! no eps for now
  3546. double eps = double(0.0);
  3547. VHACD::Vect3 hit = start + dir * tmax;
  3548. if (( hit.GetX() < bounds.GetMin().GetX() - eps
  3549. || hit.GetX() > bounds.GetMax().GetX() + eps)
  3550. && taxis != 0)
  3551. return false;
  3552. if (( hit.GetY() < bounds.GetMin().GetY() - eps
  3553. || hit.GetY() > bounds.GetMax().GetY() + eps)
  3554. && taxis != 1)
  3555. return false;
  3556. if (( hit.GetZ() < bounds.GetMin().GetZ() - eps
  3557. || hit.GetZ() > bounds.GetMax().GetZ() + eps)
  3558. && taxis != 2)
  3559. return false;
  3560. //! output results
  3561. t = tmax;
  3562. return true;
  3563. }
  3564. // Moller and Trumbore's method
  3565. inline bool IntersectRayTriTwoSided(const VHACD::Vect3& p,
  3566. const VHACD::Vect3& dir,
  3567. const VHACD::Vect3& a,
  3568. const VHACD::Vect3& b,
  3569. const VHACD::Vect3& c,
  3570. double& t,
  3571. double& u,
  3572. double& v,
  3573. double& w,
  3574. double& sign,
  3575. VHACD::Vect3* normal)
  3576. {
  3577. VHACD::Vect3 ab = b - a;
  3578. VHACD::Vect3 ac = c - a;
  3579. VHACD::Vect3 n = ab.Cross(ac);
  3580. double d = -dir.Dot(n);
  3581. double ood = double(1.0) / d; // No need to check for division by zero here as infinity arithmetic will save us...
  3582. VHACD::Vect3 ap = p - a;
  3583. t = ap.Dot(n) * ood;
  3584. if (t < double(0.0))
  3585. {
  3586. return false;
  3587. }
  3588. VHACD::Vect3 e = -dir.Cross(ap);
  3589. v = ac.Dot(e) * ood;
  3590. if (v < double(0.0) || v > double(1.0)) // ...here...
  3591. {
  3592. return false;
  3593. }
  3594. w = -ab.Dot(e) * ood;
  3595. if (w < double(0.0) || v + w > double(1.0)) // ...and here
  3596. {
  3597. return false;
  3598. }
  3599. u = double(1.0) - v - w;
  3600. if (normal)
  3601. {
  3602. *normal = n;
  3603. }
  3604. sign = d;
  3605. return true;
  3606. }
  3607. // RTCD 5.1.5, page 142
  3608. inline VHACD::Vect3 ClosestPointOnTriangle(const VHACD::Vect3& a,
  3609. const VHACD::Vect3& b,
  3610. const VHACD::Vect3& c,
  3611. const VHACD::Vect3& p,
  3612. double& v,
  3613. double& w)
  3614. {
  3615. VHACD::Vect3 ab = b - a;
  3616. VHACD::Vect3 ac = c - a;
  3617. VHACD::Vect3 ap = p - a;
  3618. double d1 = ab.Dot(ap);
  3619. double d2 = ac.Dot(ap);
  3620. if ( d1 <= double(0.0)
  3621. && d2 <= double(0.0))
  3622. {
  3623. v = double(0.0);
  3624. w = double(0.0);
  3625. return a;
  3626. }
  3627. VHACD::Vect3 bp = p - b;
  3628. double d3 = ab.Dot(bp);
  3629. double d4 = ac.Dot(bp);
  3630. if ( d3 >= double(0.0)
  3631. && d4 <= d3)
  3632. {
  3633. v = double(1.0);
  3634. w = double(0.0);
  3635. return b;
  3636. }
  3637. double vc = d1 * d4 - d3 * d2;
  3638. if ( vc <= double(0.0)
  3639. && d1 >= double(0.0)
  3640. && d3 <= double(0.0))
  3641. {
  3642. v = d1 / (d1 - d3);
  3643. w = double(0.0);
  3644. return a + v * ab;
  3645. }
  3646. VHACD::Vect3 cp = p - c;
  3647. double d5 = ab.Dot(cp);
  3648. double d6 = ac.Dot(cp);
  3649. if (d6 >= double(0.0) && d5 <= d6)
  3650. {
  3651. v = double(0.0);
  3652. w = double(1.0);
  3653. return c;
  3654. }
  3655. double vb = d5 * d2 - d1 * d6;
  3656. if ( vb <= double(0.0)
  3657. && d2 >= double(0.0)
  3658. && d6 <= double(0.0))
  3659. {
  3660. v = double(0.0);
  3661. w = d2 / (d2 - d6);
  3662. return a + w * ac;
  3663. }
  3664. double va = d3 * d6 - d5 * d4;
  3665. if ( va <= double(0.0)
  3666. && (d4 - d3) >= double(0.0)
  3667. && (d5 - d6) >= double(0.0))
  3668. {
  3669. w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  3670. v = double(1.0) - w;
  3671. return b + w * (c - b);
  3672. }
  3673. double denom = double(1.0) / (va + vb + vc);
  3674. v = vb * denom;
  3675. w = vc * denom;
  3676. return a + ab * v + ac * w;
  3677. }
  3678. class AABBTree
  3679. {
  3680. public:
  3681. AABBTree() = default;
  3682. AABBTree(AABBTree&&) = default;
  3683. AABBTree& operator=(AABBTree&&) = default;
  3684. AABBTree(const std::vector<VHACD::Vertex>& vertices,
  3685. const std::vector<VHACD::Triangle>& indices);
  3686. bool TraceRay(const VHACD::Vect3& start,
  3687. const VHACD::Vect3& to,
  3688. double& outT,
  3689. double& faceSign,
  3690. VHACD::Vect3& hitLocation) const;
  3691. bool TraceRay(const VHACD::Vect3& start,
  3692. const VHACD::Vect3& dir,
  3693. uint32_t& insideCount,
  3694. uint32_t& outsideCount) const;
  3695. bool TraceRay(const VHACD::Vect3& start,
  3696. const VHACD::Vect3& dir,
  3697. double& outT,
  3698. double& u,
  3699. double& v,
  3700. double& w,
  3701. double& faceSign,
  3702. uint32_t& faceIndex) const;
  3703. VHACD::Vect3 GetCenter() const;
  3704. VHACD::Vect3 GetMinExtents() const;
  3705. VHACD::Vect3 GetMaxExtents() const;
  3706. bool GetClosestPointWithinDistance(const VHACD::Vect3& point,
  3707. double maxDistance,
  3708. VHACD::Vect3& closestPoint) const;
  3709. private:
  3710. struct Node
  3711. {
  3712. union
  3713. {
  3714. uint32_t m_children;
  3715. uint32_t m_numFaces{ 0 };
  3716. };
  3717. uint32_t* m_faces{ nullptr };
  3718. VHACD::BoundsAABB m_extents;
  3719. };
  3720. struct FaceSorter
  3721. {
  3722. FaceSorter(const std::vector<VHACD::Vertex>& positions,
  3723. const std::vector<VHACD::Triangle>& indices,
  3724. uint32_t axis);
  3725. bool operator()(uint32_t lhs, uint32_t rhs) const;
  3726. double GetCentroid(uint32_t face) const;
  3727. const std::vector<VHACD::Vertex>& m_vertices;
  3728. const std::vector<VHACD::Triangle>& m_indices;
  3729. uint32_t m_axis;
  3730. };
  3731. // partition the objects and return the number of objects in the lower partition
  3732. uint32_t PartitionMedian(Node& n,
  3733. uint32_t* faces,
  3734. uint32_t numFaces);
  3735. uint32_t PartitionSAH(Node& n,
  3736. uint32_t* faces,
  3737. uint32_t numFaces);
  3738. void Build();
  3739. void BuildRecursive(uint32_t nodeIndex,
  3740. uint32_t* faces,
  3741. uint32_t numFaces);
  3742. void TraceRecursive(uint32_t nodeIndex,
  3743. const VHACD::Vect3& start,
  3744. const VHACD::Vect3& dir,
  3745. double& outT,
  3746. double& u,
  3747. double& v,
  3748. double& w,
  3749. double& faceSign,
  3750. uint32_t& faceIndex) const;
  3751. bool GetClosestPointWithinDistance(const VHACD::Vect3& point,
  3752. const double maxDis,
  3753. double& dis,
  3754. double& v,
  3755. double& w,
  3756. uint32_t& faceIndex,
  3757. VHACD::Vect3& closest) const;
  3758. void GetClosestPointWithinDistanceSqRecursive(uint32_t nodeIndex,
  3759. const VHACD::Vect3& point,
  3760. double& outDisSq,
  3761. double& outV,
  3762. double& outW,
  3763. uint32_t& outFaceIndex,
  3764. VHACD::Vect3& closest) const;
  3765. VHACD::BoundsAABB CalculateFaceBounds(uint32_t* faces,
  3766. uint32_t numFaces);
  3767. // track the next free node
  3768. uint32_t m_freeNode;
  3769. const std::vector<VHACD::Vertex>* m_vertices{ nullptr };
  3770. const std::vector<VHACD::Triangle>* m_indices{ nullptr };
  3771. std::vector<uint32_t> m_faces;
  3772. std::vector<Node> m_nodes;
  3773. std::vector<VHACD::BoundsAABB> m_faceBounds;
  3774. // stats
  3775. uint32_t m_treeDepth{ 0 };
  3776. uint32_t m_innerNodes{ 0 };
  3777. uint32_t m_leafNodes{ 0 };
  3778. uint32_t s_depth{ 0 };
  3779. };
  3780. AABBTree::FaceSorter::FaceSorter(const std::vector<VHACD::Vertex>& positions,
  3781. const std::vector<VHACD::Triangle>& indices,
  3782. uint32_t axis)
  3783. : m_vertices(positions)
  3784. , m_indices(indices)
  3785. , m_axis(axis)
  3786. {
  3787. }
  3788. inline bool AABBTree::FaceSorter::operator()(uint32_t lhs,
  3789. uint32_t rhs) const
  3790. {
  3791. double a = GetCentroid(lhs);
  3792. double b = GetCentroid(rhs);
  3793. if (a == b)
  3794. {
  3795. return lhs < rhs;
  3796. }
  3797. else
  3798. {
  3799. return a < b;
  3800. }
  3801. }
  3802. inline double AABBTree::FaceSorter::GetCentroid(uint32_t face) const
  3803. {
  3804. const VHACD::Vect3& a = m_vertices[m_indices[face].mI0];
  3805. const VHACD::Vect3& b = m_vertices[m_indices[face].mI1];
  3806. const VHACD::Vect3& c = m_vertices[m_indices[face].mI2];
  3807. return (a[m_axis] + b[m_axis] + c[m_axis]) / double(3.0);
  3808. }
  3809. AABBTree::AABBTree(const std::vector<VHACD::Vertex>& vertices,
  3810. const std::vector<VHACD::Triangle>& indices)
  3811. : m_vertices(&vertices)
  3812. , m_indices(&indices)
  3813. {
  3814. Build();
  3815. }
  3816. bool AABBTree::TraceRay(const VHACD::Vect3& start,
  3817. const VHACD::Vect3& to,
  3818. double& outT,
  3819. double& faceSign,
  3820. VHACD::Vect3& hitLocation) const
  3821. {
  3822. VHACD::Vect3 dir = to - start;
  3823. double distance = dir.Normalize();
  3824. double u, v, w;
  3825. uint32_t faceIndex;
  3826. bool hit = TraceRay(start,
  3827. dir,
  3828. outT,
  3829. u,
  3830. v,
  3831. w,
  3832. faceSign,
  3833. faceIndex);
  3834. if (hit)
  3835. {
  3836. hitLocation = start + dir * outT;
  3837. }
  3838. if (hit && outT > distance)
  3839. {
  3840. hit = false;
  3841. }
  3842. return hit;
  3843. }
  3844. bool AABBTree::TraceRay(const VHACD::Vect3& start,
  3845. const VHACD::Vect3& dir,
  3846. uint32_t& insideCount,
  3847. uint32_t& outsideCount) const
  3848. {
  3849. double outT, u, v, w, faceSign;
  3850. uint32_t faceIndex;
  3851. bool hit = TraceRay(start,
  3852. dir,
  3853. outT,
  3854. u,
  3855. v,
  3856. w,
  3857. faceSign,
  3858. faceIndex);
  3859. if (hit)
  3860. {
  3861. if (faceSign >= 0)
  3862. {
  3863. insideCount++;
  3864. }
  3865. else
  3866. {
  3867. outsideCount++;
  3868. }
  3869. }
  3870. return hit;
  3871. }
  3872. bool AABBTree::TraceRay(const VHACD::Vect3& start,
  3873. const VHACD::Vect3& dir,
  3874. double& outT,
  3875. double& u,
  3876. double& v,
  3877. double& w,
  3878. double& faceSign,
  3879. uint32_t& faceIndex) const
  3880. {
  3881. outT = FLT_MAX;
  3882. TraceRecursive(0,
  3883. start,
  3884. dir,
  3885. outT,
  3886. u,
  3887. v,
  3888. w,
  3889. faceSign,
  3890. faceIndex);
  3891. return (outT != FLT_MAX);
  3892. }
  3893. VHACD::Vect3 AABBTree::GetCenter() const
  3894. {
  3895. return m_nodes[0].m_extents.GetCenter();
  3896. }
  3897. VHACD::Vect3 AABBTree::GetMinExtents() const
  3898. {
  3899. return m_nodes[0].m_extents.GetMin();
  3900. }
  3901. VHACD::Vect3 AABBTree::GetMaxExtents() const
  3902. {
  3903. return m_nodes[0].m_extents.GetMax();
  3904. }
  3905. bool AABBTree::GetClosestPointWithinDistance(const VHACD::Vect3& point,
  3906. double maxDistance,
  3907. VHACD::Vect3& closestPoint) const
  3908. {
  3909. double dis, v, w;
  3910. uint32_t faceIndex;
  3911. bool hit = GetClosestPointWithinDistance(point,
  3912. maxDistance,
  3913. dis,
  3914. v,
  3915. w,
  3916. faceIndex,
  3917. closestPoint);
  3918. return hit;
  3919. }
  3920. // partition faces around the median face
  3921. uint32_t AABBTree::PartitionMedian(Node& n,
  3922. uint32_t* faces,
  3923. uint32_t numFaces)
  3924. {
  3925. FaceSorter predicate(*m_vertices,
  3926. *m_indices,
  3927. n.m_extents.GetSize().LongestAxis());
  3928. std::nth_element(faces,
  3929. faces + numFaces / 2,
  3930. faces + numFaces,
  3931. predicate);
  3932. return numFaces / 2;
  3933. }
  3934. // partition faces based on the surface area heuristic
  3935. uint32_t AABBTree::PartitionSAH(Node&,
  3936. uint32_t* faces,
  3937. uint32_t numFaces)
  3938. {
  3939. uint32_t bestAxis = 0;
  3940. uint32_t bestIndex = 0;
  3941. double bestCost = FLT_MAX;
  3942. for (uint32_t a = 0; a < 3; ++a)
  3943. {
  3944. // sort faces by centroids
  3945. FaceSorter predicate(*m_vertices,
  3946. *m_indices,
  3947. a);
  3948. std::sort(faces,
  3949. faces + numFaces,
  3950. predicate);
  3951. // two passes over data to calculate upper and lower bounds
  3952. std::vector<double> cumulativeLower(numFaces);
  3953. std::vector<double> cumulativeUpper(numFaces);
  3954. VHACD::BoundsAABB lower;
  3955. VHACD::BoundsAABB upper;
  3956. for (uint32_t i = 0; i < numFaces; ++i)
  3957. {
  3958. lower.Union(m_faceBounds[faces[i]]);
  3959. upper.Union(m_faceBounds[faces[numFaces - i - 1]]);
  3960. cumulativeLower[i] = lower.SurfaceArea();
  3961. cumulativeUpper[numFaces - i - 1] = upper.SurfaceArea();
  3962. }
  3963. double invTotalSA = double(1.0) / cumulativeUpper[0];
  3964. // test all split positions
  3965. for (uint32_t i = 0; i < numFaces - 1; ++i)
  3966. {
  3967. double pBelow = cumulativeLower[i] * invTotalSA;
  3968. double pAbove = cumulativeUpper[i] * invTotalSA;
  3969. double cost = double(0.125) + (pBelow * i + pAbove * (numFaces - i));
  3970. if (cost <= bestCost)
  3971. {
  3972. bestCost = cost;
  3973. bestIndex = i;
  3974. bestAxis = a;
  3975. }
  3976. }
  3977. }
  3978. // re-sort by best axis
  3979. FaceSorter predicate(*m_vertices,
  3980. *m_indices,
  3981. bestAxis);
  3982. std::sort(faces,
  3983. faces + numFaces,
  3984. predicate);
  3985. return bestIndex + 1;
  3986. }
  3987. void AABBTree::Build()
  3988. {
  3989. const uint32_t numFaces = uint32_t(m_indices->size());
  3990. // build initial list of faces
  3991. m_faces.reserve(numFaces);
  3992. // calculate bounds of each face and store
  3993. m_faceBounds.reserve(numFaces);
  3994. std::vector<VHACD::BoundsAABB> stack;
  3995. for (uint32_t i = 0; i < numFaces; ++i)
  3996. {
  3997. VHACD::BoundsAABB top = CalculateFaceBounds(&i,
  3998. 1);
  3999. m_faces.push_back(i);
  4000. m_faceBounds.push_back(top);
  4001. }
  4002. m_nodes.reserve(uint32_t(numFaces * double(1.5)));
  4003. // allocate space for all the nodes
  4004. m_freeNode = 1;
  4005. // start building
  4006. BuildRecursive(0,
  4007. m_faces.data(),
  4008. numFaces);
  4009. assert(s_depth == 0);
  4010. }
  4011. void AABBTree::BuildRecursive(uint32_t nodeIndex,
  4012. uint32_t* faces,
  4013. uint32_t numFaces)
  4014. {
  4015. const uint32_t kMaxFacesPerLeaf = 6;
  4016. // if we've run out of nodes allocate some more
  4017. if (nodeIndex >= m_nodes.size())
  4018. {
  4019. uint32_t s = std::max(uint32_t(double(1.5) * m_nodes.size()), 512U);
  4020. m_nodes.resize(s);
  4021. }
  4022. // a reference to the current node, need to be careful here as this reference may become invalid if array is resized
  4023. Node& n = m_nodes[nodeIndex];
  4024. // track max tree depth
  4025. ++s_depth;
  4026. m_treeDepth = std::max(m_treeDepth, s_depth);
  4027. n.m_extents = CalculateFaceBounds(faces,
  4028. numFaces);
  4029. // calculate bounds of faces and add node
  4030. if (numFaces <= kMaxFacesPerLeaf)
  4031. {
  4032. n.m_faces = faces;
  4033. n.m_numFaces = numFaces;
  4034. ++m_leafNodes;
  4035. }
  4036. else
  4037. {
  4038. ++m_innerNodes;
  4039. // face counts for each branch
  4040. const uint32_t leftCount = PartitionMedian(n, faces, numFaces);
  4041. // const uint32_t leftCount = PartitionSAH(n, faces, numFaces);
  4042. const uint32_t rightCount = numFaces - leftCount;
  4043. // alloc 2 nodes
  4044. m_nodes[nodeIndex].m_children = m_freeNode;
  4045. // allocate two nodes
  4046. m_freeNode += 2;
  4047. // split faces in half and build each side recursively
  4048. BuildRecursive(m_nodes[nodeIndex].m_children + 0, faces, leftCount);
  4049. BuildRecursive(m_nodes[nodeIndex].m_children + 1, faces + leftCount, rightCount);
  4050. }
  4051. --s_depth;
  4052. }
  4053. void AABBTree::TraceRecursive(uint32_t nodeIndex,
  4054. const VHACD::Vect3& start,
  4055. const VHACD::Vect3& dir,
  4056. double& outT,
  4057. double& outU,
  4058. double& outV,
  4059. double& outW,
  4060. double& faceSign,
  4061. uint32_t& faceIndex) const
  4062. {
  4063. const Node& node = m_nodes[nodeIndex];
  4064. if (node.m_faces == NULL)
  4065. {
  4066. // find closest node
  4067. const Node& leftChild = m_nodes[node.m_children + 0];
  4068. const Node& rightChild = m_nodes[node.m_children + 1];
  4069. double dist[2] = { FLT_MAX, FLT_MAX };
  4070. IntersectRayAABB(start,
  4071. dir,
  4072. leftChild.m_extents,
  4073. dist[0]);
  4074. IntersectRayAABB(start,
  4075. dir,
  4076. rightChild.m_extents,
  4077. dist[1]);
  4078. uint32_t closest = 0;
  4079. uint32_t furthest = 1;
  4080. if (dist[1] < dist[0])
  4081. {
  4082. closest = 1;
  4083. furthest = 0;
  4084. }
  4085. if (dist[closest] < outT)
  4086. {
  4087. TraceRecursive(node.m_children + closest,
  4088. start,
  4089. dir,
  4090. outT,
  4091. outU,
  4092. outV,
  4093. outW,
  4094. faceSign,
  4095. faceIndex);
  4096. }
  4097. if (dist[furthest] < outT)
  4098. {
  4099. TraceRecursive(node.m_children + furthest,
  4100. start,
  4101. dir,
  4102. outT,
  4103. outU,
  4104. outV,
  4105. outW,
  4106. faceSign,
  4107. faceIndex);
  4108. }
  4109. }
  4110. else
  4111. {
  4112. double t, u, v, w, s;
  4113. for (uint32_t i = 0; i < node.m_numFaces; ++i)
  4114. {
  4115. uint32_t indexStart = node.m_faces[i];
  4116. const VHACD::Vect3& a = (*m_vertices)[(*m_indices)[indexStart].mI0];
  4117. const VHACD::Vect3& b = (*m_vertices)[(*m_indices)[indexStart].mI1];
  4118. const VHACD::Vect3& c = (*m_vertices)[(*m_indices)[indexStart].mI2];
  4119. if (IntersectRayTriTwoSided(start, dir, a, b, c, t, u, v, w, s, NULL))
  4120. {
  4121. if (t < outT)
  4122. {
  4123. outT = t;
  4124. outU = u;
  4125. outV = v;
  4126. outW = w;
  4127. faceSign = s;
  4128. faceIndex = node.m_faces[i];
  4129. }
  4130. }
  4131. }
  4132. }
  4133. }
  4134. bool AABBTree::GetClosestPointWithinDistance(const VHACD::Vect3& point,
  4135. const double maxDis,
  4136. double& dis,
  4137. double& v,
  4138. double& w,
  4139. uint32_t& faceIndex,
  4140. VHACD::Vect3& closest) const
  4141. {
  4142. dis = maxDis;
  4143. faceIndex = uint32_t(~0);
  4144. double disSq = dis * dis;
  4145. GetClosestPointWithinDistanceSqRecursive(0,
  4146. point,
  4147. disSq,
  4148. v,
  4149. w,
  4150. faceIndex,
  4151. closest);
  4152. dis = sqrt(disSq);
  4153. return (faceIndex < (~(static_cast<unsigned int>(0))));
  4154. }
  4155. void AABBTree::GetClosestPointWithinDistanceSqRecursive(uint32_t nodeIndex,
  4156. const VHACD::Vect3& point,
  4157. double& outDisSq,
  4158. double& outV,
  4159. double& outW,
  4160. uint32_t& outFaceIndex,
  4161. VHACD::Vect3& closestPoint) const
  4162. {
  4163. const Node& node = m_nodes[nodeIndex];
  4164. if (node.m_faces == nullptr)
  4165. {
  4166. // find closest node
  4167. const Node& leftChild = m_nodes[node.m_children + 0];
  4168. const Node& rightChild = m_nodes[node.m_children + 1];
  4169. // double dist[2] = { FLT_MAX, FLT_MAX };
  4170. VHACD::Vect3 lp = leftChild.m_extents.ClosestPoint(point);
  4171. VHACD::Vect3 rp = rightChild.m_extents.ClosestPoint(point);
  4172. uint32_t closest = 0;
  4173. uint32_t furthest = 1;
  4174. double dcSq = (point - lp).GetNormSquared();
  4175. double dfSq = (point - rp).GetNormSquared();
  4176. if (dfSq < dcSq)
  4177. {
  4178. closest = 1;
  4179. furthest = 0;
  4180. std::swap(dfSq, dcSq);
  4181. }
  4182. if (dcSq < outDisSq)
  4183. {
  4184. GetClosestPointWithinDistanceSqRecursive(node.m_children + closest,
  4185. point,
  4186. outDisSq,
  4187. outV,
  4188. outW,
  4189. outFaceIndex,
  4190. closestPoint);
  4191. }
  4192. if (dfSq < outDisSq)
  4193. {
  4194. GetClosestPointWithinDistanceSqRecursive(node.m_children + furthest,
  4195. point,
  4196. outDisSq,
  4197. outV,
  4198. outW,
  4199. outFaceIndex,
  4200. closestPoint);
  4201. }
  4202. }
  4203. else
  4204. {
  4205. double v, w;
  4206. for (uint32_t i = 0; i < node.m_numFaces; ++i)
  4207. {
  4208. uint32_t indexStart = node.m_faces[i];
  4209. const VHACD::Vect3& a = (*m_vertices)[(*m_indices)[indexStart].mI0];
  4210. const VHACD::Vect3& b = (*m_vertices)[(*m_indices)[indexStart].mI1];
  4211. const VHACD::Vect3& c = (*m_vertices)[(*m_indices)[indexStart].mI2];
  4212. VHACD::Vect3 cp = ClosestPointOnTriangle(a, b, c, point, v, w);
  4213. double disSq = (cp - point).GetNormSquared();
  4214. if (disSq < outDisSq)
  4215. {
  4216. closestPoint = cp;
  4217. outDisSq = disSq;
  4218. outV = v;
  4219. outW = w;
  4220. outFaceIndex = node.m_faces[i];
  4221. }
  4222. }
  4223. }
  4224. }
  4225. VHACD::BoundsAABB AABBTree::CalculateFaceBounds(uint32_t* faces,
  4226. uint32_t numFaces)
  4227. {
  4228. VHACD::Vect3 minExtents( FLT_MAX);
  4229. VHACD::Vect3 maxExtents(-FLT_MAX);
  4230. // calculate face bounds
  4231. for (uint32_t i = 0; i < numFaces; ++i)
  4232. {
  4233. VHACD::Vect3 a = (*m_vertices)[(*m_indices)[faces[i]].mI0];
  4234. VHACD::Vect3 b = (*m_vertices)[(*m_indices)[faces[i]].mI1];
  4235. VHACD::Vect3 c = (*m_vertices)[(*m_indices)[faces[i]].mI2];
  4236. minExtents = a.CWiseMin(minExtents);
  4237. maxExtents = a.CWiseMax(maxExtents);
  4238. minExtents = b.CWiseMin(minExtents);
  4239. maxExtents = b.CWiseMax(maxExtents);
  4240. minExtents = c.CWiseMin(minExtents);
  4241. maxExtents = c.CWiseMax(maxExtents);
  4242. }
  4243. return VHACD::BoundsAABB(minExtents,
  4244. maxExtents);
  4245. }
  4246. enum class VoxelValue : uint8_t
  4247. {
  4248. PRIMITIVE_UNDEFINED = 0,
  4249. PRIMITIVE_OUTSIDE_SURFACE_TOWALK = 1,
  4250. PRIMITIVE_OUTSIDE_SURFACE = 2,
  4251. PRIMITIVE_INSIDE_SURFACE = 3,
  4252. PRIMITIVE_ON_SURFACE = 4
  4253. };
  4254. class Volume
  4255. {
  4256. public:
  4257. void Voxelize(const std::vector<VHACD::Vertex>& points,
  4258. const std::vector<VHACD::Triangle>& triangles,
  4259. const size_t dim,
  4260. FillMode fillMode,
  4261. const AABBTree& aabbTree);
  4262. void RaycastFill(const AABBTree& aabbTree);
  4263. void SetVoxel(const size_t i,
  4264. const size_t j,
  4265. const size_t k,
  4266. VoxelValue value);
  4267. VoxelValue& GetVoxel(const size_t i,
  4268. const size_t j,
  4269. const size_t k);
  4270. const VoxelValue& GetVoxel(const size_t i,
  4271. const size_t j,
  4272. const size_t k) const;
  4273. const std::vector<Voxel>& GetSurfaceVoxels() const;
  4274. const std::vector<Voxel>& GetInteriorVoxels() const;
  4275. double GetScale() const;
  4276. const VHACD::BoundsAABB& GetBounds() const;
  4277. const VHACD::Vector3<uint32_t>& GetDimensions() const;
  4278. VHACD::BoundsAABB m_bounds;
  4279. double m_scale{ 1.0 };
  4280. VHACD::Vector3<uint32_t> m_dim{ 0 };
  4281. size_t m_numVoxelsOnSurface{ 0 };
  4282. size_t m_numVoxelsInsideSurface{ 0 };
  4283. size_t m_numVoxelsOutsideSurface{ 0 };
  4284. std::vector<VoxelValue> m_data;
  4285. private:
  4286. void MarkOutsideSurface(const size_t i0,
  4287. const size_t j0,
  4288. const size_t k0,
  4289. const size_t i1,
  4290. const size_t j1,
  4291. const size_t k1);
  4292. void FillOutsideSurface();
  4293. void FillInsideSurface();
  4294. std::vector<VHACD::Voxel> m_surfaceVoxels;
  4295. std::vector<VHACD::Voxel> m_interiorVoxels;
  4296. };
  4297. bool PlaneBoxOverlap(const VHACD::Vect3& normal,
  4298. const VHACD::Vect3& vert,
  4299. const VHACD::Vect3& maxbox)
  4300. {
  4301. int32_t q;
  4302. VHACD::Vect3 vmin;
  4303. VHACD::Vect3 vmax;
  4304. double v;
  4305. for (q = 0; q < 3; q++)
  4306. {
  4307. v = vert[q];
  4308. if (normal[q] > double(0.0))
  4309. {
  4310. vmin[q] = -maxbox[q] - v;
  4311. vmax[q] = maxbox[q] - v;
  4312. }
  4313. else
  4314. {
  4315. vmin[q] = maxbox[q] - v;
  4316. vmax[q] = -maxbox[q] - v;
  4317. }
  4318. }
  4319. if (normal.Dot(vmin) > double(0.0))
  4320. return false;
  4321. if (normal.Dot(vmax) >= double(0.0))
  4322. return true;
  4323. return false;
  4324. }
  4325. bool AxisTest(double a, double b, double fa, double fb,
  4326. double v0, double v1, double v2, double v3,
  4327. double boxHalfSize1, double boxHalfSize2)
  4328. {
  4329. double p0 = a * v0 + b * v1;
  4330. double p1 = a * v2 + b * v3;
  4331. double min = std::min(p0, p1);
  4332. double max = std::max(p0, p1);
  4333. double rad = fa * boxHalfSize1 + fb * boxHalfSize2;
  4334. if (min > rad || max < -rad)
  4335. {
  4336. return false;
  4337. }
  4338. return true;
  4339. }
  4340. bool TriBoxOverlap(const VHACD::Vect3& boxCenter,
  4341. const VHACD::Vect3& boxHalfSize,
  4342. const VHACD::Vect3& triVer0,
  4343. const VHACD::Vect3& triVer1,
  4344. const VHACD::Vect3& triVer2)
  4345. {
  4346. /* use separating axis theorem to test overlap between triangle and box */
  4347. /* need to test for overlap in these directions: */
  4348. /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
  4349. /* we do not even need to test these) */
  4350. /* 2) normal of the triangle */
  4351. /* 3) crossproduct(edge from tri, {x,y,z}-direction) */
  4352. /* this gives 3x3=9 more tests */
  4353. VHACD::Vect3 v0 = triVer0 - boxCenter;
  4354. VHACD::Vect3 v1 = triVer1 - boxCenter;
  4355. VHACD::Vect3 v2 = triVer2 - boxCenter;
  4356. VHACD::Vect3 e0 = v1 - v0;
  4357. VHACD::Vect3 e1 = v2 - v1;
  4358. VHACD::Vect3 e2 = v0 - v2;
  4359. /* This is the fastest branch on Sun */
  4360. /* move everything so that the boxcenter is in (0,0,0) */
  4361. /* Bullet 3: */
  4362. /* test the 9 tests first (this was faster) */
  4363. double fex = fabs(e0[0]);
  4364. double fey = fabs(e0[1]);
  4365. double fez = fabs(e0[2]);
  4366. /*
  4367. * These should use Get*() instead of subscript for consistency, but the function calls are long enough already
  4368. */
  4369. if (!AxisTest( e0[2], -e0[1], fez, fey, v0[1], v0[2], v2[1], v2[2], boxHalfSize[1], boxHalfSize[2])) return 0; // X01
  4370. if (!AxisTest(-e0[2], e0[0], fez, fex, v0[0], v0[2], v2[0], v2[2], boxHalfSize[0], boxHalfSize[2])) return 0; // Y02
  4371. if (!AxisTest( e0[1], -e0[0], fey, fex, v1[0], v1[1], v2[0], v2[1], boxHalfSize[0], boxHalfSize[1])) return 0; // Z12
  4372. fex = fabs(e1[0]);
  4373. fey = fabs(e1[1]);
  4374. fez = fabs(e1[2]);
  4375. if (!AxisTest( e1[2], -e1[1], fez, fey, v0[1], v0[2], v2[1], v2[2], boxHalfSize[1], boxHalfSize[2])) return 0; // X01
  4376. if (!AxisTest(-e1[2], e1[0], fez, fex, v0[0], v0[2], v2[0], v2[2], boxHalfSize[0], boxHalfSize[2])) return 0; // Y02
  4377. if (!AxisTest( e1[1], -e1[0], fey, fex, v0[0], v0[1], v1[0], v1[1], boxHalfSize[0], boxHalfSize[2])) return 0; // Z0
  4378. fex = fabs(e2[0]);
  4379. fey = fabs(e2[1]);
  4380. fez = fabs(e2[2]);
  4381. if (!AxisTest( e2[2], -e2[1], fez, fey, v0[1], v0[2], v1[1], v1[2], boxHalfSize[1], boxHalfSize[2])) return 0; // X2
  4382. if (!AxisTest(-e2[2], e2[0], fez, fex, v0[0], v0[2], v1[0], v1[2], boxHalfSize[0], boxHalfSize[2])) return 0; // Y1
  4383. if (!AxisTest( e2[1], -e2[0], fey, fex, v1[0], v1[1], v2[0], v2[1], boxHalfSize[0], boxHalfSize[1])) return 0; // Z12
  4384. /* Bullet 1: */
  4385. /* first test overlap in the {x,y,z}-directions */
  4386. /* find min, max of the triangle each direction, and test for overlap in */
  4387. /* that direction -- this is equivalent to testing a minimal AABB around */
  4388. /* the triangle against the AABB */
  4389. /* test in 0-direction */
  4390. double min = std::min({v0.GetX(), v1.GetX(), v2.GetX()});
  4391. double max = std::max({v0.GetX(), v1.GetX(), v2.GetX()});
  4392. if (min > boxHalfSize[0] || max < -boxHalfSize[0])
  4393. return false;
  4394. /* test in 1-direction */
  4395. min = std::min({v0.GetY(), v1.GetY(), v2.GetY()});
  4396. max = std::max({v0.GetY(), v1.GetY(), v2.GetY()});
  4397. if (min > boxHalfSize[1] || max < -boxHalfSize[1])
  4398. return false;
  4399. /* test in getZ-direction */
  4400. min = std::min({v0.GetZ(), v1.GetZ(), v2.GetZ()});
  4401. max = std::max({v0.GetZ(), v1.GetZ(), v2.GetZ()});
  4402. if (min > boxHalfSize[2] || max < -boxHalfSize[2])
  4403. return false;
  4404. /* Bullet 2: */
  4405. /* test if the box intersects the plane of the triangle */
  4406. /* compute plane equation of triangle: normal*x+d=0 */
  4407. VHACD::Vect3 normal = e0.Cross(e1);
  4408. if (!PlaneBoxOverlap(normal, v0, boxHalfSize))
  4409. return false;
  4410. return true; /* box and triangle overlaps */
  4411. }
  4412. void Volume::Voxelize(const std::vector<VHACD::Vertex>& points,
  4413. const std::vector<VHACD::Triangle>& indices,
  4414. const size_t dimensions,
  4415. FillMode fillMode,
  4416. const AABBTree& aabbTree)
  4417. {
  4418. double a = std::pow(dimensions, 0.33);
  4419. size_t dim = a * double(1.5);
  4420. dim = std::max(dim, size_t(32));
  4421. if (points.size() == 0)
  4422. {
  4423. return;
  4424. }
  4425. m_bounds = BoundsAABB(points);
  4426. VHACD::Vect3 d = m_bounds.GetSize();
  4427. double r;
  4428. // Equal comparison is important here to avoid taking the last branch when d[0] == d[1] with d[2] being the smallest
  4429. // dimension. That would lead to dimensions in i and j to be a lot bigger than expected and make the amount of
  4430. // voxels in the volume totally unmanageable.
  4431. if (d[0] >= d[1] && d[0] >= d[2])
  4432. {
  4433. r = d[0];
  4434. m_dim[0] = uint32_t(dim);
  4435. m_dim[1] = uint32_t(2 + static_cast<size_t>(dim * d[1] / d[0]));
  4436. m_dim[2] = uint32_t(2 + static_cast<size_t>(dim * d[2] / d[0]));
  4437. }
  4438. else if (d[1] >= d[0] && d[1] >= d[2])
  4439. {
  4440. r = d[1];
  4441. m_dim[1] = uint32_t(dim);
  4442. m_dim[0] = uint32_t(2 + static_cast<size_t>(dim * d[0] / d[1]));
  4443. m_dim[2] = uint32_t(2 + static_cast<size_t>(dim * d[2] / d[1]));
  4444. }
  4445. else
  4446. {
  4447. r = d[2];
  4448. m_dim[2] = uint32_t(dim);
  4449. m_dim[0] = uint32_t(2 + static_cast<size_t>(dim * d[0] / d[2]));
  4450. m_dim[1] = uint32_t(2 + static_cast<size_t>(dim * d[1] / d[2]));
  4451. }
  4452. m_scale = r / (dim - 1);
  4453. double invScale = (dim - 1) / r;
  4454. m_data = std::vector<VoxelValue>(m_dim[0] * m_dim[1] * m_dim[2],
  4455. VoxelValue::PRIMITIVE_UNDEFINED);
  4456. m_numVoxelsOnSurface = 0;
  4457. m_numVoxelsInsideSurface = 0;
  4458. m_numVoxelsOutsideSurface = 0;
  4459. VHACD::Vect3 p[3];
  4460. VHACD::Vect3 boxcenter;
  4461. VHACD::Vect3 pt;
  4462. const VHACD::Vect3 boxhalfsize(double(0.5));
  4463. for (size_t t = 0; t < indices.size(); ++t)
  4464. {
  4465. size_t i0, j0, k0;
  4466. size_t i1, j1, k1;
  4467. VHACD::Vector3<uint32_t> tri = indices[t];
  4468. for (int32_t c = 0; c < 3; ++c)
  4469. {
  4470. pt = points[tri[c]];
  4471. p[c] = (pt - m_bounds.GetMin()) * invScale;
  4472. size_t i = static_cast<size_t>(p[c][0] + double(0.5));
  4473. size_t j = static_cast<size_t>(p[c][1] + double(0.5));
  4474. size_t k = static_cast<size_t>(p[c][2] + double(0.5));
  4475. assert(i < m_dim[0] && j < m_dim[1] && k < m_dim[2]);
  4476. if (c == 0)
  4477. {
  4478. i0 = i1 = i;
  4479. j0 = j1 = j;
  4480. k0 = k1 = k;
  4481. }
  4482. else
  4483. {
  4484. i0 = std::min(i0, i);
  4485. j0 = std::min(j0, j);
  4486. k0 = std::min(k0, k);
  4487. i1 = std::max(i1, i);
  4488. j1 = std::max(j1, j);
  4489. k1 = std::max(k1, k);
  4490. }
  4491. }
  4492. if (i0 > 0)
  4493. --i0;
  4494. if (j0 > 0)
  4495. --j0;
  4496. if (k0 > 0)
  4497. --k0;
  4498. if (i1 < m_dim[0])
  4499. ++i1;
  4500. if (j1 < m_dim[1])
  4501. ++j1;
  4502. if (k1 < m_dim[2])
  4503. ++k1;
  4504. for (size_t i_id = i0; i_id < i1; ++i_id)
  4505. {
  4506. boxcenter[0] = uint32_t(i_id);
  4507. for (size_t j_id = j0; j_id < j1; ++j_id)
  4508. {
  4509. boxcenter[1] = uint32_t(j_id);
  4510. for (size_t k_id = k0; k_id < k1; ++k_id)
  4511. {
  4512. boxcenter[2] = uint32_t(k_id);
  4513. bool res = TriBoxOverlap(boxcenter,
  4514. boxhalfsize,
  4515. p[0],
  4516. p[1],
  4517. p[2]);
  4518. VoxelValue& value = GetVoxel(i_id,
  4519. j_id,
  4520. k_id);
  4521. if ( res
  4522. && value == VoxelValue::PRIMITIVE_UNDEFINED)
  4523. {
  4524. value = VoxelValue::PRIMITIVE_ON_SURFACE;
  4525. ++m_numVoxelsOnSurface;
  4526. m_surfaceVoxels.emplace_back(uint32_t(i_id),
  4527. uint32_t(j_id),
  4528. uint32_t(k_id));
  4529. }
  4530. }
  4531. }
  4532. }
  4533. }
  4534. if (fillMode == FillMode::SURFACE_ONLY)
  4535. {
  4536. const size_t i0_local = m_dim[0];
  4537. const size_t j0_local = m_dim[1];
  4538. const size_t k0_local = m_dim[2];
  4539. for (size_t i_id = 0; i_id < i0_local; ++i_id)
  4540. {
  4541. for (size_t j_id = 0; j_id < j0_local; ++j_id)
  4542. {
  4543. for (size_t k_id = 0; k_id < k0_local; ++k_id)
  4544. {
  4545. const VoxelValue& voxel = GetVoxel(i_id,
  4546. j_id,
  4547. k_id);
  4548. if (voxel != VoxelValue::PRIMITIVE_ON_SURFACE)
  4549. {
  4550. SetVoxel(i_id,
  4551. j_id,
  4552. k_id,
  4553. VoxelValue::PRIMITIVE_OUTSIDE_SURFACE);
  4554. }
  4555. }
  4556. }
  4557. }
  4558. }
  4559. else if (fillMode == FillMode::FLOOD_FILL)
  4560. {
  4561. /*
  4562. * Marking the outside edges of the voxel cube to be outside surfaces to walk
  4563. */
  4564. MarkOutsideSurface(0, 0, 0, m_dim[0], m_dim[1], 1);
  4565. MarkOutsideSurface(0, 0, m_dim[2] - 1, m_dim[0], m_dim[1], m_dim[2]);
  4566. MarkOutsideSurface(0, 0, 0, m_dim[0], 1, m_dim[2]);
  4567. MarkOutsideSurface(0, m_dim[1] - 1, 0, m_dim[0], m_dim[1], m_dim[2]);
  4568. MarkOutsideSurface(0, 0, 0, 1, m_dim[1], m_dim[2]);
  4569. MarkOutsideSurface(m_dim[0] - 1, 0, 0, m_dim[0], m_dim[1], m_dim[2]);
  4570. FillOutsideSurface();
  4571. FillInsideSurface();
  4572. }
  4573. else if (fillMode == FillMode::RAYCAST_FILL)
  4574. {
  4575. RaycastFill(aabbTree);
  4576. }
  4577. }
  4578. void Volume::RaycastFill(const AABBTree& aabbTree)
  4579. {
  4580. const uint32_t i0 = m_dim[0];
  4581. const uint32_t j0 = m_dim[1];
  4582. const uint32_t k0 = m_dim[2];
  4583. size_t maxSize = i0 * j0 * k0;
  4584. std::vector<Voxel> temp;
  4585. temp.reserve(maxSize);
  4586. uint32_t count{ 0 };
  4587. m_numVoxelsInsideSurface = 0;
  4588. for (uint32_t i = 0; i < i0; ++i)
  4589. {
  4590. for (uint32_t j = 0; j < j0; ++j)
  4591. {
  4592. for (uint32_t k = 0; k < k0; ++k)
  4593. {
  4594. VoxelValue& voxel = GetVoxel(i, j, k);
  4595. if (voxel != VoxelValue::PRIMITIVE_ON_SURFACE)
  4596. {
  4597. VHACD::Vect3 start = VHACD::Vect3(i, j, k) * m_scale + m_bounds.GetMin();
  4598. uint32_t insideCount = 0;
  4599. uint32_t outsideCount = 0;
  4600. VHACD::Vect3 directions[6] = {
  4601. VHACD::Vect3( 1, 0, 0),
  4602. VHACD::Vect3(-1, 0, 0), // this was 1, 0, 0 in the original code, but looks wrong
  4603. VHACD::Vect3( 0, 1, 0),
  4604. VHACD::Vect3( 0, -1, 0),
  4605. VHACD::Vect3( 0, 0, 1),
  4606. VHACD::Vect3( 0, 0, -1)
  4607. };
  4608. for (uint32_t r = 0; r < 6; r++)
  4609. {
  4610. aabbTree.TraceRay(start,
  4611. directions[r],
  4612. insideCount,
  4613. outsideCount);
  4614. // Early out if we hit the outside of the mesh
  4615. if (outsideCount)
  4616. {
  4617. break;
  4618. }
  4619. // Early out if we accumulated 3 inside hits
  4620. if (insideCount >= 3)
  4621. {
  4622. break;
  4623. }
  4624. }
  4625. if (outsideCount == 0 && insideCount >= 3)
  4626. {
  4627. voxel = VoxelValue::PRIMITIVE_INSIDE_SURFACE;
  4628. temp.emplace_back(i, j, k);
  4629. count++;
  4630. m_numVoxelsInsideSurface++;
  4631. }
  4632. else
  4633. {
  4634. voxel = VoxelValue::PRIMITIVE_OUTSIDE_SURFACE;
  4635. }
  4636. }
  4637. }
  4638. }
  4639. }
  4640. if (count)
  4641. {
  4642. m_interiorVoxels = std::move(temp);
  4643. }
  4644. }
  4645. void Volume::SetVoxel(const size_t i,
  4646. const size_t j,
  4647. const size_t k,
  4648. VoxelValue value)
  4649. {
  4650. assert(i < m_dim[0]);
  4651. assert(j < m_dim[1]);
  4652. assert(k < m_dim[2]);
  4653. m_data[k + j * m_dim[2] + i * m_dim[1] * m_dim[2]] = value;
  4654. }
  4655. VoxelValue& Volume::GetVoxel(const size_t i,
  4656. const size_t j,
  4657. const size_t k)
  4658. {
  4659. assert(i < m_dim[0]);
  4660. assert(j < m_dim[1]);
  4661. assert(k < m_dim[2]);
  4662. return m_data[k + j * m_dim[2] + i * m_dim[1] * m_dim[2]];
  4663. }
  4664. const VoxelValue& Volume::GetVoxel(const size_t i,
  4665. const size_t j,
  4666. const size_t k) const
  4667. {
  4668. assert(i < m_dim[0]);
  4669. assert(j < m_dim[1]);
  4670. assert(k < m_dim[2]);
  4671. return m_data[k + j * m_dim[2] + i * m_dim[1] * m_dim[2]];
  4672. }
  4673. const std::vector<Voxel>& Volume::GetSurfaceVoxels() const
  4674. {
  4675. return m_surfaceVoxels;
  4676. }
  4677. const std::vector<Voxel>& Volume::GetInteriorVoxels() const
  4678. {
  4679. return m_interiorVoxels;
  4680. }
  4681. double Volume::GetScale() const
  4682. {
  4683. return m_scale;
  4684. }
  4685. const VHACD::BoundsAABB& Volume::GetBounds() const
  4686. {
  4687. return m_bounds;
  4688. }
  4689. const VHACD::Vector3<uint32_t>& Volume::GetDimensions() const
  4690. {
  4691. return m_dim;
  4692. }
  4693. void Volume::MarkOutsideSurface(const size_t i0,
  4694. const size_t j0,
  4695. const size_t k0,
  4696. const size_t i1,
  4697. const size_t j1,
  4698. const size_t k1)
  4699. {
  4700. for (size_t i = i0; i < i1; ++i)
  4701. {
  4702. for (size_t j = j0; j < j1; ++j)
  4703. {
  4704. for (size_t k = k0; k < k1; ++k)
  4705. {
  4706. VoxelValue& v = GetVoxel(i, j, k);
  4707. if (v == VoxelValue::PRIMITIVE_UNDEFINED)
  4708. {
  4709. v = VoxelValue::PRIMITIVE_OUTSIDE_SURFACE_TOWALK;
  4710. }
  4711. }
  4712. }
  4713. }
  4714. }
  4715. inline void WalkForward(int64_t start,
  4716. int64_t end,
  4717. VoxelValue* ptr,
  4718. int64_t stride,
  4719. int64_t maxDistance)
  4720. {
  4721. for (int64_t i = start, count = 0;
  4722. count < maxDistance && i < end && *ptr == VoxelValue::PRIMITIVE_UNDEFINED;
  4723. ++i, ptr += stride, ++count)
  4724. {
  4725. *ptr = VoxelValue::PRIMITIVE_OUTSIDE_SURFACE_TOWALK;
  4726. }
  4727. }
  4728. inline void WalkBackward(int64_t start,
  4729. int64_t end,
  4730. VoxelValue* ptr,
  4731. int64_t stride,
  4732. int64_t maxDistance)
  4733. {
  4734. for (int64_t i = start, count = 0;
  4735. count < maxDistance && i >= end && *ptr == VoxelValue::PRIMITIVE_UNDEFINED;
  4736. --i, ptr -= stride, ++count)
  4737. {
  4738. *ptr = VoxelValue::PRIMITIVE_OUTSIDE_SURFACE_TOWALK;
  4739. }
  4740. }
  4741. void Volume::FillOutsideSurface()
  4742. {
  4743. size_t voxelsWalked = 0;
  4744. const int64_t i0 = m_dim[0];
  4745. const int64_t j0 = m_dim[1];
  4746. const int64_t k0 = m_dim[2];
  4747. // Avoid striding too far in each direction to stay in L1 cache as much as possible.
  4748. // The cache size required for the walk is roughly (4 * walkDistance * 64) since
  4749. // the k direction doesn't count as it's walking byte per byte directly in a cache lines.
  4750. // ~16k is required for a walk distance of 64 in each directions.
  4751. const size_t walkDistance = 64;
  4752. // using the stride directly instead of calling GetVoxel for each iterations saves
  4753. // a lot of multiplications and pipeline stalls due to data dependencies on imul.
  4754. const size_t istride = &GetVoxel(1, 0, 0) - &GetVoxel(0, 0, 0);
  4755. const size_t jstride = &GetVoxel(0, 1, 0) - &GetVoxel(0, 0, 0);
  4756. const size_t kstride = &GetVoxel(0, 0, 1) - &GetVoxel(0, 0, 0);
  4757. // It might seem counter intuitive to go over the whole voxel range multiple times
  4758. // but since we do the run in memory order, it leaves us with far fewer cache misses
  4759. // than a BFS algorithm and it has the additional benefit of not requiring us to
  4760. // store and manipulate a fifo for recursion that might become huge when the number
  4761. // of voxels is large.
  4762. // This will outperform the BFS algorithm by several orders of magnitude in practice.
  4763. do
  4764. {
  4765. voxelsWalked = 0;
  4766. for (int64_t i = 0; i < i0; ++i)
  4767. {
  4768. for (int64_t j = 0; j < j0; ++j)
  4769. {
  4770. for (int64_t k = 0; k < k0; ++k)
  4771. {
  4772. VoxelValue& voxel = GetVoxel(i, j, k);
  4773. if (voxel == VoxelValue::PRIMITIVE_OUTSIDE_SURFACE_TOWALK)
  4774. {
  4775. voxelsWalked++;
  4776. voxel = VoxelValue::PRIMITIVE_OUTSIDE_SURFACE;
  4777. // walk in each direction to mark other voxel that should be walked.
  4778. // this will generate a 3d pattern that will help the overall
  4779. // algorithm converge faster while remaining cache friendly.
  4780. WalkForward(k + 1, k0, &voxel + kstride, kstride, walkDistance);
  4781. WalkBackward(k - 1, 0, &voxel - kstride, kstride, walkDistance);
  4782. WalkForward(j + 1, j0, &voxel + jstride, jstride, walkDistance);
  4783. WalkBackward(j - 1, 0, &voxel - jstride, jstride, walkDistance);
  4784. WalkForward(i + 1, i0, &voxel + istride, istride, walkDistance);
  4785. WalkBackward(i - 1, 0, &voxel - istride, istride, walkDistance);
  4786. }
  4787. }
  4788. }
  4789. }
  4790. m_numVoxelsOutsideSurface += voxelsWalked;
  4791. } while (voxelsWalked != 0);
  4792. }
  4793. void Volume::FillInsideSurface()
  4794. {
  4795. const uint32_t i0 = uint32_t(m_dim[0]);
  4796. const uint32_t j0 = uint32_t(m_dim[1]);
  4797. const uint32_t k0 = uint32_t(m_dim[2]);
  4798. size_t maxSize = i0 * j0 * k0;
  4799. std::vector<Voxel> temp;
  4800. temp.reserve(maxSize);
  4801. uint32_t count{ 0 };
  4802. for (uint32_t i = 0; i < i0; ++i)
  4803. {
  4804. for (uint32_t j = 0; j < j0; ++j)
  4805. {
  4806. for (uint32_t k = 0; k < k0; ++k)
  4807. {
  4808. VoxelValue& v = GetVoxel(i, j, k);
  4809. if (v == VoxelValue::PRIMITIVE_UNDEFINED)
  4810. {
  4811. v = VoxelValue::PRIMITIVE_INSIDE_SURFACE;
  4812. temp.emplace_back(i, j, k);
  4813. count++;
  4814. ++m_numVoxelsInsideSurface;
  4815. }
  4816. }
  4817. }
  4818. }
  4819. if ( count )
  4820. {
  4821. m_interiorVoxels = std::move(temp);
  4822. }
  4823. }
  4824. //******************************************************************************************
  4825. // ShrinkWrap helper class
  4826. //******************************************************************************************
  4827. // This is a code snippet which 'shrinkwraps' a convex hull
  4828. // to a source mesh.
  4829. //
  4830. // It is a somewhat complicated algorithm. It works as follows:
  4831. //
  4832. // * Step #1 : Compute the mean unit normal vector for each vertex in the convex hull
  4833. // * Step #2 : For each vertex in the conex hull we project is slightly outwards along the mean normal vector
  4834. // * Step #3 : We then raycast from this slightly extruded point back into the opposite direction of the mean normal vector
  4835. // resulting in a raycast from slightly beyond the vertex in the hull into the source mesh we are trying
  4836. // to 'shrink wrap' against
  4837. // * Step #4 : If the raycast fails we leave the original vertex alone
  4838. // * Step #5 : If the raycast hits a backface we leave the original vertex alone
  4839. // * Step #6 : If the raycast hits too far away (no more than a certain threshold distance) we live it alone
  4840. // * Step #7 : If the point we hit on the source mesh is not still within the convex hull, we reject it.
  4841. // * Step #8 : If all of the previous conditions are met, then we take the raycast hit location as the 'new position'
  4842. // * Step #9 : Once all points have been projected, if possible, we need to recompute the convex hull again based on these shrinkwrapped points
  4843. // * Step #10 : In theory that should work.. let's see...
  4844. //***********************************************************************************************
  4845. // QuickHull implementation
  4846. //***********************************************************************************************
  4847. //////////////////////////////////////////////////////////////////////////
  4848. // Quickhull base class holding the hull during construction
  4849. //////////////////////////////////////////////////////////////////////////
  4850. class QuickHull
  4851. {
  4852. public:
  4853. uint32_t ComputeConvexHull(const std::vector<VHACD::Vertex>& vertices,
  4854. uint32_t maxHullVertices);
  4855. const std::vector<VHACD::Vertex>& GetVertices() const;
  4856. const std::vector<VHACD::Triangle>& GetIndices() const;
  4857. private:
  4858. std::vector<VHACD::Vertex> m_vertices;
  4859. std::vector<VHACD::Triangle> m_indices;
  4860. };
  4861. uint32_t QuickHull::ComputeConvexHull(const std::vector<VHACD::Vertex>& vertices,
  4862. uint32_t maxHullVertices)
  4863. {
  4864. m_indices.clear();
  4865. VHACD::ConvexHull ch(vertices,
  4866. double(0.0001),
  4867. maxHullVertices);
  4868. auto& vlist = ch.GetVertexPool();
  4869. if ( !vlist.empty() )
  4870. {
  4871. size_t vcount = vlist.size();
  4872. m_vertices.resize(vcount);
  4873. std::copy(vlist.begin(),
  4874. vlist.end(),
  4875. m_vertices.begin());
  4876. }
  4877. for (std::list<ConvexHullFace>::const_iterator node = ch.GetList().begin(); node != ch.GetList().end(); ++node)
  4878. {
  4879. const VHACD::ConvexHullFace& face = *node;
  4880. m_indices.emplace_back(face.m_index[0],
  4881. face.m_index[1],
  4882. face.m_index[2]);
  4883. }
  4884. return uint32_t(m_indices.size());
  4885. }
  4886. const std::vector<VHACD::Vertex>& QuickHull::GetVertices() const
  4887. {
  4888. return m_vertices;
  4889. }
  4890. const std::vector<VHACD::Triangle>& QuickHull::GetIndices() const
  4891. {
  4892. return m_indices;
  4893. }
  4894. //******************************************************************************************
  4895. // Implementation of the ShrinkWrap function
  4896. //******************************************************************************************
  4897. void ShrinkWrap(SimpleMesh& sourceConvexHull,
  4898. const AABBTree& aabbTree,
  4899. uint32_t maxHullVertexCount,
  4900. double distanceThreshold,
  4901. bool doShrinkWrap)
  4902. {
  4903. std::vector<VHACD::Vertex> verts; // New verts for the new convex hull
  4904. verts.reserve(sourceConvexHull.m_vertices.size());
  4905. // Examine each vertex and see if it is within the voxel distance.
  4906. // If it is, then replace the point with the shrinkwrapped / projected point
  4907. for (uint32_t j = 0; j < sourceConvexHull.m_vertices.size(); j++)
  4908. {
  4909. VHACD::Vertex& p = sourceConvexHull.m_vertices[j];
  4910. if (doShrinkWrap)
  4911. {
  4912. VHACD::Vect3 closest;
  4913. if (aabbTree.GetClosestPointWithinDistance(p, distanceThreshold, closest))
  4914. {
  4915. p = closest;
  4916. }
  4917. }
  4918. verts.emplace_back(p);
  4919. }
  4920. // Final step is to recompute the convex hull
  4921. VHACD::QuickHull qh;
  4922. uint32_t tcount = qh.ComputeConvexHull(verts,
  4923. maxHullVertexCount);
  4924. if (tcount)
  4925. {
  4926. sourceConvexHull.m_vertices = qh.GetVertices();
  4927. sourceConvexHull.m_indices = qh.GetIndices();
  4928. }
  4929. }
  4930. //********************************************************************************************************************
  4931. #if !VHACD_DISABLE_THREADING
  4932. //********************************************************************************************************************
  4933. // Definition of the ThreadPool
  4934. //********************************************************************************************************************
  4935. class ThreadPool {
  4936. public:
  4937. ThreadPool();
  4938. ThreadPool(int worker);
  4939. ~ThreadPool();
  4940. template<typename F, typename... Args>
  4941. auto enqueue(F&& f, Args&& ... args)
  4942. #ifndef __cpp_lib_is_invocable
  4943. -> std::future< typename std::result_of< F( Args... ) >::type>;
  4944. #else
  4945. -> std::future< typename std::invoke_result_t<F, Args...>>;
  4946. #endif
  4947. private:
  4948. std::vector<std::thread> workers;
  4949. std::deque<std::function<void()>> tasks;
  4950. std::mutex task_mutex;
  4951. std::condition_variable cv;
  4952. bool closed;
  4953. };
  4954. ThreadPool::ThreadPool()
  4955. : ThreadPool(1)
  4956. {
  4957. }
  4958. ThreadPool::ThreadPool(int worker)
  4959. : closed(false)
  4960. {
  4961. workers.reserve(worker);
  4962. for(int i=0; i<worker; i++)
  4963. {
  4964. workers.emplace_back(
  4965. [this]
  4966. {
  4967. std::unique_lock<std::mutex> lock(this->task_mutex);
  4968. while(true)
  4969. {
  4970. while (this->tasks.empty())
  4971. {
  4972. if (this->closed)
  4973. {
  4974. return;
  4975. }
  4976. this->cv.wait(lock);
  4977. }
  4978. auto task = this->tasks.front();
  4979. this->tasks.pop_front();
  4980. lock.unlock();
  4981. task();
  4982. lock.lock();
  4983. }
  4984. }
  4985. );
  4986. }
  4987. }
  4988. template<typename F, typename... Args>
  4989. auto ThreadPool::enqueue(F&& f, Args&& ... args)
  4990. #ifndef __cpp_lib_is_invocable
  4991. -> std::future< typename std::result_of< F( Args... ) >::type>
  4992. #else
  4993. -> std::future< typename std::invoke_result_t<F, Args...>>
  4994. #endif
  4995. {
  4996. #ifndef __cpp_lib_is_invocable
  4997. using return_type = typename std::result_of< F( Args... ) >::type;
  4998. #else
  4999. using return_type = typename std::invoke_result_t< F, Args... >;
  5000. #endif
  5001. auto task = std::make_shared<std::packaged_task<return_type()> > (
  5002. std::bind(std::forward<F>(f), std::forward<Args>(args)...)
  5003. );
  5004. auto result = task->get_future();
  5005. {
  5006. std::unique_lock<std::mutex> lock(task_mutex);
  5007. if (!closed)
  5008. {
  5009. tasks.emplace_back([task]
  5010. {
  5011. (*task)();
  5012. });
  5013. cv.notify_one();
  5014. }
  5015. }
  5016. return result;
  5017. }
  5018. ThreadPool::~ThreadPool() {
  5019. {
  5020. std::unique_lock<std::mutex> lock(task_mutex);
  5021. closed = true;
  5022. }
  5023. cv.notify_all();
  5024. for (auto && worker : workers)
  5025. {
  5026. worker.join();
  5027. }
  5028. }
  5029. #endif
  5030. enum class Stages
  5031. {
  5032. COMPUTE_BOUNDS_OF_INPUT_MESH,
  5033. REINDEXING_INPUT_MESH,
  5034. CREATE_RAYCAST_MESH,
  5035. VOXELIZING_INPUT_MESH,
  5036. BUILD_INITIAL_CONVEX_HULL,
  5037. PERFORMING_DECOMPOSITION,
  5038. INITIALIZING_CONVEX_HULLS_FOR_MERGING,
  5039. COMPUTING_COST_MATRIX,
  5040. MERGING_CONVEX_HULLS,
  5041. FINALIZING_RESULTS,
  5042. NUM_STAGES
  5043. };
  5044. class VHACDCallbacks
  5045. {
  5046. public:
  5047. virtual void ProgressUpdate(Stages stage,
  5048. double stageProgress,
  5049. const char *operation) = 0;
  5050. virtual bool IsCanceled() const = 0;
  5051. virtual ~VHACDCallbacks() = default;
  5052. };
  5053. enum class SplitAxis
  5054. {
  5055. X_AXIS_NEGATIVE,
  5056. X_AXIS_POSITIVE,
  5057. Y_AXIS_NEGATIVE,
  5058. Y_AXIS_POSITIVE,
  5059. Z_AXIS_NEGATIVE,
  5060. Z_AXIS_POSITIVE,
  5061. };
  5062. // This class represents a collection of voxels, the convex hull
  5063. // which surrounds them, and a triangle mesh representation of those voxels
  5064. class VoxelHull
  5065. {
  5066. public:
  5067. // This method constructs a new VoxelHull based on a plane split of the parent
  5068. // convex hull
  5069. VoxelHull(const VoxelHull& parent,
  5070. SplitAxis axis,
  5071. uint32_t splitLoc);
  5072. // Here we construct the initial convex hull around the
  5073. // entire voxel set
  5074. VoxelHull(Volume& voxels,
  5075. const IVHACD::Parameters &params,
  5076. VHACDCallbacks *callbacks);
  5077. ~VoxelHull() = default;
  5078. // Helper method to refresh the min/max voxel bounding region
  5079. void MinMaxVoxelRegion(const Voxel &v);
  5080. void BuildRaycastMesh();
  5081. // We now compute the convex hull relative to a triangle mesh generated
  5082. // from the voxels
  5083. void ComputeConvexHull();
  5084. // Returns true if this convex hull should be considered done
  5085. bool IsComplete();
  5086. // Convert a voxel position into it's correct double precision location
  5087. VHACD::Vect3 GetPoint(const int32_t x,
  5088. const int32_t y,
  5089. const int32_t z,
  5090. const double scale,
  5091. const VHACD::Vect3& bmin) const;
  5092. // Sees if we have already got an index for this voxel position.
  5093. // If the voxel position has already been indexed, we just return
  5094. // that index value.
  5095. // If not, then we convert it into the floating point position and
  5096. // add it to the index map
  5097. uint32_t GetVertexIndex(const VHACD::Vector3<uint32_t>& p);
  5098. // This method will convert the voxels into an actual indexed triangle mesh of boxes
  5099. // This serves two purposes.
  5100. // The primary purpose is so that when we compute a convex hull it considered all of the points
  5101. // for each voxel, not just the center point. If you don't do this, then the hulls don't fit the
  5102. // mesh accurately enough.
  5103. // The second reason we convert it into a triangle mesh is so that we can do raycasting against it
  5104. // to search for the best splitting plane fairly quickly. That algorithm will be discussed in the
  5105. // method which computes the best splitting plane.
  5106. void BuildVoxelMesh();
  5107. // Convert a single voxel position into an actual 3d box mesh comprised
  5108. // of 12 triangles
  5109. void AddVoxelBox(const Voxel &v);
  5110. // Add the triangle represented by these 3 indices into the 'box' set of vertices
  5111. // to the output mesh
  5112. void AddTri(const std::array<VHACD::Vector3<uint32_t>, 8>& box,
  5113. uint32_t i1,
  5114. uint32_t i2,
  5115. uint32_t i3);
  5116. // Here we convert from voxel space to a 3d position, index it, and add
  5117. // the triangle positions and indices for the output mesh
  5118. void AddTriangle(const VHACD::Vector3<uint32_t>& p1,
  5119. const VHACD::Vector3<uint32_t>& p2,
  5120. const VHACD::Vector3<uint32_t>& p3);
  5121. // When computing the split plane, we start by simply
  5122. // taking the midpoint of the longest side. However,
  5123. // we can also search the surface and look for the greatest
  5124. // spot of concavity and use that as the split location.
  5125. // This will make the convex decomposition more efficient
  5126. // as it will tend to cut across the greatest point of
  5127. // concavity on the surface.
  5128. SplitAxis ComputeSplitPlane(uint32_t& location);
  5129. VHACD::Vect3 GetPosition(const VHACD::Vector3<int32_t>& ip) const;
  5130. double Raycast(const VHACD::Vector3<int32_t>& p1,
  5131. const VHACD::Vector3<int32_t>& p2) const;
  5132. bool FindConcavity(uint32_t idx,
  5133. uint32_t& splitLoc);
  5134. // Finding the greatest area of concavity..
  5135. bool FindConcavityX(uint32_t& splitLoc);
  5136. // Finding the greatest area of concavity..
  5137. bool FindConcavityY(uint32_t& splitLoc);
  5138. // Finding the greatest area of concavity..
  5139. bool FindConcavityZ(uint32_t& splitLoc);
  5140. // This operation is performed in a background thread.
  5141. // It splits the voxels by a plane
  5142. void PerformPlaneSplit();
  5143. // Used only for debugging. Saves the voxelized mesh to disk
  5144. // Optionally saves the original source mesh as well for comparison
  5145. void SaveVoxelMesh(const SimpleMesh& inputMesh,
  5146. bool saveVoxelMesh,
  5147. bool saveSourceMesh);
  5148. void SaveOBJ(const char* fname,
  5149. const VoxelHull* h);
  5150. void SaveOBJ(const char* fname);
  5151. private:
  5152. void WriteOBJ(FILE* fph,
  5153. const std::vector<VHACD::Vertex>& vertices,
  5154. const std::vector<VHACD::Triangle>& indices,
  5155. uint32_t baseIndex);
  5156. public:
  5157. SplitAxis m_axis{ SplitAxis::X_AXIS_NEGATIVE };
  5158. Volume* m_voxels{ nullptr }; // The voxelized data set
  5159. double m_voxelScale{ 0 }; // Size of a single voxel
  5160. double m_voxelScaleHalf{ 0 }; // 1/2 of the size of a single voxel
  5161. VHACD::BoundsAABB m_voxelBounds;
  5162. VHACD::Vect3 m_voxelAdjust; // Minimum coordinates of the voxel space, with adjustment
  5163. uint32_t m_depth{ 0 }; // How deep in the recursion of the binary tree this hull is
  5164. uint32_t m_index{ 0 }; // Each convex hull is given a unique id to distinguish it from the others
  5165. double m_volumeError{ 0 }; // The percentage error from the convex hull volume vs. the voxel volume
  5166. double m_voxelVolume{ 0 }; // The volume of the voxels
  5167. double m_hullVolume{ 0 }; // The volume of the enclosing convex hull
  5168. std::unique_ptr<IVHACD::ConvexHull> m_convexHull{ nullptr }; // The convex hull which encloses this set of voxels.
  5169. std::vector<Voxel> m_surfaceVoxels; // The voxels which are on the surface of the source mesh.
  5170. std::vector<Voxel> m_newSurfaceVoxels; // Voxels which are on the surface as a result of a plane split
  5171. std::vector<Voxel> m_interiorVoxels; // Voxels which are part of the interior of the hull
  5172. std::unique_ptr<VoxelHull> m_hullA{ nullptr }; // hull resulting from one side of the plane split
  5173. std::unique_ptr<VoxelHull> m_hullB{ nullptr }; // hull resulting from the other side of the plane split
  5174. // Defines the coordinates this convex hull comprises within the voxel volume
  5175. // of the entire source
  5176. VHACD::Vector3<uint32_t> m_1{ 0 };
  5177. VHACD::Vector3<uint32_t> m_2{ 0 };
  5178. AABBTree m_AABBTree;
  5179. std::unordered_map<uint32_t, uint32_t> m_voxelIndexMap; // Maps from a voxel coordinate space into a vertex index space
  5180. std::vector<VHACD::Vertex> m_vertices;
  5181. std::vector<VHACD::Triangle> m_indices;
  5182. static uint32_t m_voxelHullCount;
  5183. IVHACD::Parameters m_params;
  5184. VHACDCallbacks* m_callbacks{ nullptr };
  5185. };
  5186. uint32_t VoxelHull::m_voxelHullCount = 0;
  5187. VoxelHull::VoxelHull(const VoxelHull& parent,
  5188. SplitAxis axis,
  5189. uint32_t splitLoc)
  5190. : m_axis(axis)
  5191. , m_voxels(parent.m_voxels)
  5192. , m_voxelScale(m_voxels->GetScale())
  5193. , m_voxelScaleHalf(m_voxelScale * double(0.5))
  5194. , m_voxelBounds(m_voxels->GetBounds())
  5195. , m_voxelAdjust(m_voxelBounds.GetMin() - m_voxelScaleHalf)
  5196. , m_depth(parent.m_depth + 1)
  5197. , m_index(++m_voxelHullCount)
  5198. , m_1(parent.m_1)
  5199. , m_2(parent.m_2)
  5200. , m_params(parent.m_params)
  5201. {
  5202. // Default copy the voxel region from the parent, but values will
  5203. // be adjusted next based on the split axis and location
  5204. switch ( m_axis )
  5205. {
  5206. case SplitAxis::X_AXIS_NEGATIVE:
  5207. m_2.GetX() = splitLoc;
  5208. break;
  5209. case SplitAxis::X_AXIS_POSITIVE:
  5210. m_1.GetX() = splitLoc + 1;
  5211. break;
  5212. case SplitAxis::Y_AXIS_NEGATIVE:
  5213. m_2.GetY() = splitLoc;
  5214. break;
  5215. case SplitAxis::Y_AXIS_POSITIVE:
  5216. m_1.GetY() = splitLoc + 1;
  5217. break;
  5218. case SplitAxis::Z_AXIS_NEGATIVE:
  5219. m_2.GetZ() = splitLoc;
  5220. break;
  5221. case SplitAxis::Z_AXIS_POSITIVE:
  5222. m_1.GetZ() = splitLoc + 1;
  5223. break;
  5224. }
  5225. // First, we copy all of the interior voxels from our parent
  5226. // which intersect our region
  5227. for (auto& i : parent.m_interiorVoxels)
  5228. {
  5229. VHACD::Vector3<uint32_t> v = i.GetVoxel();
  5230. if (v.CWiseAllGE(m_1) && v.CWiseAllLE(m_2))
  5231. {
  5232. bool newSurface = false;
  5233. switch ( m_axis )
  5234. {
  5235. case SplitAxis::X_AXIS_NEGATIVE:
  5236. if ( v.GetX() == splitLoc )
  5237. {
  5238. newSurface = true;
  5239. }
  5240. break;
  5241. case SplitAxis::X_AXIS_POSITIVE:
  5242. if ( v.GetX() == m_1.GetX() )
  5243. {
  5244. newSurface = true;
  5245. }
  5246. break;
  5247. case SplitAxis::Y_AXIS_NEGATIVE:
  5248. if ( v.GetY() == splitLoc )
  5249. {
  5250. newSurface = true;
  5251. }
  5252. break;
  5253. case SplitAxis::Y_AXIS_POSITIVE:
  5254. if ( v.GetY() == m_1.GetY() )
  5255. {
  5256. newSurface = true;
  5257. }
  5258. break;
  5259. case SplitAxis::Z_AXIS_NEGATIVE:
  5260. if ( v.GetZ() == splitLoc )
  5261. {
  5262. newSurface = true;
  5263. }
  5264. break;
  5265. case SplitAxis::Z_AXIS_POSITIVE:
  5266. if ( v.GetZ() == m_1.GetZ() )
  5267. {
  5268. newSurface = true;
  5269. }
  5270. break;
  5271. }
  5272. // If his interior voxels lie directly on the split plane then
  5273. // these become new surface voxels for our patch
  5274. if ( newSurface )
  5275. {
  5276. m_newSurfaceVoxels.push_back(i);
  5277. }
  5278. else
  5279. {
  5280. m_interiorVoxels.push_back(i);
  5281. }
  5282. }
  5283. }
  5284. // Next we copy all of the surface voxels which intersect our region
  5285. for (auto& i : parent.m_surfaceVoxels)
  5286. {
  5287. VHACD::Vector3<uint32_t> v = i.GetVoxel();
  5288. if (v.CWiseAllGE(m_1) && v.CWiseAllLE(m_2))
  5289. {
  5290. m_surfaceVoxels.push_back(i);
  5291. }
  5292. }
  5293. // Our parent's new surface voxels become our new surface voxels so long as they intersect our region
  5294. for (auto& i : parent.m_newSurfaceVoxels)
  5295. {
  5296. VHACD::Vector3<uint32_t> v = i.GetVoxel();
  5297. if (v.CWiseAllGE(m_1) && v.CWiseAllLE(m_2))
  5298. {
  5299. m_newSurfaceVoxels.push_back(i);
  5300. }
  5301. }
  5302. // Recompute the min-max bounding box which would be different after the split occurs
  5303. m_1 = VHACD::Vector3<uint32_t>(0x7FFFFFFF);
  5304. m_2 = VHACD::Vector3<uint32_t>(0);
  5305. for (auto& i : m_surfaceVoxels)
  5306. {
  5307. MinMaxVoxelRegion(i);
  5308. }
  5309. for (auto& i : m_newSurfaceVoxels)
  5310. {
  5311. MinMaxVoxelRegion(i);
  5312. }
  5313. for (auto& i : m_interiorVoxels)
  5314. {
  5315. MinMaxVoxelRegion(i);
  5316. }
  5317. BuildVoxelMesh();
  5318. BuildRaycastMesh(); // build a raycast mesh of the voxel mesh
  5319. ComputeConvexHull();
  5320. }
  5321. VoxelHull::VoxelHull(Volume& voxels,
  5322. const IVHACD::Parameters& params,
  5323. VHACDCallbacks* callbacks)
  5324. : m_voxels(&voxels)
  5325. , m_voxelScale(m_voxels->GetScale())
  5326. , m_voxelScaleHalf(m_voxelScale * double(0.5))
  5327. , m_voxelBounds(m_voxels->GetBounds())
  5328. , m_voxelAdjust(m_voxelBounds.GetMin() - m_voxelScaleHalf)
  5329. , m_index(++m_voxelHullCount)
  5330. // Here we get a copy of all voxels which lie on the surface mesh
  5331. , m_surfaceVoxels(m_voxels->GetSurfaceVoxels())
  5332. // Now we get a copy of all voxels which are considered part of the 'interior' of the source mesh
  5333. , m_interiorVoxels(m_voxels->GetInteriorVoxels())
  5334. , m_2(m_voxels->GetDimensions() - 1)
  5335. , m_params(params)
  5336. , m_callbacks(callbacks)
  5337. {
  5338. BuildVoxelMesh();
  5339. BuildRaycastMesh(); // build a raycast mesh of the voxel mesh
  5340. ComputeConvexHull();
  5341. }
  5342. void VoxelHull::MinMaxVoxelRegion(const Voxel& v)
  5343. {
  5344. VHACD::Vector3<uint32_t> x = v.GetVoxel();
  5345. m_1 = m_1.CWiseMin(x);
  5346. m_2 = m_2.CWiseMax(x);
  5347. }
  5348. void VoxelHull::BuildRaycastMesh()
  5349. {
  5350. // Create a raycast mesh representation of the voxelized surface mesh
  5351. if ( !m_indices.empty() )
  5352. {
  5353. m_AABBTree = AABBTree(m_vertices,
  5354. m_indices);
  5355. }
  5356. }
  5357. void VoxelHull::ComputeConvexHull()
  5358. {
  5359. if ( !m_vertices.empty() )
  5360. {
  5361. // we compute the convex hull as follows...
  5362. VHACD::QuickHull qh;
  5363. uint32_t tcount = qh.ComputeConvexHull(m_vertices,
  5364. uint32_t(m_vertices.size()));
  5365. if ( tcount )
  5366. {
  5367. m_convexHull = std::unique_ptr<IVHACD::ConvexHull>(new IVHACD::ConvexHull);
  5368. m_convexHull->m_points = qh.GetVertices();
  5369. m_convexHull->m_triangles = qh.GetIndices();
  5370. VHACD::ComputeCentroid(m_convexHull->m_points,
  5371. m_convexHull->m_triangles,
  5372. m_convexHull->m_center);
  5373. m_convexHull->m_volume = VHACD::ComputeMeshVolume(m_convexHull->m_points,
  5374. m_convexHull->m_triangles);
  5375. }
  5376. }
  5377. if ( m_convexHull )
  5378. {
  5379. m_hullVolume = m_convexHull->m_volume;
  5380. }
  5381. // This is the volume of a single voxel
  5382. double singleVoxelVolume = m_voxelScale * m_voxelScale * m_voxelScale;
  5383. size_t voxelCount = m_interiorVoxels.size() + m_newSurfaceVoxels.size() + m_surfaceVoxels.size();
  5384. m_voxelVolume = singleVoxelVolume * double(voxelCount);
  5385. double diff = fabs(m_hullVolume - m_voxelVolume);
  5386. m_volumeError = (diff * 100) / m_voxelVolume;
  5387. }
  5388. bool VoxelHull::IsComplete()
  5389. {
  5390. bool ret = false;
  5391. if ( m_convexHull == nullptr )
  5392. {
  5393. ret = true;
  5394. }
  5395. else if ( m_volumeError < m_params.m_minimumVolumePercentErrorAllowed )
  5396. {
  5397. ret = true;
  5398. }
  5399. else if ( m_depth > m_params.m_maxRecursionDepth )
  5400. {
  5401. ret = true;
  5402. }
  5403. else
  5404. {
  5405. // We compute the voxel width on all 3 axes and see if they are below the min threshold size
  5406. VHACD::Vector3<uint32_t> d = m_2 - m_1;
  5407. if ( d.GetX() <= m_params.m_minEdgeLength &&
  5408. d.GetY() <= m_params.m_minEdgeLength &&
  5409. d.GetZ() <= m_params.m_minEdgeLength )
  5410. {
  5411. ret = true;
  5412. }
  5413. }
  5414. return ret;
  5415. }
  5416. VHACD::Vect3 VoxelHull::GetPoint(const int32_t x,
  5417. const int32_t y,
  5418. const int32_t z,
  5419. const double scale,
  5420. const VHACD::Vect3& bmin) const
  5421. {
  5422. return VHACD::Vect3(x * scale + bmin.GetX(),
  5423. y * scale + bmin.GetY(),
  5424. z * scale + bmin.GetZ());
  5425. }
  5426. uint32_t VoxelHull::GetVertexIndex(const VHACD::Vector3<uint32_t>& p)
  5427. {
  5428. uint32_t ret = 0;
  5429. uint32_t address = (p.GetX() << 20) | (p.GetY() << 10) | p.GetZ();
  5430. auto found = m_voxelIndexMap.find(address);
  5431. if ( found != m_voxelIndexMap.end() )
  5432. {
  5433. ret = found->second;
  5434. }
  5435. else
  5436. {
  5437. VHACD::Vect3 vertex = GetPoint(p.GetX(),
  5438. p.GetY(),
  5439. p.GetZ(),
  5440. m_voxelScale,
  5441. m_voxelAdjust);
  5442. ret = uint32_t(m_voxelIndexMap.size());
  5443. m_voxelIndexMap[address] = ret;
  5444. m_vertices.emplace_back(vertex);
  5445. }
  5446. return ret;
  5447. }
  5448. void VoxelHull::BuildVoxelMesh()
  5449. {
  5450. // When we build the triangle mesh we do *not* need the interior voxels, only the ones
  5451. // which lie upon the logical surface of the mesh.
  5452. // Each time we perform a plane split, voxels which are along the splitting plane become
  5453. // 'new surface voxels'.
  5454. for (auto& i : m_surfaceVoxels)
  5455. {
  5456. AddVoxelBox(i);
  5457. }
  5458. for (auto& i : m_newSurfaceVoxels)
  5459. {
  5460. AddVoxelBox(i);
  5461. }
  5462. }
  5463. void VoxelHull::AddVoxelBox(const Voxel &v)
  5464. {
  5465. // The voxel position of the upper left corner of the box
  5466. VHACD::Vector3<uint32_t> bmin(v.GetX(),
  5467. v.GetY(),
  5468. v.GetZ());
  5469. // The voxel position of the lower right corner of the box
  5470. VHACD::Vector3<uint32_t> bmax(bmin.GetX() + 1,
  5471. bmin.GetY() + 1,
  5472. bmin.GetZ() + 1);
  5473. // Build the set of 8 voxel positions representing
  5474. // the coordinates of the box
  5475. std::array<VHACD::Vector3<uint32_t>, 8> box{{
  5476. { bmin.GetX(), bmin.GetY(), bmin.GetZ() },
  5477. { bmax.GetX(), bmin.GetY(), bmin.GetZ() },
  5478. { bmax.GetX(), bmax.GetY(), bmin.GetZ() },
  5479. { bmin.GetX(), bmax.GetY(), bmin.GetZ() },
  5480. { bmin.GetX(), bmin.GetY(), bmax.GetZ() },
  5481. { bmax.GetX(), bmin.GetY(), bmax.GetZ() },
  5482. { bmax.GetX(), bmax.GetY(), bmax.GetZ() },
  5483. { bmin.GetX(), bmax.GetY(), bmax.GetZ() }
  5484. }};
  5485. // Now add the 12 triangles comprising the 3d box
  5486. AddTri(box, 2, 1, 0);
  5487. AddTri(box, 3, 2, 0);
  5488. AddTri(box, 7, 2, 3);
  5489. AddTri(box, 7, 6, 2);
  5490. AddTri(box, 5, 1, 2);
  5491. AddTri(box, 5, 2, 6);
  5492. AddTri(box, 5, 4, 1);
  5493. AddTri(box, 4, 0, 1);
  5494. AddTri(box, 4, 6, 7);
  5495. AddTri(box, 4, 5, 6);
  5496. AddTri(box, 4, 7, 0);
  5497. AddTri(box, 7, 3, 0);
  5498. }
  5499. void VoxelHull::AddTri(const std::array<VHACD::Vector3<uint32_t>, 8>& box,
  5500. uint32_t i1,
  5501. uint32_t i2,
  5502. uint32_t i3)
  5503. {
  5504. AddTriangle(box[i1], box[i2], box[i3]);
  5505. }
  5506. void VoxelHull::AddTriangle(const VHACD::Vector3<uint32_t>& p1,
  5507. const VHACD::Vector3<uint32_t>& p2,
  5508. const VHACD::Vector3<uint32_t>& p3)
  5509. {
  5510. uint32_t i1 = GetVertexIndex(p1);
  5511. uint32_t i2 = GetVertexIndex(p2);
  5512. uint32_t i3 = GetVertexIndex(p3);
  5513. m_indices.emplace_back(i1, i2, i3);
  5514. }
  5515. SplitAxis VoxelHull::ComputeSplitPlane(uint32_t& location)
  5516. {
  5517. SplitAxis ret = SplitAxis::X_AXIS_NEGATIVE;
  5518. VHACD::Vector3<uint32_t> d = m_2 - m_1;
  5519. if ( d.GetX() >= d.GetY() && d.GetX() >= d.GetZ() )
  5520. {
  5521. ret = SplitAxis::X_AXIS_NEGATIVE;
  5522. location = (m_2.GetX() + 1 + m_1.GetX()) / 2;
  5523. uint32_t edgeLoc;
  5524. if ( m_params.m_findBestPlane && FindConcavityX(edgeLoc) )
  5525. {
  5526. location = edgeLoc;
  5527. }
  5528. }
  5529. else if ( d.GetY() >= d.GetX() && d.GetY() >= d.GetZ() )
  5530. {
  5531. ret = SplitAxis::Y_AXIS_NEGATIVE;
  5532. location = (m_2.GetY() + 1 + m_1.GetY()) / 2;
  5533. uint32_t edgeLoc;
  5534. if ( m_params.m_findBestPlane && FindConcavityY(edgeLoc) )
  5535. {
  5536. location = edgeLoc;
  5537. }
  5538. }
  5539. else
  5540. {
  5541. ret = SplitAxis::Z_AXIS_NEGATIVE;
  5542. location = (m_2.GetZ() + 1 + m_1.GetZ()) / 2;
  5543. uint32_t edgeLoc;
  5544. if ( m_params.m_findBestPlane && FindConcavityZ(edgeLoc) )
  5545. {
  5546. location = edgeLoc;
  5547. }
  5548. }
  5549. return ret;
  5550. }
  5551. VHACD::Vect3 VoxelHull::GetPosition(const VHACD::Vector3<int32_t>& ip) const
  5552. {
  5553. return GetPoint(ip.GetX(),
  5554. ip.GetY(),
  5555. ip.GetZ(),
  5556. m_voxelScale,
  5557. m_voxelAdjust);
  5558. }
  5559. double VoxelHull::Raycast(const VHACD::Vector3<int32_t>& p1,
  5560. const VHACD::Vector3<int32_t>& p2) const
  5561. {
  5562. double ret;
  5563. VHACD::Vect3 from = GetPosition(p1);
  5564. VHACD::Vect3 to = GetPosition(p2);
  5565. double outT;
  5566. double faceSign;
  5567. VHACD::Vect3 hitLocation;
  5568. if (m_AABBTree.TraceRay(from, to, outT, faceSign, hitLocation))
  5569. {
  5570. ret = (from - hitLocation).GetNorm();
  5571. }
  5572. else
  5573. {
  5574. ret = 0; // if it doesn't hit anything, just assign it to zero.
  5575. }
  5576. return ret;
  5577. }
  5578. bool VoxelHull::FindConcavity(uint32_t idx,
  5579. uint32_t& splitLoc)
  5580. {
  5581. bool ret = false;
  5582. int32_t d = (m_2[idx] - m_1[idx]) + 1; // The length of the getX axis in voxel space
  5583. uint32_t idx1;
  5584. uint32_t idx2;
  5585. uint32_t idx3;
  5586. switch (idx)
  5587. {
  5588. case 0: // X
  5589. idx1 = 0;
  5590. idx2 = 1;
  5591. idx3 = 2;
  5592. break;
  5593. case 1: // Y
  5594. idx1 = 1;
  5595. idx2 = 0;
  5596. idx3 = 2;
  5597. break;
  5598. case 2:
  5599. idx1 = 2;
  5600. idx2 = 1;
  5601. idx3 = 0;
  5602. break;
  5603. default:
  5604. /*
  5605. * To silence uninitialized variable warnings
  5606. */
  5607. idx1 = 0;
  5608. idx2 = 0;
  5609. idx3 = 0;
  5610. assert(0 && "findConcavity::idx must be 0, 1, or 2");
  5611. break;
  5612. }
  5613. // We will compute the edge error on the XY plane and the XZ plane
  5614. // searching for the greatest location of concavity
  5615. std::vector<double> edgeError1 = std::vector<double>(d);
  5616. std::vector<double> edgeError2 = std::vector<double>(d);
  5617. // Counter of number of voxel samples on the XY plane we have accumulated
  5618. uint32_t index1 = 0;
  5619. // Compute Edge Error on the XY plane
  5620. for (uint32_t i0 = m_1[idx1]; i0 <= m_2[idx1]; i0++)
  5621. {
  5622. double errorTotal = 0;
  5623. // We now perform a raycast from the sides inward on the XY plane to
  5624. // determine the total error (distance of the surface from the sides)
  5625. // along this getX position.
  5626. for (uint32_t i1 = m_1[idx2]; i1 <= m_2[idx2]; i1++)
  5627. {
  5628. VHACD::Vector3<int32_t> p1;
  5629. VHACD::Vector3<int32_t> p2;
  5630. switch (idx)
  5631. {
  5632. case 0:
  5633. {
  5634. p1 = VHACD::Vector3<int32_t>(i0, i1, m_1.GetZ() - 2);
  5635. p2 = VHACD::Vector3<int32_t>(i0, i1, m_2.GetZ() + 2);
  5636. break;
  5637. }
  5638. case 1:
  5639. {
  5640. p1 = VHACD::Vector3<int32_t>(i1, i0, m_1.GetZ() - 2);
  5641. p2 = VHACD::Vector3<int32_t>(i1, i0, m_2.GetZ() + 2);
  5642. break;
  5643. }
  5644. case 2:
  5645. {
  5646. p1 = VHACD::Vector3<int32_t>(m_1.GetX() - 2, i1, i0);
  5647. p2 = VHACD::Vector3<int32_t>(m_2.GetX() + 2, i1, i0);
  5648. break;
  5649. }
  5650. }
  5651. double e1 = Raycast(p1, p2);
  5652. double e2 = Raycast(p2, p1);
  5653. errorTotal = errorTotal + e1 + e2;
  5654. }
  5655. // The total amount of edge error along this voxel location
  5656. edgeError1[index1] = errorTotal;
  5657. index1++;
  5658. }
  5659. // Compute edge error along the XZ plane
  5660. uint32_t index2 = 0;
  5661. for (uint32_t i0 = m_1[idx1]; i0 <= m_2[idx1]; i0++)
  5662. {
  5663. double errorTotal = 0;
  5664. for (uint32_t i1 = m_1[idx3]; i1 <= m_2[idx3]; i1++)
  5665. {
  5666. VHACD::Vector3<int32_t> p1;
  5667. VHACD::Vector3<int32_t> p2;
  5668. switch (idx)
  5669. {
  5670. case 0:
  5671. {
  5672. p1 = VHACD::Vector3<int32_t>(i0, m_1.GetY() - 2, i1);
  5673. p2 = VHACD::Vector3<int32_t>(i0, m_2.GetY() + 2, i1);
  5674. break;
  5675. }
  5676. case 1:
  5677. {
  5678. p1 = VHACD::Vector3<int32_t>(m_1.GetX() - 2, i0, i1);
  5679. p2 = VHACD::Vector3<int32_t>(m_2.GetX() + 2, i0, i1);
  5680. break;
  5681. }
  5682. case 2:
  5683. {
  5684. p1 = VHACD::Vector3<int32_t>(i1, m_1.GetY() - 2, i0);
  5685. p2 = VHACD::Vector3<int32_t>(i1, m_2.GetY() + 2, i0);
  5686. break;
  5687. }
  5688. }
  5689. double e1 = Raycast(p1, p2); // raycast from one side to the interior
  5690. double e2 = Raycast(p2, p1); // raycast from the other side to the interior
  5691. errorTotal = errorTotal + e1 + e2;
  5692. }
  5693. edgeError2[index2] = errorTotal;
  5694. index2++;
  5695. }
  5696. // we now compute the first derivative to find the greatest spot of concavity on the XY plane
  5697. double maxDiff = 0;
  5698. uint32_t maxC = 0;
  5699. for (uint32_t x = 1; x < index1; x++)
  5700. {
  5701. if ( edgeError1[x] > 0 && edgeError1[x - 1] > 0 )
  5702. {
  5703. double diff = abs(edgeError1[x] - edgeError1[x - 1]);
  5704. if ( diff > maxDiff )
  5705. {
  5706. maxDiff = diff;
  5707. maxC = x-1;
  5708. }
  5709. }
  5710. }
  5711. // Now see if there is a greater concavity on the XZ plane
  5712. for (uint32_t x = 1; x < index2; x++)
  5713. {
  5714. if ( edgeError2[x] > 0 && edgeError2[x - 1] > 0 )
  5715. {
  5716. double diff = abs(edgeError2[x] - edgeError2[x - 1]);
  5717. if ( diff > maxDiff )
  5718. {
  5719. maxDiff = diff;
  5720. maxC = x - 1;
  5721. }
  5722. }
  5723. }
  5724. splitLoc = maxC + m_1[idx1];
  5725. // we do not allow an edge split if it is too close to the ends
  5726. if ( splitLoc > (m_1[idx1] + 4)
  5727. && splitLoc < (m_2[idx1] - 4) )
  5728. {
  5729. ret = true;
  5730. }
  5731. return ret;
  5732. }
  5733. // Finding the greatest area of concavity..
  5734. bool VoxelHull::FindConcavityX(uint32_t& splitLoc)
  5735. {
  5736. return FindConcavity(0, splitLoc);
  5737. }
  5738. // Finding the greatest area of concavity..
  5739. bool VoxelHull::FindConcavityY(uint32_t& splitLoc)
  5740. {
  5741. return FindConcavity(1, splitLoc);
  5742. }
  5743. // Finding the greatest area of concavity..
  5744. bool VoxelHull::FindConcavityZ(uint32_t &splitLoc)
  5745. {
  5746. return FindConcavity(2, splitLoc);
  5747. }
  5748. void VoxelHull::PerformPlaneSplit()
  5749. {
  5750. if ( IsComplete() )
  5751. {
  5752. }
  5753. else
  5754. {
  5755. uint32_t splitLoc;
  5756. SplitAxis axis = ComputeSplitPlane(splitLoc);
  5757. switch ( axis )
  5758. {
  5759. case SplitAxis::X_AXIS_NEGATIVE:
  5760. case SplitAxis::X_AXIS_POSITIVE:
  5761. // Split on the getX axis at this split location
  5762. m_hullA = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::X_AXIS_NEGATIVE, splitLoc));
  5763. m_hullB = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::X_AXIS_POSITIVE, splitLoc));
  5764. break;
  5765. case SplitAxis::Y_AXIS_NEGATIVE:
  5766. case SplitAxis::Y_AXIS_POSITIVE:
  5767. // Split on the 1 axis at this split location
  5768. m_hullA = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::Y_AXIS_NEGATIVE, splitLoc));
  5769. m_hullB = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::Y_AXIS_POSITIVE, splitLoc));
  5770. break;
  5771. case SplitAxis::Z_AXIS_NEGATIVE:
  5772. case SplitAxis::Z_AXIS_POSITIVE:
  5773. // Split on the getZ axis at this split location
  5774. m_hullA = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::Z_AXIS_NEGATIVE, splitLoc));
  5775. m_hullB = std::unique_ptr<VoxelHull>(new VoxelHull(*this, SplitAxis::Z_AXIS_POSITIVE, splitLoc));
  5776. break;
  5777. }
  5778. }
  5779. }
  5780. void VoxelHull::SaveVoxelMesh(const SimpleMesh &inputMesh,
  5781. bool saveVoxelMesh,
  5782. bool saveSourceMesh)
  5783. {
  5784. char scratch[512];
  5785. snprintf(scratch,
  5786. sizeof(scratch),
  5787. "voxel-mesh-%03d.obj",
  5788. m_index);
  5789. FILE *fph = fopen(scratch,
  5790. "wb");
  5791. if ( fph )
  5792. {
  5793. uint32_t baseIndex = 1;
  5794. if ( saveVoxelMesh )
  5795. {
  5796. WriteOBJ(fph,
  5797. m_vertices,
  5798. m_indices,
  5799. baseIndex);
  5800. baseIndex += uint32_t(m_vertices.size());
  5801. }
  5802. if ( saveSourceMesh )
  5803. {
  5804. WriteOBJ(fph,
  5805. inputMesh.m_vertices,
  5806. inputMesh.m_indices,
  5807. baseIndex);
  5808. }
  5809. fclose(fph);
  5810. }
  5811. }
  5812. void VoxelHull::SaveOBJ(const char* fname,
  5813. const VoxelHull* h)
  5814. {
  5815. FILE *fph = fopen(fname,"wb");
  5816. if ( fph )
  5817. {
  5818. uint32_t baseIndex = 1;
  5819. WriteOBJ(fph,
  5820. m_vertices,
  5821. m_indices,
  5822. baseIndex);
  5823. baseIndex += uint32_t(m_vertices.size());
  5824. WriteOBJ(fph,
  5825. h->m_vertices,
  5826. h->m_indices,
  5827. baseIndex);
  5828. fclose(fph);
  5829. }
  5830. }
  5831. void VoxelHull::SaveOBJ(const char *fname)
  5832. {
  5833. FILE *fph = fopen(fname, "wb");
  5834. if ( fph )
  5835. {
  5836. printf("Saving '%s' with %d vertices and %d triangles\n",
  5837. fname,
  5838. uint32_t(m_vertices.size()),
  5839. uint32_t(m_indices.size()));
  5840. WriteOBJ(fph,
  5841. m_vertices,
  5842. m_indices,
  5843. 1);
  5844. fclose(fph);
  5845. }
  5846. }
  5847. void VoxelHull::WriteOBJ(FILE* fph,
  5848. const std::vector<VHACD::Vertex>& vertices,
  5849. const std::vector<VHACD::Triangle>& indices,
  5850. uint32_t baseIndex)
  5851. {
  5852. if (!fph)
  5853. {
  5854. return;
  5855. }
  5856. for (size_t i = 0; i < vertices.size(); ++i)
  5857. {
  5858. const VHACD::Vertex& v = vertices[i];
  5859. fprintf(fph, "v %0.9f %0.9f %0.9f\n",
  5860. v.mX,
  5861. v.mY,
  5862. v.mZ);
  5863. }
  5864. for (size_t i = 0; i < indices.size(); ++i)
  5865. {
  5866. const VHACD::Triangle& t = indices[i];
  5867. fprintf(fph, "f %d %d %d\n",
  5868. t.mI0 + baseIndex,
  5869. t.mI1 + baseIndex,
  5870. t.mI2 + baseIndex);
  5871. }
  5872. }
  5873. class VHACDImpl;
  5874. // This class represents a single task to compute the volume error
  5875. // of two convex hulls combined
  5876. class CostTask
  5877. {
  5878. public:
  5879. VHACDImpl* m_this{ nullptr };
  5880. IVHACD::ConvexHull* m_hullA{ nullptr };
  5881. IVHACD::ConvexHull* m_hullB{ nullptr };
  5882. double m_concavity{ 0 }; // concavity of the two combined
  5883. std::future<void> m_future;
  5884. };
  5885. class HullPair
  5886. {
  5887. public:
  5888. HullPair() = default;
  5889. HullPair(uint32_t hullA,
  5890. uint32_t hullB,
  5891. double concavity);
  5892. bool operator<(const HullPair &h) const;
  5893. uint32_t m_hullA{ 0 };
  5894. uint32_t m_hullB{ 0 };
  5895. double m_concavity{ 0 };
  5896. };
  5897. HullPair::HullPair(uint32_t hullA,
  5898. uint32_t hullB,
  5899. double concavity)
  5900. : m_hullA(hullA)
  5901. , m_hullB(hullB)
  5902. , m_concavity(concavity)
  5903. {
  5904. }
  5905. bool HullPair::operator<(const HullPair &h) const
  5906. {
  5907. return m_concavity > h.m_concavity ? true : false;
  5908. }
  5909. // void jobCallback(void* userPtr);
  5910. class VHACDImpl : public IVHACD, public VHACDCallbacks
  5911. {
  5912. // Don't consider more than 100,000 convex hulls.
  5913. static constexpr uint32_t MaxConvexHullFragments{ 100000 };
  5914. public:
  5915. VHACDImpl() = default;
  5916. /*
  5917. * Overrides VHACD::IVHACD
  5918. */
  5919. ~VHACDImpl() override
  5920. {
  5921. Clean();
  5922. }
  5923. void Cancel() override final;
  5924. bool Compute(const float* const points,
  5925. const uint32_t countPoints,
  5926. const uint32_t* const triangles,
  5927. const uint32_t countTriangles,
  5928. const Parameters& params) override final;
  5929. bool Compute(const double* const points,
  5930. const uint32_t countPoints,
  5931. const uint32_t* const triangles,
  5932. const uint32_t countTriangles,
  5933. const Parameters& params) override final;
  5934. uint32_t GetNConvexHulls() const override final;
  5935. bool GetConvexHull(const uint32_t index,
  5936. ConvexHull& ch) const override final;
  5937. void Clean() override final; // release internally allocated memory
  5938. void Release() override final;
  5939. // Will compute the center of mass of the convex hull decomposition results and return it
  5940. // in 'centerOfMass'. Returns false if the center of mass could not be computed.
  5941. bool ComputeCenterOfMass(double centerOfMass[3]) const override final;
  5942. // In synchronous mode (non-multi-threaded) the state is always 'ready'
  5943. // In asynchronous mode, this returns true if the background thread is not still actively computing
  5944. // a new solution. In an asynchronous config the 'IsReady' call will report any update or log
  5945. // messages in the caller's current thread.
  5946. bool IsReady(void) const override final;
  5947. /**
  5948. * At the request of LegionFu : [email protected]
  5949. * This method will return which convex hull is closest to the source position.
  5950. * You can use this method to figure out, for example, which vertices in the original
  5951. * source mesh are best associated with which convex hull.
  5952. *
  5953. * @param pos : The input 3d position to test against
  5954. *
  5955. * @return : Returns which convex hull this position is closest to.
  5956. */
  5957. uint32_t findNearestConvexHull(const double pos[3],
  5958. double& distanceToHull) override final;
  5959. // private:
  5960. bool Compute(const std::vector<VHACD::Vertex>& points,
  5961. const std::vector<VHACD::Triangle>& triangles,
  5962. const Parameters& params);
  5963. // Take the source position, normalize it, and then convert it into an index position
  5964. uint32_t GetIndex(VHACD::VertexIndex& vi,
  5965. const VHACD::Vertex& p);
  5966. // This copies the input mesh while scaling the input positions
  5967. // to fit into a normalized unit cube. It also re-indexes all of the
  5968. // vertex positions in case they weren't clean coming in.
  5969. void CopyInputMesh(const std::vector<VHACD::Vertex>& points,
  5970. const std::vector<VHACD::Triangle>& triangles);
  5971. void ScaleOutputConvexHull(ConvexHull &ch);
  5972. void AddCostToPriorityQueue(CostTask& task);
  5973. void ReleaseConvexHull(ConvexHull* ch);
  5974. void PerformConvexDecomposition();
  5975. double ComputeConvexHullVolume(const ConvexHull& sm);
  5976. double ComputeVolume4(const VHACD::Vect3& a,
  5977. const VHACD::Vect3& b,
  5978. const VHACD::Vect3& c,
  5979. const VHACD::Vect3& d);
  5980. double ComputeConcavity(double volumeSeparate,
  5981. double volumeCombined,
  5982. double volumeMesh);
  5983. // See if we can compute the cost without having to actually merge convex hulls.
  5984. // If the axis aligned bounding boxes (slightly inflated) of the two convex hulls
  5985. // do not intersect, then we don't need to actually compute the merged convex hull
  5986. // volume.
  5987. bool DoFastCost(CostTask& mt);
  5988. void PerformMergeCostTask(CostTask& mt);
  5989. ConvexHull* ComputeReducedConvexHull(const ConvexHull& ch,
  5990. uint32_t maxVerts,
  5991. bool projectHullVertices);
  5992. // Take the points in convex hull A and the points in convex hull B and generate
  5993. // a new convex hull on the combined set of points.
  5994. // Once completed, we create a SimpleMesh instance to hold the triangle mesh
  5995. // and we compute an inflated AABB for it.
  5996. ConvexHull* ComputeCombinedConvexHull(const ConvexHull& sm1,
  5997. const ConvexHull& sm2);
  5998. ConvexHull* GetHull(uint32_t index);
  5999. bool RemoveHull(uint32_t index);
  6000. ConvexHull* CopyConvexHull(const ConvexHull& source);
  6001. const char* GetStageName(Stages stage) const;
  6002. /*
  6003. * Overrides VHACD::VHACDCallbacks
  6004. */
  6005. void ProgressUpdate(Stages stage,
  6006. double stageProgress,
  6007. const char* operation) override final;
  6008. bool IsCanceled() const override final;
  6009. std::atomic<bool> m_canceled{ false };
  6010. Parameters m_params; // Convex decomposition parameters
  6011. std::vector<IVHACD::ConvexHull*> m_convexHulls; // Finalized convex hulls
  6012. std::vector<std::unique_ptr<VoxelHull>> m_voxelHulls; // completed voxel hulls
  6013. std::vector<std::unique_ptr<VoxelHull>> m_pendingHulls;
  6014. std::vector<std::unique_ptr<AABBTree>> m_trees;
  6015. VHACD::AABBTree m_AABBTree;
  6016. VHACD::Volume m_voxelize;
  6017. VHACD::Vect3 m_center;
  6018. double m_scale{ double(1.0) };
  6019. double m_recipScale{ double(1.0) };
  6020. SimpleMesh m_inputMesh; // re-indexed and normalized input mesh
  6021. std::vector<VHACD::Vertex> m_vertices;
  6022. std::vector<VHACD::Triangle> m_indices;
  6023. double m_overallHullVolume{ double(0.0) };
  6024. double m_voxelScale{ double(0.0) };
  6025. double m_voxelHalfScale{ double(0.0) };
  6026. VHACD::Vect3 m_voxelBmin;
  6027. VHACD::Vect3 m_voxelBmax;
  6028. uint32_t m_meshId{ 0 };
  6029. std::priority_queue<HullPair> m_hullPairQueue;
  6030. #if !VHACD_DISABLE_THREADING
  6031. std::unique_ptr<ThreadPool> m_threadPool{ nullptr };
  6032. #endif
  6033. std::unordered_map<uint32_t, IVHACD::ConvexHull*> m_hulls;
  6034. double m_overallProgress{ double(0.0) };
  6035. double m_stageProgress{ double(0.0) };
  6036. double m_operationProgress{ double(0.0) };
  6037. };
  6038. void VHACDImpl::Cancel()
  6039. {
  6040. m_canceled = true;
  6041. }
  6042. bool VHACDImpl::Compute(const float* const points,
  6043. const uint32_t countPoints,
  6044. const uint32_t* const triangles,
  6045. const uint32_t countTriangles,
  6046. const Parameters& params)
  6047. {
  6048. std::vector<VHACD::Vertex> v;
  6049. v.reserve(countPoints);
  6050. for (uint32_t i = 0; i < countPoints; ++i)
  6051. {
  6052. v.emplace_back(points[i * 3 + 0],
  6053. points[i * 3 + 1],
  6054. points[i * 3 + 2]);
  6055. }
  6056. std::vector<VHACD::Triangle> t;
  6057. t.reserve(countTriangles);
  6058. for (uint32_t i = 0; i < countTriangles; ++i)
  6059. {
  6060. t.emplace_back(triangles[i * 3 + 0],
  6061. triangles[i * 3 + 1],
  6062. triangles[i * 3 + 2]);
  6063. }
  6064. return Compute(v, t, params);
  6065. }
  6066. bool VHACDImpl::Compute(const double* const points,
  6067. const uint32_t countPoints,
  6068. const uint32_t* const triangles,
  6069. const uint32_t countTriangles,
  6070. const Parameters& params)
  6071. {
  6072. std::vector<VHACD::Vertex> v;
  6073. v.reserve(countPoints);
  6074. for (uint32_t i = 0; i < countPoints; ++i)
  6075. {
  6076. v.emplace_back(points[i * 3 + 0],
  6077. points[i * 3 + 1],
  6078. points[i * 3 + 2]);
  6079. }
  6080. std::vector<VHACD::Triangle> t;
  6081. t.reserve(countTriangles);
  6082. for (uint32_t i = 0; i < countTriangles; ++i)
  6083. {
  6084. t.emplace_back(triangles[i * 3 + 0],
  6085. triangles[i * 3 + 1],
  6086. triangles[i * 3 + 2]);
  6087. }
  6088. return Compute(v, t, params);
  6089. }
  6090. uint32_t VHACDImpl::GetNConvexHulls() const
  6091. {
  6092. return uint32_t(m_convexHulls.size());
  6093. }
  6094. bool VHACDImpl::GetConvexHull(const uint32_t index,
  6095. ConvexHull& ch) const
  6096. {
  6097. bool ret = false;
  6098. if ( index < uint32_t(m_convexHulls.size() ))
  6099. {
  6100. ch = *m_convexHulls[index];
  6101. ret = true;
  6102. }
  6103. return ret;
  6104. }
  6105. void VHACDImpl::Clean()
  6106. {
  6107. #if !VHACD_DISABLE_THREADING
  6108. m_threadPool = nullptr;
  6109. #endif
  6110. m_trees.clear();
  6111. for (auto& ch : m_convexHulls)
  6112. {
  6113. ReleaseConvexHull(ch);
  6114. }
  6115. m_convexHulls.clear();
  6116. for (auto& ch : m_hulls)
  6117. {
  6118. ReleaseConvexHull(ch.second);
  6119. }
  6120. m_hulls.clear();
  6121. m_voxelHulls.clear();
  6122. m_pendingHulls.clear();
  6123. m_vertices.clear();
  6124. m_indices.clear();
  6125. }
  6126. void VHACDImpl::Release()
  6127. {
  6128. delete this;
  6129. }
  6130. bool VHACDImpl::ComputeCenterOfMass(double centerOfMass[3]) const
  6131. {
  6132. bool ret = false;
  6133. return ret;
  6134. }
  6135. bool VHACDImpl::IsReady() const
  6136. {
  6137. return true;
  6138. }
  6139. uint32_t VHACDImpl::findNearestConvexHull(const double pos[3],
  6140. double& distanceToHull)
  6141. {
  6142. uint32_t ret = 0; // The default return code is zero
  6143. uint32_t hullCount = GetNConvexHulls();
  6144. distanceToHull = 0;
  6145. // First, make sure that we have valid and completed results
  6146. if ( hullCount )
  6147. {
  6148. // See if we already have AABB trees created for each convex hull
  6149. if ( m_trees.empty() )
  6150. {
  6151. // For each convex hull, we generate an AABB tree for fast closest point queries
  6152. for (uint32_t i = 0; i < hullCount; i++)
  6153. {
  6154. VHACD::IVHACD::ConvexHull ch;
  6155. GetConvexHull(i,ch);
  6156. // Pass the triangle mesh to create an AABB tree instance based on it.
  6157. m_trees.emplace_back(new AABBTree(ch.m_points,
  6158. ch.m_triangles));
  6159. }
  6160. }
  6161. // We now compute the closest point to each convex hull and save the nearest one
  6162. double closest = 1e99;
  6163. for (uint32_t i = 0; i < hullCount; i++)
  6164. {
  6165. std::unique_ptr<AABBTree>& t = m_trees[i];
  6166. if ( t )
  6167. {
  6168. VHACD::Vect3 closestPoint;
  6169. VHACD::Vect3 position(pos[0],
  6170. pos[1],
  6171. pos[2]);
  6172. if ( t->GetClosestPointWithinDistance(position, 1e99, closestPoint))
  6173. {
  6174. VHACD::Vect3 d = position - closestPoint;
  6175. double distanceSquared = d.GetNormSquared();
  6176. if ( distanceSquared < closest )
  6177. {
  6178. closest = distanceSquared;
  6179. ret = i;
  6180. }
  6181. }
  6182. }
  6183. }
  6184. distanceToHull = sqrt(closest); // compute the distance to the nearest convex hull
  6185. }
  6186. return ret;
  6187. }
  6188. bool VHACDImpl::Compute(const std::vector<VHACD::Vertex>& points,
  6189. const std::vector<VHACD::Triangle>& triangles,
  6190. const Parameters& params)
  6191. {
  6192. bool ret = false;
  6193. m_params = params;
  6194. m_canceled = false;
  6195. Clean(); // release any previous results
  6196. #if !VHACD_DISABLE_THREADING
  6197. if ( m_params.m_asyncACD )
  6198. {
  6199. m_threadPool = std::unique_ptr<ThreadPool>(new ThreadPool(8));
  6200. }
  6201. #endif
  6202. CopyInputMesh(points,
  6203. triangles);
  6204. if ( !m_canceled )
  6205. {
  6206. // We now recursively perform convex decomposition until complete
  6207. PerformConvexDecomposition();
  6208. }
  6209. if ( m_canceled )
  6210. {
  6211. Clean();
  6212. ret = false;
  6213. if ( m_params.m_logger )
  6214. {
  6215. m_params.m_logger->Log("VHACD operation canceled before it was complete.");
  6216. }
  6217. }
  6218. else
  6219. {
  6220. ret = true;
  6221. }
  6222. #if !VHACD_DISABLE_THREADING
  6223. m_threadPool = nullptr;
  6224. #endif
  6225. return ret;
  6226. }
  6227. uint32_t VHACDImpl::GetIndex(VHACD::VertexIndex& vi,
  6228. const VHACD::Vertex& p)
  6229. {
  6230. VHACD::Vect3 pos = (VHACD::Vect3(p) - m_center) * m_recipScale;
  6231. bool newPos;
  6232. uint32_t ret = vi.GetIndex(pos,
  6233. newPos);
  6234. return ret;
  6235. }
  6236. void VHACDImpl::CopyInputMesh(const std::vector<VHACD::Vertex>& points,
  6237. const std::vector<VHACD::Triangle>& triangles)
  6238. {
  6239. m_vertices.clear();
  6240. m_indices.clear();
  6241. m_indices.reserve(triangles.size());
  6242. // First we must find the bounding box of this input vertices and normalize them into a unit-cube
  6243. VHACD::Vect3 bmin( FLT_MAX);
  6244. VHACD::Vect3 bmax(-FLT_MAX);
  6245. ProgressUpdate(Stages::COMPUTE_BOUNDS_OF_INPUT_MESH,
  6246. 0,
  6247. "ComputingBounds");
  6248. for (uint32_t i = 0; i < points.size(); i++)
  6249. {
  6250. const VHACD::Vertex& p = points[i];
  6251. bmin = bmin.CWiseMin(p);
  6252. bmax = bmax.CWiseMax(p);
  6253. }
  6254. ProgressUpdate(Stages::COMPUTE_BOUNDS_OF_INPUT_MESH,
  6255. 100,
  6256. "ComputingBounds");
  6257. m_center = (bmax + bmin) * double(0.5);
  6258. VHACD::Vect3 scale = bmax - bmin;
  6259. m_scale = scale.MaxCoeff();
  6260. m_recipScale = m_scale > double(0.0) ? double(1.0) / m_scale : double(0.0);
  6261. {
  6262. VHACD::VertexIndex vi = VHACD::VertexIndex(double(0.001), false);
  6263. uint32_t dcount = 0;
  6264. for (uint32_t i = 0; i < triangles.size() && !m_canceled; ++i)
  6265. {
  6266. const VHACD::Triangle& t = triangles[i];
  6267. const VHACD::Vertex& p1 = points[t.mI0];
  6268. const VHACD::Vertex& p2 = points[t.mI1];
  6269. const VHACD::Vertex& p3 = points[t.mI2];
  6270. uint32_t i1 = GetIndex(vi, p1);
  6271. uint32_t i2 = GetIndex(vi, p2);
  6272. uint32_t i3 = GetIndex(vi, p3);
  6273. if ( i1 == i2 || i1 == i3 || i2 == i3 )
  6274. {
  6275. dcount++;
  6276. }
  6277. else
  6278. {
  6279. m_indices.emplace_back(i1, i2, i3);
  6280. }
  6281. }
  6282. if ( dcount )
  6283. {
  6284. if ( m_params.m_logger )
  6285. {
  6286. char scratch[512];
  6287. snprintf(scratch,
  6288. sizeof(scratch),
  6289. "Skipped %d degenerate triangles", dcount);
  6290. m_params.m_logger->Log(scratch);
  6291. }
  6292. }
  6293. m_vertices = vi.TakeVertices();
  6294. }
  6295. // Create the raycast mesh
  6296. if ( !m_canceled )
  6297. {
  6298. ProgressUpdate(Stages::CREATE_RAYCAST_MESH,
  6299. 0,
  6300. "Building RaycastMesh");
  6301. m_AABBTree = VHACD::AABBTree(m_vertices,
  6302. m_indices);
  6303. ProgressUpdate(Stages::CREATE_RAYCAST_MESH,
  6304. 100,
  6305. "RaycastMesh completed");
  6306. }
  6307. if ( !m_canceled )
  6308. {
  6309. ProgressUpdate(Stages::VOXELIZING_INPUT_MESH,
  6310. 0,
  6311. "Voxelizing Input Mesh");
  6312. m_voxelize = VHACD::Volume();
  6313. m_voxelize.Voxelize(m_vertices,
  6314. m_indices,
  6315. m_params.m_resolution,
  6316. m_params.m_fillMode,
  6317. m_AABBTree);
  6318. m_voxelScale = m_voxelize.GetScale();
  6319. m_voxelHalfScale = m_voxelScale * double(0.5);
  6320. m_voxelBmin = m_voxelize.GetBounds().GetMin();
  6321. m_voxelBmax = m_voxelize.GetBounds().GetMax();
  6322. ProgressUpdate(Stages::VOXELIZING_INPUT_MESH,
  6323. 100,
  6324. "Voxelization complete");
  6325. }
  6326. m_inputMesh.m_vertices = m_vertices;
  6327. m_inputMesh.m_indices = m_indices;
  6328. if ( !m_canceled )
  6329. {
  6330. ProgressUpdate(Stages::BUILD_INITIAL_CONVEX_HULL,
  6331. 0,
  6332. "Build initial ConvexHull");
  6333. std::unique_ptr<VoxelHull> vh = std::unique_ptr<VoxelHull>(new VoxelHull(m_voxelize,
  6334. m_params,
  6335. this));
  6336. if ( vh->m_convexHull )
  6337. {
  6338. m_overallHullVolume = vh->m_convexHull->m_volume;
  6339. }
  6340. m_pendingHulls.push_back(std::move(vh));
  6341. ProgressUpdate(Stages::BUILD_INITIAL_CONVEX_HULL,
  6342. 100,
  6343. "Initial ConvexHull complete");
  6344. }
  6345. }
  6346. void VHACDImpl::ScaleOutputConvexHull(ConvexHull& ch)
  6347. {
  6348. for (uint32_t i = 0; i < ch.m_points.size(); i++)
  6349. {
  6350. VHACD::Vect3 p = ch.m_points[i];
  6351. p = (p * m_scale) + m_center;
  6352. ch.m_points[i] = p;
  6353. }
  6354. ch.m_volume = ComputeConvexHullVolume(ch); // get the combined volume
  6355. VHACD::BoundsAABB b(ch.m_points);
  6356. ch.mBmin = b.GetMin();
  6357. ch.mBmax = b.GetMax();
  6358. ComputeCentroid(ch.m_points,
  6359. ch.m_triangles,
  6360. ch.m_center);
  6361. }
  6362. void VHACDImpl::AddCostToPriorityQueue(CostTask& task)
  6363. {
  6364. HullPair hp(task.m_hullA->m_meshId,
  6365. task.m_hullB->m_meshId,
  6366. task.m_concavity);
  6367. m_hullPairQueue.push(hp);
  6368. }
  6369. void VHACDImpl::ReleaseConvexHull(ConvexHull* ch)
  6370. {
  6371. if ( ch )
  6372. {
  6373. delete ch;
  6374. }
  6375. }
  6376. void jobCallback(std::unique_ptr<VoxelHull>& userPtr)
  6377. {
  6378. userPtr->PerformPlaneSplit();
  6379. }
  6380. void computeMergeCostTask(CostTask& ptr)
  6381. {
  6382. ptr.m_this->PerformMergeCostTask(ptr);
  6383. }
  6384. void VHACDImpl::PerformConvexDecomposition()
  6385. {
  6386. {
  6387. ScopedTime st("Convex Decomposition",
  6388. m_params.m_logger);
  6389. double maxHulls = pow(2, m_params.m_maxRecursionDepth);
  6390. // We recursively split convex hulls until we can
  6391. // no longer recurse further.
  6392. Timer t;
  6393. while ( !m_pendingHulls.empty() && !m_canceled )
  6394. {
  6395. size_t count = m_pendingHulls.size() + m_voxelHulls.size();
  6396. double e = t.PeekElapsedSeconds();
  6397. if ( e >= double(0.1) )
  6398. {
  6399. t.Reset();
  6400. double stageProgress = (double(count) * double(100.0)) / maxHulls;
  6401. ProgressUpdate(Stages::PERFORMING_DECOMPOSITION,
  6402. stageProgress,
  6403. "Performing recursive decomposition of convex hulls");
  6404. }
  6405. // First we make a copy of the hulls we are processing
  6406. std::vector<std::unique_ptr<VoxelHull>> oldList = std::move(m_pendingHulls);
  6407. // For each hull we want to split, we either
  6408. // immediately perform the plane split or we post it as
  6409. // a job to be performed in a background thread
  6410. std::vector<std::future<void>> futures(oldList.size());
  6411. uint32_t futureCount = 0;
  6412. for (auto& i : oldList)
  6413. {
  6414. if ( i->IsComplete() || count > MaxConvexHullFragments )
  6415. {
  6416. }
  6417. else
  6418. {
  6419. #if !VHACD_DISABLE_THREADING
  6420. if ( m_threadPool )
  6421. {
  6422. futures[futureCount] = m_threadPool->enqueue([&i]
  6423. {
  6424. jobCallback(i);
  6425. });
  6426. futureCount++;
  6427. }
  6428. else
  6429. #endif
  6430. {
  6431. i->PerformPlaneSplit();
  6432. }
  6433. }
  6434. }
  6435. // Wait for any outstanding jobs to complete in the background threads
  6436. if ( futureCount )
  6437. {
  6438. for (uint32_t i = 0; i < futureCount; i++)
  6439. {
  6440. futures[i].get();
  6441. }
  6442. }
  6443. // Now, we rebuild the pending convex hulls list by
  6444. // adding the two children to the output list if
  6445. // we need to recurse them further
  6446. for (auto& vh : oldList)
  6447. {
  6448. if ( vh->IsComplete() || count > MaxConvexHullFragments )
  6449. {
  6450. if ( vh->m_convexHull )
  6451. {
  6452. m_voxelHulls.push_back(std::move(vh));
  6453. }
  6454. }
  6455. else
  6456. {
  6457. if ( vh->m_hullA )
  6458. {
  6459. m_pendingHulls.push_back(std::move(vh->m_hullA));
  6460. }
  6461. if ( vh->m_hullB )
  6462. {
  6463. m_pendingHulls.push_back(std::move(vh->m_hullB));
  6464. }
  6465. }
  6466. }
  6467. }
  6468. }
  6469. if ( !m_canceled )
  6470. {
  6471. // Give each convex hull a unique guid
  6472. m_meshId = 0;
  6473. m_hulls.clear();
  6474. // Build the convex hull id map
  6475. std::vector<ConvexHull*> hulls;
  6476. ProgressUpdate(Stages::INITIALIZING_CONVEX_HULLS_FOR_MERGING,
  6477. 0,
  6478. "Initializing ConvexHulls");
  6479. for (auto& vh : m_voxelHulls)
  6480. {
  6481. if ( m_canceled )
  6482. {
  6483. break;
  6484. }
  6485. ConvexHull* ch = CopyConvexHull(*vh->m_convexHull);
  6486. m_meshId++;
  6487. ch->m_meshId = m_meshId;
  6488. m_hulls[m_meshId] = ch;
  6489. // Compute the volume of the convex hull
  6490. ch->m_volume = ComputeConvexHullVolume(*ch);
  6491. // Compute the AABB of the convex hull
  6492. VHACD::BoundsAABB b = VHACD::BoundsAABB(ch->m_points).Inflate(double(0.1));
  6493. ch->mBmin = b.GetMin();
  6494. ch->mBmax = b.GetMax();
  6495. ComputeCentroid(ch->m_points,
  6496. ch->m_triangles,
  6497. ch->m_center);
  6498. hulls.push_back(ch);
  6499. }
  6500. ProgressUpdate(Stages::INITIALIZING_CONVEX_HULLS_FOR_MERGING,
  6501. 100,
  6502. "ConvexHull initialization complete");
  6503. m_voxelHulls.clear();
  6504. // here we merge convex hulls as needed until the match the
  6505. // desired maximum hull count.
  6506. size_t hullCount = hulls.size();
  6507. if ( hullCount > m_params.m_maxConvexHulls && !m_canceled)
  6508. {
  6509. size_t costMatrixSize = ((hullCount * hullCount) - hullCount) >> 1;
  6510. std::vector<CostTask> tasks;
  6511. tasks.reserve(costMatrixSize);
  6512. ScopedTime st("Computing the Cost Matrix",
  6513. m_params.m_logger);
  6514. // First thing we need to do is compute the cost matrix
  6515. // This is computed as the volume error of any two convex hulls
  6516. // combined
  6517. ProgressUpdate(Stages::COMPUTING_COST_MATRIX,
  6518. 0,
  6519. "Computing Hull Merge Cost Matrix");
  6520. for (size_t i = 1; i < hullCount && !m_canceled; i++)
  6521. {
  6522. ConvexHull* chA = hulls[i];
  6523. for (size_t j = 0; j < i && !m_canceled; j++)
  6524. {
  6525. ConvexHull* chB = hulls[j];
  6526. CostTask ct;
  6527. ct.m_hullA = chA;
  6528. ct.m_hullB = chB;
  6529. ct.m_this = this;
  6530. if ( DoFastCost(ct) )
  6531. {
  6532. }
  6533. else
  6534. {
  6535. tasks.push_back(std::move(ct));
  6536. CostTask* task = &tasks.back();
  6537. #if !VHACD_DISABLE_THREADING
  6538. if ( m_threadPool )
  6539. {
  6540. task->m_future = m_threadPool->enqueue([task]
  6541. {
  6542. computeMergeCostTask(*task);
  6543. });
  6544. }
  6545. #endif
  6546. }
  6547. }
  6548. }
  6549. if ( !m_canceled )
  6550. {
  6551. #if !VHACD_DISABLE_THREADING
  6552. if ( m_threadPool )
  6553. {
  6554. for (CostTask& task : tasks)
  6555. {
  6556. task.m_future.get();
  6557. }
  6558. for (CostTask& task : tasks)
  6559. {
  6560. AddCostToPriorityQueue(task);
  6561. }
  6562. }
  6563. else
  6564. #endif
  6565. {
  6566. for (CostTask& task : tasks)
  6567. {
  6568. PerformMergeCostTask(task);
  6569. AddCostToPriorityQueue(task);
  6570. }
  6571. }
  6572. ProgressUpdate(Stages::COMPUTING_COST_MATRIX,
  6573. 100,
  6574. "Finished cost matrix");
  6575. }
  6576. if ( !m_canceled )
  6577. {
  6578. ScopedTime stMerging("Merging Convex Hulls",
  6579. m_params.m_logger);
  6580. Timer t;
  6581. // Now that we know the cost to merge each hull, we can begin merging them.
  6582. bool cancel = false;
  6583. uint32_t maxMergeCount = uint32_t(m_hulls.size()) - m_params.m_maxConvexHulls;
  6584. uint32_t startCount = uint32_t(m_hulls.size());
  6585. while ( !cancel
  6586. && m_hulls.size() > m_params.m_maxConvexHulls
  6587. && !m_hullPairQueue.empty()
  6588. && !m_canceled)
  6589. {
  6590. double e = t.PeekElapsedSeconds();
  6591. if ( e >= double(0.1) )
  6592. {
  6593. t.Reset();
  6594. uint32_t hullsProcessed = startCount - uint32_t(m_hulls.size() );
  6595. double stageProgress = double(hullsProcessed * 100) / double(maxMergeCount);
  6596. ProgressUpdate(Stages::MERGING_CONVEX_HULLS,
  6597. stageProgress,
  6598. "Merging Convex Hulls");
  6599. }
  6600. HullPair hp = m_hullPairQueue.top();
  6601. m_hullPairQueue.pop();
  6602. // It is entirely possible that the hull pair queue can
  6603. // have references to convex hulls that are no longer valid
  6604. // because they were previously merged. So we check for this
  6605. // and if either hull referenced in this pair no longer
  6606. // exists, then we skip it.
  6607. // Look up this pair of hulls by ID
  6608. ConvexHull* ch1 = GetHull(hp.m_hullA);
  6609. ConvexHull* ch2 = GetHull(hp.m_hullB);
  6610. // If both hulls are still valid, then we merge them, delete the old
  6611. // two hulls and recompute the cost matrix for the new combined hull
  6612. // we have created
  6613. if ( ch1 && ch2 )
  6614. {
  6615. // This is the convex hull which results from combining the
  6616. // vertices in the two source hulls
  6617. ConvexHull* combinedHull = ComputeCombinedConvexHull(*ch1,
  6618. *ch2);
  6619. // The two old convex hulls are going to get removed
  6620. RemoveHull(hp.m_hullA);
  6621. RemoveHull(hp.m_hullB);
  6622. m_meshId++;
  6623. combinedHull->m_meshId = m_meshId;
  6624. tasks.clear();
  6625. tasks.reserve(m_hulls.size());
  6626. // Compute the cost between this new merged hull
  6627. // and all existing convex hulls and then
  6628. // add that to the priority queue
  6629. for (auto& i : m_hulls)
  6630. {
  6631. if ( m_canceled )
  6632. {
  6633. break;
  6634. }
  6635. ConvexHull* secondHull = i.second;
  6636. CostTask ct;
  6637. ct.m_hullA = combinedHull;
  6638. ct.m_hullB = secondHull;
  6639. ct.m_this = this;
  6640. if ( DoFastCost(ct) )
  6641. {
  6642. }
  6643. else
  6644. {
  6645. tasks.push_back(std::move(ct));
  6646. }
  6647. }
  6648. m_hulls[combinedHull->m_meshId] = combinedHull;
  6649. // See how many merge cost tasks were posted
  6650. // If there are 8 or more and we are running asynchronously, then do them that way.
  6651. #if !VHACD_DISABLE_THREADING
  6652. if ( m_threadPool && tasks.size() >= 2)
  6653. {
  6654. for (CostTask& task : tasks)
  6655. {
  6656. task.m_future = m_threadPool->enqueue([&task]
  6657. {
  6658. computeMergeCostTask(task);
  6659. });
  6660. }
  6661. for (CostTask& task : tasks)
  6662. {
  6663. task.m_future.get();
  6664. }
  6665. }
  6666. else
  6667. #endif
  6668. {
  6669. for (CostTask& task : tasks)
  6670. {
  6671. PerformMergeCostTask(task);
  6672. }
  6673. }
  6674. for (CostTask& task : tasks)
  6675. {
  6676. AddCostToPriorityQueue(task);
  6677. }
  6678. }
  6679. }
  6680. // Ok...once we are done, we copy the results!
  6681. m_meshId -= 0;
  6682. ProgressUpdate(Stages::FINALIZING_RESULTS,
  6683. 0,
  6684. "Finalizing results");
  6685. for (auto& i : m_hulls)
  6686. {
  6687. if ( m_canceled )
  6688. {
  6689. break;
  6690. }
  6691. ConvexHull* ch = i.second;
  6692. // We now must reduce the convex hull
  6693. if ( ch->m_points.size() > m_params.m_maxNumVerticesPerCH || m_params.m_shrinkWrap)
  6694. {
  6695. ConvexHull* reduce = ComputeReducedConvexHull(*ch,
  6696. m_params.m_maxNumVerticesPerCH,
  6697. m_params.m_shrinkWrap);
  6698. ReleaseConvexHull(ch);
  6699. ch = reduce;
  6700. }
  6701. ScaleOutputConvexHull(*ch);
  6702. ch->m_meshId = m_meshId;
  6703. m_meshId++;
  6704. m_convexHulls.push_back(ch);
  6705. }
  6706. m_hulls.clear(); // since the hulls were moved into the output list, we don't need to delete them from this container
  6707. ProgressUpdate(Stages::FINALIZING_RESULTS,
  6708. 100,
  6709. "Finalized results complete");
  6710. }
  6711. }
  6712. else
  6713. {
  6714. ProgressUpdate(Stages::FINALIZING_RESULTS,
  6715. 0,
  6716. "Finalizing results");
  6717. m_meshId = 0;
  6718. for (auto& ch : hulls)
  6719. {
  6720. // We now must reduce the convex hull
  6721. if ( ch->m_points.size() > m_params.m_maxNumVerticesPerCH || m_params.m_shrinkWrap )
  6722. {
  6723. ConvexHull* reduce = ComputeReducedConvexHull(*ch,
  6724. m_params.m_maxNumVerticesPerCH,
  6725. m_params.m_shrinkWrap);
  6726. ReleaseConvexHull(ch);
  6727. ch = reduce;
  6728. }
  6729. ScaleOutputConvexHull(*ch);
  6730. ch->m_meshId = m_meshId;
  6731. m_meshId++;
  6732. m_convexHulls.push_back(ch);
  6733. }
  6734. m_hulls.clear();
  6735. ProgressUpdate(Stages::FINALIZING_RESULTS,
  6736. 100,
  6737. "Finalized results");
  6738. }
  6739. }
  6740. }
  6741. double VHACDImpl::ComputeConvexHullVolume(const ConvexHull& sm)
  6742. {
  6743. double totalVolume = 0;
  6744. VHACD::Vect3 bary(0, 0, 0);
  6745. for (uint32_t i = 0; i < sm.m_points.size(); i++)
  6746. {
  6747. VHACD::Vect3 p(sm.m_points[i]);
  6748. bary += p;
  6749. }
  6750. bary /= double(sm.m_points.size());
  6751. for (uint32_t i = 0; i < sm.m_triangles.size(); i++)
  6752. {
  6753. uint32_t i1 = sm.m_triangles[i].mI0;
  6754. uint32_t i2 = sm.m_triangles[i].mI1;
  6755. uint32_t i3 = sm.m_triangles[i].mI2;
  6756. VHACD::Vect3 ver0(sm.m_points[i1]);
  6757. VHACD::Vect3 ver1(sm.m_points[i2]);
  6758. VHACD::Vect3 ver2(sm.m_points[i3]);
  6759. totalVolume += ComputeVolume4(ver0,
  6760. ver1,
  6761. ver2,
  6762. bary);
  6763. }
  6764. totalVolume = totalVolume / double(6.0);
  6765. return totalVolume;
  6766. }
  6767. double VHACDImpl::ComputeVolume4(const VHACD::Vect3& a,
  6768. const VHACD::Vect3& b,
  6769. const VHACD::Vect3& c,
  6770. const VHACD::Vect3& d)
  6771. {
  6772. VHACD::Vect3 ad = a - d;
  6773. VHACD::Vect3 bd = b - d;
  6774. VHACD::Vect3 cd = c - d;
  6775. VHACD::Vect3 bcd = bd.Cross(cd);
  6776. double dot = ad.Dot(bcd);
  6777. return dot;
  6778. }
  6779. double VHACDImpl::ComputeConcavity(double volumeSeparate,
  6780. double volumeCombined,
  6781. double volumeMesh)
  6782. {
  6783. return fabs(volumeSeparate - volumeCombined) / volumeMesh;
  6784. }
  6785. bool VHACDImpl::DoFastCost(CostTask& mt)
  6786. {
  6787. bool ret = false;
  6788. ConvexHull* ch1 = mt.m_hullA;
  6789. ConvexHull* ch2 = mt.m_hullB;
  6790. VHACD::BoundsAABB ch1b(ch1->mBmin,
  6791. ch1->mBmax);
  6792. VHACD::BoundsAABB ch2b(ch2->mBmin,
  6793. ch2->mBmax);
  6794. if (!ch1b.Intersects(ch2b))
  6795. {
  6796. VHACD::BoundsAABB b = ch1b.Union(ch2b);
  6797. double combinedVolume = b.Volume();
  6798. double concavity = ComputeConcavity(ch1->m_volume + ch2->m_volume,
  6799. combinedVolume,
  6800. m_overallHullVolume);
  6801. HullPair hp(ch1->m_meshId,
  6802. ch2->m_meshId,
  6803. concavity);
  6804. m_hullPairQueue.push(hp);
  6805. ret = true;
  6806. }
  6807. return ret;
  6808. }
  6809. void VHACDImpl::PerformMergeCostTask(CostTask& mt)
  6810. {
  6811. ConvexHull* ch1 = mt.m_hullA;
  6812. ConvexHull* ch2 = mt.m_hullB;
  6813. double volume1 = ch1->m_volume;
  6814. double volume2 = ch2->m_volume;
  6815. ConvexHull* combined = ComputeCombinedConvexHull(*ch1,
  6816. *ch2); // Build the combined convex hull
  6817. double combinedVolume = ComputeConvexHullVolume(*combined); // get the combined volume
  6818. mt.m_concavity = ComputeConcavity(volume1 + volume2,
  6819. combinedVolume,
  6820. m_overallHullVolume);
  6821. ReleaseConvexHull(combined);
  6822. }
  6823. IVHACD::ConvexHull* VHACDImpl::ComputeReducedConvexHull(const ConvexHull& ch,
  6824. uint32_t maxVerts,
  6825. bool projectHullVertices)
  6826. {
  6827. SimpleMesh sourceConvexHull;
  6828. sourceConvexHull.m_vertices = ch.m_points;
  6829. sourceConvexHull.m_indices = ch.m_triangles;
  6830. ShrinkWrap(sourceConvexHull,
  6831. m_AABBTree,
  6832. maxVerts,
  6833. m_voxelScale,
  6834. projectHullVertices);
  6835. ConvexHull *ret = new ConvexHull;
  6836. ret->m_points = sourceConvexHull.m_vertices;
  6837. ret->m_triangles = sourceConvexHull.m_indices;
  6838. VHACD::BoundsAABB b = VHACD::BoundsAABB(ret->m_points).Inflate(double(0.1));
  6839. ret->mBmin = b.GetMin();
  6840. ret->mBmax = b.GetMax();
  6841. ComputeCentroid(ret->m_points,
  6842. ret->m_triangles,
  6843. ret->m_center);
  6844. ret->m_volume = ComputeConvexHullVolume(*ret);
  6845. // Return the convex hull
  6846. return ret;
  6847. }
  6848. IVHACD::ConvexHull* VHACDImpl::ComputeCombinedConvexHull(const ConvexHull& sm1,
  6849. const ConvexHull& sm2)
  6850. {
  6851. uint32_t vcount = uint32_t(sm1.m_points.size() + sm2.m_points.size()); // Total vertices from both hulls
  6852. std::vector<VHACD::Vertex> vertices(vcount);
  6853. auto it = std::copy(sm1.m_points.begin(),
  6854. sm1.m_points.end(),
  6855. vertices.begin());
  6856. std::copy(sm2.m_points.begin(),
  6857. sm2.m_points.end(),
  6858. it);
  6859. VHACD::QuickHull qh;
  6860. qh.ComputeConvexHull(vertices,
  6861. vcount);
  6862. ConvexHull* ret = new ConvexHull;
  6863. ret->m_points = qh.GetVertices();
  6864. ret->m_triangles = qh.GetIndices();
  6865. ret->m_volume = ComputeConvexHullVolume(*ret);
  6866. VHACD::BoundsAABB b = VHACD::BoundsAABB(qh.GetVertices()).Inflate(double(0.1));
  6867. ret->mBmin = b.GetMin();
  6868. ret->mBmax = b.GetMax();
  6869. ComputeCentroid(ret->m_points,
  6870. ret->m_triangles,
  6871. ret->m_center);
  6872. // Return the convex hull
  6873. return ret;
  6874. }
  6875. IVHACD::ConvexHull* VHACDImpl::GetHull(uint32_t index)
  6876. {
  6877. ConvexHull* ret = nullptr;
  6878. auto found = m_hulls.find(index);
  6879. if ( found != m_hulls.end() )
  6880. {
  6881. ret = found->second;
  6882. }
  6883. return ret;
  6884. }
  6885. bool VHACDImpl::RemoveHull(uint32_t index)
  6886. {
  6887. bool ret = false;
  6888. auto found = m_hulls.find(index);
  6889. if ( found != m_hulls.end() )
  6890. {
  6891. ret = true;
  6892. ReleaseConvexHull(found->second);
  6893. m_hulls.erase(found);
  6894. }
  6895. return ret;
  6896. }
  6897. IVHACD::ConvexHull* VHACDImpl::CopyConvexHull(const ConvexHull& source)
  6898. {
  6899. ConvexHull *ch = new ConvexHull;
  6900. *ch = source;
  6901. return ch;
  6902. }
  6903. const char* VHACDImpl::GetStageName(Stages stage) const
  6904. {
  6905. const char *ret = "unknown";
  6906. switch ( stage )
  6907. {
  6908. case Stages::COMPUTE_BOUNDS_OF_INPUT_MESH:
  6909. ret = "COMPUTE_BOUNDS_OF_INPUT_MESH";
  6910. break;
  6911. case Stages::REINDEXING_INPUT_MESH:
  6912. ret = "REINDEXING_INPUT_MESH";
  6913. break;
  6914. case Stages::CREATE_RAYCAST_MESH:
  6915. ret = "CREATE_RAYCAST_MESH";
  6916. break;
  6917. case Stages::VOXELIZING_INPUT_MESH:
  6918. ret = "VOXELIZING_INPUT_MESH";
  6919. break;
  6920. case Stages::BUILD_INITIAL_CONVEX_HULL:
  6921. ret = "BUILD_INITIAL_CONVEX_HULL";
  6922. break;
  6923. case Stages::PERFORMING_DECOMPOSITION:
  6924. ret = "PERFORMING_DECOMPOSITION";
  6925. break;
  6926. case Stages::INITIALIZING_CONVEX_HULLS_FOR_MERGING:
  6927. ret = "INITIALIZING_CONVEX_HULLS_FOR_MERGING";
  6928. break;
  6929. case Stages::COMPUTING_COST_MATRIX:
  6930. ret = "COMPUTING_COST_MATRIX";
  6931. break;
  6932. case Stages::MERGING_CONVEX_HULLS:
  6933. ret = "MERGING_CONVEX_HULLS";
  6934. break;
  6935. case Stages::FINALIZING_RESULTS:
  6936. ret = "FINALIZING_RESULTS";
  6937. break;
  6938. case Stages::NUM_STAGES:
  6939. // Should be unreachable, here to silence enumeration value not handled in switch warnings
  6940. // GCC/Clang's -Wswitch
  6941. break;
  6942. }
  6943. return ret;
  6944. }
  6945. void VHACDImpl::ProgressUpdate(Stages stage,
  6946. double stageProgress,
  6947. const char* operation)
  6948. {
  6949. if ( m_params.m_callback )
  6950. {
  6951. double overallProgress = (double(stage) * 100) / double(Stages::NUM_STAGES);
  6952. const char *s = GetStageName(stage);
  6953. m_params.m_callback->Update(overallProgress,
  6954. stageProgress,
  6955. s,
  6956. operation);
  6957. }
  6958. }
  6959. bool VHACDImpl::IsCanceled() const
  6960. {
  6961. return m_canceled;
  6962. }
  6963. IVHACD* CreateVHACD(void)
  6964. {
  6965. VHACDImpl *ret = new VHACDImpl;
  6966. return static_cast< IVHACD *>(ret);
  6967. }
  6968. IVHACD* CreateVHACD(void);
  6969. #if !VHACD_DISABLE_THREADING
  6970. class LogMessage
  6971. {
  6972. public:
  6973. double m_overallProgress{ double(-1.0) };
  6974. double m_stageProgress{ double(-1.0) };
  6975. std::string m_stage;
  6976. std::string m_operation;
  6977. };
  6978. class VHACDAsyncImpl : public VHACD::IVHACD,
  6979. public VHACD::IVHACD::IUserCallback,
  6980. VHACD::IVHACD::IUserLogger,
  6981. VHACD::IVHACD::IUserTaskRunner
  6982. {
  6983. public:
  6984. VHACDAsyncImpl() = default;
  6985. ~VHACDAsyncImpl() override;
  6986. void Cancel() override final;
  6987. bool Compute(const float* const points,
  6988. const uint32_t countPoints,
  6989. const uint32_t* const triangles,
  6990. const uint32_t countTriangles,
  6991. const Parameters& params) override final;
  6992. bool Compute(const double* const points,
  6993. const uint32_t countPoints,
  6994. const uint32_t* const triangles,
  6995. const uint32_t countTriangles,
  6996. const Parameters& params) override final;
  6997. bool GetConvexHull(const uint32_t index,
  6998. VHACD::IVHACD::ConvexHull& ch) const override final;
  6999. uint32_t GetNConvexHulls() const override final;
  7000. void Clean() override final; // release internally allocated memory
  7001. void Release() override final; // release IVHACD
  7002. // Will compute the center of mass of the convex hull decomposition results and return it
  7003. // in 'centerOfMass'. Returns false if the center of mass could not be computed.
  7004. bool ComputeCenterOfMass(double centerOfMass[3]) const override;
  7005. bool IsReady() const override final;
  7006. /**
  7007. * At the request of LegionFu : [email protected]
  7008. * This method will return which convex hull is closest to the source position.
  7009. * You can use this method to figure out, for example, which vertices in the original
  7010. * source mesh are best associated with which convex hull.
  7011. *
  7012. * @param pos : The input 3d position to test against
  7013. *
  7014. * @return : Returns which convex hull this position is closest to.
  7015. */
  7016. uint32_t findNearestConvexHull(const double pos[3],
  7017. double& distanceToHull) override final;
  7018. void Update(const double overallProgress,
  7019. const double stageProgress,
  7020. const char* const stage,
  7021. const char *operation) override final;
  7022. void Log(const char* const msg) override final;
  7023. void* StartTask(std::function<void()> func) override;
  7024. void JoinTask(void* Task) override;
  7025. bool Compute(const Parameters params);
  7026. bool ComputeNow(const std::vector<VHACD::Vertex>& points,
  7027. const std::vector<VHACD::Triangle>& triangles,
  7028. const Parameters& _desc);
  7029. // As a convenience for the calling application we only send it update and log messages from it's own main
  7030. // thread. This reduces the complexity burden on the caller by making sure it only has to deal with log
  7031. // messages in it's main application thread.
  7032. void ProcessPendingMessages() const;
  7033. private:
  7034. VHACD::VHACDImpl m_VHACD;
  7035. std::vector<VHACD::Vertex> m_vertices;
  7036. std::vector<VHACD::Triangle> m_indices;
  7037. VHACD::IVHACD::IUserCallback* m_callback{ nullptr };
  7038. VHACD::IVHACD::IUserLogger* m_logger{ nullptr };
  7039. VHACD::IVHACD::IUserTaskRunner* m_taskRunner{ nullptr };
  7040. void* m_task{ nullptr };
  7041. std::atomic<bool> m_running{ false };
  7042. std::atomic<bool> m_cancel{ false };
  7043. // Thread safe caching mechanism for messages and update status.
  7044. // This is so that caller always gets messages in his own thread
  7045. // Member variables are marked as 'mutable' since the message dispatch function
  7046. // is called from const query methods.
  7047. mutable std::mutex m_messageMutex;
  7048. mutable std::vector<LogMessage> m_messages;
  7049. mutable std::atomic<bool> m_haveMessages{ false };
  7050. };
  7051. VHACDAsyncImpl::~VHACDAsyncImpl()
  7052. {
  7053. Cancel();
  7054. }
  7055. void VHACDAsyncImpl::Cancel()
  7056. {
  7057. m_cancel = true;
  7058. m_VHACD.Cancel();
  7059. if (m_task)
  7060. {
  7061. m_taskRunner->JoinTask(m_task); // Wait for the thread to fully exit before we delete the instance
  7062. m_task = nullptr;
  7063. }
  7064. m_cancel = false; // clear the cancel semaphore
  7065. }
  7066. bool VHACDAsyncImpl::Compute(const float* const points,
  7067. const uint32_t countPoints,
  7068. const uint32_t* const triangles,
  7069. const uint32_t countTriangles,
  7070. const Parameters& params)
  7071. {
  7072. m_vertices.reserve(countPoints);
  7073. for (uint32_t i = 0; i < countPoints; ++i)
  7074. {
  7075. m_vertices.emplace_back(points[i * 3 + 0],
  7076. points[i * 3 + 1],
  7077. points[i * 3 + 2]);
  7078. }
  7079. m_indices.reserve(countTriangles);
  7080. for (uint32_t i = 0; i < countTriangles; ++i)
  7081. {
  7082. m_indices.emplace_back(triangles[i * 3 + 0],
  7083. triangles[i * 3 + 1],
  7084. triangles[i * 3 + 2]);
  7085. }
  7086. return Compute(params);
  7087. }
  7088. bool VHACDAsyncImpl::Compute(const double* const points,
  7089. const uint32_t countPoints,
  7090. const uint32_t* const triangles,
  7091. const uint32_t countTriangles,
  7092. const Parameters& params)
  7093. {
  7094. // We need to copy the input vertices and triangles into our own buffers so we can operate
  7095. // on them safely from the background thread.
  7096. // Can't be local variables due to being asynchronous
  7097. m_vertices.reserve(countPoints);
  7098. for (uint32_t i = 0; i < countPoints; ++i)
  7099. {
  7100. m_vertices.emplace_back(points[i * 3 + 0],
  7101. points[i * 3 + 1],
  7102. points[i * 3 + 2]);
  7103. }
  7104. m_indices.reserve(countTriangles);
  7105. for (uint32_t i = 0; i < countTriangles; ++i)
  7106. {
  7107. m_indices.emplace_back(triangles[i * 3 + 0],
  7108. triangles[i * 3 + 1],
  7109. triangles[i * 3 + 2]);
  7110. }
  7111. return Compute(params);
  7112. }
  7113. bool VHACDAsyncImpl::GetConvexHull(const uint32_t index,
  7114. VHACD::IVHACD::ConvexHull& ch) const
  7115. {
  7116. return m_VHACD.GetConvexHull(index,
  7117. ch);
  7118. }
  7119. uint32_t VHACDAsyncImpl::GetNConvexHulls() const
  7120. {
  7121. ProcessPendingMessages();
  7122. return m_VHACD.GetNConvexHulls();
  7123. }
  7124. void VHACDAsyncImpl::Clean()
  7125. {
  7126. Cancel();
  7127. m_VHACD.Clean();
  7128. }
  7129. void VHACDAsyncImpl::Release()
  7130. {
  7131. delete this;
  7132. }
  7133. bool VHACDAsyncImpl::ComputeCenterOfMass(double centerOfMass[3]) const
  7134. {
  7135. bool ret = false;
  7136. centerOfMass[0] = 0;
  7137. centerOfMass[1] = 0;
  7138. centerOfMass[2] = 0;
  7139. if (IsReady())
  7140. {
  7141. ret = m_VHACD.ComputeCenterOfMass(centerOfMass);
  7142. }
  7143. return ret;
  7144. }
  7145. bool VHACDAsyncImpl::IsReady() const
  7146. {
  7147. ProcessPendingMessages();
  7148. return !m_running;
  7149. }
  7150. uint32_t VHACDAsyncImpl::findNearestConvexHull(const double pos[3],
  7151. double& distanceToHull)
  7152. {
  7153. uint32_t ret = 0; // The default return code is zero
  7154. distanceToHull = 0;
  7155. // First, make sure that we have valid and completed results
  7156. if (IsReady() )
  7157. {
  7158. ret = m_VHACD.findNearestConvexHull(pos,distanceToHull);
  7159. }
  7160. return ret;
  7161. }
  7162. void VHACDAsyncImpl::Update(const double overallProgress,
  7163. const double stageProgress,
  7164. const char* const stage,
  7165. const char* operation)
  7166. {
  7167. m_messageMutex.lock();
  7168. LogMessage m;
  7169. m.m_operation = std::string(operation);
  7170. m.m_overallProgress = overallProgress;
  7171. m.m_stageProgress = stageProgress;
  7172. m.m_stage = std::string(stage);
  7173. m_messages.push_back(m);
  7174. m_haveMessages = true;
  7175. m_messageMutex.unlock();
  7176. }
  7177. void VHACDAsyncImpl::Log(const char* const msg)
  7178. {
  7179. m_messageMutex.lock();
  7180. LogMessage m;
  7181. m.m_operation = std::string(msg);
  7182. m_haveMessages = true;
  7183. m_messages.push_back(m);
  7184. m_messageMutex.unlock();
  7185. }
  7186. void* VHACDAsyncImpl::StartTask(std::function<void()> func)
  7187. {
  7188. return new std::thread(func);
  7189. }
  7190. void VHACDAsyncImpl::JoinTask(void* Task)
  7191. {
  7192. std::thread* t = static_cast<std::thread*>(Task);
  7193. t->join();
  7194. delete t;
  7195. }
  7196. bool VHACDAsyncImpl::Compute(Parameters params)
  7197. {
  7198. Cancel(); // if we previously had a solution running; cancel it.
  7199. m_taskRunner = params.m_taskRunner ? params.m_taskRunner : this;
  7200. params.m_taskRunner = m_taskRunner;
  7201. m_running = true;
  7202. m_task = m_taskRunner->StartTask([this, params]() {
  7203. ComputeNow(m_vertices,
  7204. m_indices,
  7205. params);
  7206. // If we have a user provided callback and the user did *not* call 'cancel' we notify him that the
  7207. // task is completed. However..if the user selected 'cancel' we do not send a completed notification event.
  7208. if (params.m_callback && !m_cancel)
  7209. {
  7210. params.m_callback->NotifyVHACDComplete();
  7211. }
  7212. m_running = false;
  7213. });
  7214. return true;
  7215. }
  7216. bool VHACDAsyncImpl::ComputeNow(const std::vector<VHACD::Vertex>& points,
  7217. const std::vector<VHACD::Triangle>& triangles,
  7218. const Parameters& _desc)
  7219. {
  7220. uint32_t ret = 0;
  7221. Parameters desc;
  7222. m_callback = _desc.m_callback;
  7223. m_logger = _desc.m_logger;
  7224. desc = _desc;
  7225. // Set our intercepting callback interfaces if non-null
  7226. desc.m_callback = _desc.m_callback ? this : nullptr;
  7227. desc.m_logger = _desc.m_logger ? this : nullptr;
  7228. // If not task runner provided, then use the default one
  7229. if (desc.m_taskRunner == nullptr)
  7230. {
  7231. desc.m_taskRunner = this;
  7232. }
  7233. bool ok = m_VHACD.Compute(points,
  7234. triangles,
  7235. desc);
  7236. if (ok)
  7237. {
  7238. ret = m_VHACD.GetNConvexHulls();
  7239. }
  7240. return ret ? true : false;
  7241. }
  7242. void VHACDAsyncImpl::ProcessPendingMessages() const
  7243. {
  7244. if (m_cancel)
  7245. {
  7246. return;
  7247. }
  7248. if ( m_haveMessages )
  7249. {
  7250. m_messageMutex.lock();
  7251. for (auto& i : m_messages)
  7252. {
  7253. if ( i.m_overallProgress == -1 )
  7254. {
  7255. if ( m_logger )
  7256. {
  7257. m_logger->Log(i.m_operation.c_str());
  7258. }
  7259. }
  7260. else if ( m_callback )
  7261. {
  7262. m_callback->Update(i.m_overallProgress,
  7263. i.m_stageProgress,
  7264. i.m_stage.c_str(),
  7265. i.m_operation.c_str());
  7266. }
  7267. }
  7268. m_messages.clear();
  7269. m_haveMessages = false;
  7270. m_messageMutex.unlock();
  7271. }
  7272. }
  7273. IVHACD* CreateVHACD_ASYNC()
  7274. {
  7275. VHACDAsyncImpl* m = new VHACDAsyncImpl;
  7276. return static_cast<IVHACD*>(m);
  7277. }
  7278. #endif
  7279. } // namespace VHACD
  7280. #ifdef _MSC_VER
  7281. #pragma warning(pop)
  7282. #endif // _MSC_VER
  7283. #ifdef __GNUC__
  7284. #pragma GCC diagnostic pop
  7285. #endif // __GNUC__
  7286. #endif // ENABLE_VHACD_IMPLEMENTATION
  7287. #endif // VHACD_H