12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849 |
- ///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros
- ///|/ Copyright (c) 2020 Henner Zeller
- ///|/
- ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
- ///|/
- #include "bbs_3mf.hpp"
- #include "../libslic3r.h"
- #include "../Exception.hpp"
- #include "../Model.hpp"
- #include "../Preset.hpp"
- #include "../Utils.hpp"
- #include "../LocalesUtils.hpp"
- #include "../GCode.hpp"
- #include "../GCode/GCodeProcessor.hpp"
- #include "../GCode/ThumbnailData.hpp"
- #include "../Geometry.hpp"
- #include "../Semver.hpp"
- #include "../Time.hpp"
- #include "BBConfig.hpp"
- #include "../I18N.hpp"
- #include <limits>
- #include <mutex>
- #include <stdexcept>
- #include <iomanip>
- #include <boost/assign.hpp>
- #include <boost/bimap.hpp>
- #include <boost/algorithm/string/classification.hpp>
- #include <boost/algorithm/string/split.hpp>
- #include <boost/algorithm/string/predicate.hpp>
- #include <boost/algorithm/string/replace.hpp>
- #include <boost/filesystem/operations.hpp>
- #include <boost/nowide/fstream.hpp>
- #include <boost/nowide/cstdio.hpp>
- #include <boost/spirit/include/karma.hpp>
- #include <boost/spirit/include/qi_int.hpp>
- #include <boost/log/trivial.hpp>
- #include <boost/beast/core/detail/base64.hpp>
- #include <boost/property_tree/ptree.hpp>
- #include <boost/property_tree/xml_parser.hpp>
- #include <boost/foreach.hpp>
- //#include <openssl/md5.h>
- namespace pt = boost::property_tree;
- #include <tbb/parallel_for.h>
- #include <tbb/parallel_reduce.h>
- #include <expat.h>
- #include <Eigen/Dense>
- #include "miniz_extension.hpp"
- #include "nlohmann/json.hpp"
- //#include "TextConfiguration.hpp" //Susi_not_impl
- //#include "EmbossShape.hpp" //Susi_not_impl
- //#include "ExPolygonSerialize.hpp" //Susi_not_impl
- //#include "NSVGUtils.hpp"
- #include <fast_float/fast_float.h>
- // Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
- // https://github.com/boostorg/spirit/pull/586
- // where the exported string is one digit shorter than it should be to guarantee lossless round trip.
- // The code is left here for the ocasion boost guys improve.
- #define EXPORT_3MF_USE_SPIRIT_KARMA_FP 0
- #define WRITE_ZIP_LANGUAGE_ENCODING 1
- // @see https://commons.apache.org/proper/commons-compress/apidocs/src-html/org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField.html
- struct ZipUnicodePathExtraField
- {
- static std::string encode(std::string const& u8path, std::string const& path) {
- std::string extra;
- if (u8path != path) {
- // 0x7075 - for Unicode filenames
- extra.push_back('\x75');
- extra.push_back('\x70');
- boost::uint16_t len = 5 + u8path.length();
- extra.push_back((char)(len & 0xff));
- extra.push_back((char)(len >> 8));
- auto crc = mz_crc32(0, (unsigned char *) path.c_str(), path.length());
- extra.push_back('\x01'); // version 1
- extra.append((char *)&crc, (char *)&crc + 4); // Little Endian
- extra.append(u8path);
- }
- return extra;
- }
- static std::string decode(std::string const& extra, std::string const& path = {}) {
- char const * p = extra.data();
- char const * e = p + extra.length();
- while (p + 4 < e) {
- boost::uint16_t len = ((boost::uint16_t)p[2]) | ((boost::uint16_t)p[3] << 8);
- if (p[0] == '\x75' && p[1] == '\x70' && len >= 5 && p + 4 + len < e && p[4] == '\x01') {
- return std::string(p + 9, p + 4 + len);
- }
- else {
- p += 4 + len;
- }
- }
- return Slic3r::decode_path(path.c_str());
- }
- };
- //FIXME this has potentially O(n^2) time complexity!
- std::string xml_escape(std::string text, bool is_marked/* = false*/)
- {
- std::string::size_type pos = 0;
- for (;;)
- {
- pos = text.find_first_of("\"\'&<>", pos);
- if (pos == std::string::npos)
- break;
- std::string replacement;
- switch (text[pos])
- {
- case '\"': replacement = """; break;
- case '\'': replacement = "'"; break;
- case '&': replacement = "&"; break;
- case '<': replacement = is_marked ? "<" :"<"; break;
- case '>': replacement = is_marked ? ">" :">"; break;
- default: break;
- }
- text.replace(pos, 1, replacement);
- pos += replacement.size();
- }
- return text;
- }
- // Definition of escape symbols https://www.w3.org/TR/REC-xml/#AVNormalize
- // During the read of xml attribute normalization of white spaces is applied
- // Soo for not lose white space character it is escaped before store
- std::string xml_escape_double_quotes_attribute_value(std::string text)
- {
- std::string::size_type pos = 0;
- for (;;) {
- pos = text.find_first_of("\"&<\r\n\t", pos);
- if (pos == std::string::npos) break;
- std::string replacement;
- switch (text[pos]) {
- case '\"': replacement = """; break;
- case '&': replacement = "&"; break;
- case '<': replacement = "<"; break;
- case '\r': replacement = "
"; break;
- case '\n': replacement = "
"; break;
- case '\t': replacement = "	"; break;
- default: break;
- }
- text.replace(pos, 1, replacement);
- pos += replacement.size();
- }
- return text;
- }
- std::string xml_unescape(std::string s)
- {
- std::string ret;
- std::string::size_type i = 0;
- std::string::size_type pos = 0;
- while (i < s.size()) {
- std::string rep;
- if (s[i] == '&') {
- if (s.substr(i, 4) == "<") {
- ret += s.substr(pos, i - pos) + "<";
- i += 4;
- pos = i;
- }
- else if (s.substr(i, 4) == ">") {
- ret += s.substr(pos, i - pos) + ">";
- i += 4;
- pos = i;
- }
- else if (s.substr(i, 5) == "&") {
- ret += s.substr(pos, i - pos) + "&";
- i += 5;
- pos = i;
- }
- else {
- ++i;
- }
- }
- else {
- ++i;
- }
- }
- ret += s.substr(pos);
- return ret;
- }
- void save_string_file(const std_path& p, const std::string& str)
- {
- boost::nowide::ofstream file;
- file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
- file.open(p.generic_string(), std::ios_base::binary);
- file.write(str.c_str(), str.size());
- }
- #define BBL_JSON_KEY_VERSION "version"
- // VERSION NUMBERS
- // 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
- // 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
- // 2 : Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file, meshes transformed back to their coordinate system on loading.
- // WARNING !! -> the version number has been rolled back to 1
- // the next change should use 3
- const unsigned int VERSION_BBS_3MF = 1;
- // Allow loading version 2 file as well.
- const unsigned int VERSION_BBS_3MF_COMPATIBLE = 2;
- const char* BBS_3MF_VERSION1 = "bamboo_slicer:Version3mf"; // definition of the metadata name saved into .model file
- const char* BBS_3MF_VERSION = "BambuStudio:3mfVersion"; //compatible with prusa currently
- // Painting gizmos data version numbers
- // 0 : initial version of fdm, seam, mm
- const unsigned int FDM_SUPPORTS_PAINTING_VERSION = 0;
- const unsigned int SEAM_PAINTING_VERSION = 0;
- const unsigned int MM_PAINTING_VERSION = 0;
- const std::string BBS_FDM_SUPPORTS_PAINTING_VERSION = "BambuStudio:FdmSupportsPaintingVersion";
- const std::string BBS_SEAM_PAINTING_VERSION = "BambuStudio:SeamPaintingVersion";
- const std::string BBS_MM_PAINTING_VERSION = "BambuStudio:MmPaintingVersion";
- const std::string BBL_MODEL_ID_TAG = "model_id";
- const std::string BBL_MODEL_NAME_TAG = "Title";
- const std::string BBL_ORIGIN_TAG = "Origin";
- const std::string BBL_DESIGNER_TAG = "Designer";
- const std::string BBL_DESIGNER_USER_ID_TAG = "DesignerUserId";
- const std::string BBL_DESIGNER_COVER_FILE_TAG = "DesignerCover";
- const std::string BBL_DESCRIPTION_TAG = "Description";
- const std::string BBL_COPYRIGHT_TAG = "CopyRight";
- const std::string BBL_COPYRIGHT_NORMATIVE_TAG = "Copyright";
- const std::string BBL_LICENSE_TAG = "License";
- const std::string BBL_REGION_TAG = "Region";
- const std::string BBL_MODIFICATION_TAG = "ModificationDate";
- const std::string BBL_CREATION_DATE_TAG = "CreationDate";
- const std::string BBL_APPLICATION_TAG = "Application";
- const std::string BBL_PROFILE_TITLE_TAG = "ProfileTitle";
- const std::string BBL_PROFILE_COVER_TAG = "ProfileCover";
- const std::string BBL_PROFILE_DESCRIPTION_TAG = "ProfileDescription";
- const std::string BBL_PROFILE_USER_ID_TAG = "ProfileUserId";
- const std::string BBL_PROFILE_USER_NAME_TAG = "ProfileUserName";
- const std::string MODEL_FOLDER = "3D/";
- const std::string MODEL_EXTENSION = ".model";
- const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
- const std::string MODEL_RELS_FILE = "3D/_rels/3dmodel.model.rels";
- //BBS: add metadata_folder
- const std::string METADATA_DIR = "Metadata/";
- const std::string ACCESOR_DIR = "accesories/";
- const std::string GCODE_EXTENSION = ".gcode";
- const std::string THUMBNAIL_EXTENSION = ".png";
- const std::string CALIBRATION_INFO_EXTENSION = ".json";
- const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
- const std::string RELATIONSHIPS_FILE = "_rels/.rels";
- const std::string THUMBNAIL_FILE = "Metadata/plate_1.png";
- const std::string THUMBNAIL_FOR_PRINTER_FILE = "Metadata/bbl_thumbnail.png";
- const std::string PRINTER_THUMBNAIL_SMALL_FILE = "/Auxiliaries/.thumbnails/thumbnail_small.png";
- const std::string PRINTER_THUMBNAIL_MIDDLE_FILE = "/Auxiliaries/.thumbnails/thumbnail_middle.png";
- const std::string _3MF_COVER_FILE = "/Auxiliaries/.thumbnails/thumbnail_3mf.png";
- //const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
- //const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
- const std::string BBS_PRINT_CONFIG_FILE = "Metadata/print_profile.config";
- const std::string BBS_PROJECT_CONFIG_FILE = "Metadata/project_settings.config";
- const std::string BBS_MODEL_CONFIG_FILE = "Metadata/model_settings.config";
- const std::string BBS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.config.rels";
- const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config";
- const std::string BBS_LAYER_HEIGHTS_PROFILE_FILE = "Metadata/layer_heights_profile.txt";
- const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/layer_config_ranges.xml";
- /*const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
- const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";*/
- const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/custom_gcode_per_layer.xml";
- const std::string AUXILIARY_DIR = "Auxiliaries/";
- const std::string PROJECT_EMBEDDED_PRINT_PRESETS_FILE = "Metadata/print_setting_";
- const std::string PROJECT_EMBEDDED_SLICE_PRESETS_FILE = "Metadata/process_settings_";
- const std::string PROJECT_EMBEDDED_FILAMENT_PRESETS_FILE = "Metadata/filament_settings_";
- const std::string PROJECT_EMBEDDED_PRINTER_PRESETS_FILE = "Metadata/machine_settings_";
- const std::string CUT_INFORMATION_FILE = "Metadata/cut_information.xml";
- const unsigned int AUXILIARY_STR_LEN = 12;
- const unsigned int METADATA_STR_LEN = 9;
- static constexpr const char* MODEL_TAG = "model";
- static constexpr const char* RESOURCES_TAG = "resources";
- static constexpr const char* COLOR_GROUP_TAG = "m:colorgroup";
- static constexpr const char* COLOR_TAG = "m:color";
- static constexpr const char* OBJECT_TAG = "object";
- static constexpr const char* MESH_TAG = "mesh";
- static constexpr const char* MESH_STAT_TAG = "mesh_stat";
- static constexpr const char* VERTICES_TAG = "vertices";
- static constexpr const char* VERTEX_TAG = "vertex";
- static constexpr const char* TRIANGLES_TAG = "triangles";
- static constexpr const char* TRIANGLE_TAG = "triangle";
- static constexpr const char* COMPONENTS_TAG = "components";
- static constexpr const char* COMPONENT_TAG = "component";
- static constexpr const char* BUILD_TAG = "build";
- static constexpr const char* ITEM_TAG = "item";
- static constexpr const char* METADATA_TAG = "metadata";
- static constexpr const char* FILAMENT_TAG = "filament";
- static constexpr const char* SLICE_WARNING_TAG = "warning";
- static constexpr const char* WARNING_MSG_TAG = "msg";
- static constexpr const char *FILAMENT_ID_TAG = "id";
- static constexpr const char* FILAMENT_TYPE_TAG = "type";
- static constexpr const char *FILAMENT_COLOR_TAG = "color";
- static constexpr const char *FILAMENT_USED_M_TAG = "used_m";
- static constexpr const char *FILAMENT_USED_G_TAG = "used_g";
- static constexpr const char* CONFIG_TAG = "config";
- static constexpr const char* VOLUME_TAG = "volume";
- static constexpr const char* PART_TAG = "part";
- static constexpr const char* PLATE_TAG = "plate";
- static constexpr const char* INSTANCE_TAG = "model_instance";
- //BBS
- static constexpr const char* ASSEMBLE_TAG = "assemble";
- static constexpr const char* ASSEMBLE_ITEM_TAG = "assemble_item";
- static constexpr const char* SLICE_HEADER_TAG = "header";
- static constexpr const char* SLICE_HEADER_ITEM_TAG = "header_item";
- // Deprecated: text_info
- static constexpr const char* TEXT_INFO_TAG = "text_info";
- static constexpr const char* TEXT_ATTR = "text";
- static constexpr const char* FONT_NAME_ATTR = "font_name";
- static constexpr const char* FONT_INDEX_ATTR = "font_index";
- static constexpr const char* FONT_SIZE_ATTR = "font_size";
- static constexpr const char* THICKNESS_ATTR = "thickness";
- static constexpr const char* EMBEDED_DEPTH_ATTR = "embeded_depth";
- static constexpr const char* ROTATE_ANGLE_ATTR = "rotate_angle";
- static constexpr const char* TEXT_GAP_ATTR = "text_gap";
- static constexpr const char* BOLD_ATTR = "bold";
- static constexpr const char* ITALIC_ATTR = "italic";
- static constexpr const char* SURFACE_TEXT_ATTR = "surface_text";
- static constexpr const char* KEEP_HORIZONTAL_ATTR = "keep_horizontal";
- static constexpr const char* HIT_MESH_ATTR = "hit_mesh";
- static constexpr const char* HIT_POSITION_ATTR = "hit_position";
- static constexpr const char* HIT_NORMAL_ATTR = "hit_normal";
- // BBS: encrypt
- static constexpr const char* RELATIONSHIP_TAG = "Relationship";
- static constexpr const char* PID_ATTR = "pid";
- static constexpr const char* PUUID_ATTR = "p:UUID";
- static constexpr const char* PUUID_LOWER_ATTR = "p:uuid";
- static constexpr const char* PPATH_ATTR = "p:path";
- static constexpr const char *OBJECT_UUID_SUFFIX = "-61cb-4c03-9d28-80fed5dfa1dc";
- static constexpr const char *OBJECT_UUID_SUFFIX2 = "-71cb-4c03-9d28-80fed5dfa1dc";
- static constexpr const char *SUB_OBJECT_UUID_SUFFIX = "-81cb-4c03-9d28-80fed5dfa1dc";
- static constexpr const char *COMPONENT_UUID_SUFFIX = "-b206-40ff-9872-83e8017abed1";
- static constexpr const char* BUILD_UUID = "2c7c17d8-22b5-4d84-8835-1976022ea369";
- static constexpr const char* BUILD_UUID_SUFFIX = "-b1ec-4553-aec9-835e5b724bb4";
- static constexpr const char* TARGET_ATTR = "Target";
- static constexpr const char* RELS_TYPE_ATTR = "Type";
- static constexpr const char* UNIT_ATTR = "unit";
- static constexpr const char* NAME_ATTR = "name";
- static constexpr const char* COLOR_ATTR = "color";
- static constexpr const char* TYPE_ATTR = "type";
- static constexpr const char* ID_ATTR = "id";
- static constexpr const char* X_ATTR = "x";
- static constexpr const char* Y_ATTR = "y";
- static constexpr const char* Z_ATTR = "z";
- static constexpr const char* V1_ATTR = "v1";
- static constexpr const char* V2_ATTR = "v2";
- static constexpr const char* V3_ATTR = "v3";
- static constexpr const char* OBJECTID_ATTR = "objectid";
- static constexpr const char* TRANSFORM_ATTR = "transform";
- // BBS
- static constexpr const char* OFFSET_ATTR = "offset";
- static constexpr const char* PRINTABLE_ATTR = "printable";
- static constexpr const char* INSTANCESCOUNT_ATTR = "instances_count";
- static constexpr const char* CUSTOM_SUPPORTS_ATTR = "paint_supports";
- static constexpr const char* CUSTOM_SEAM_ATTR = "paint_seam";
- static constexpr const char* MMU_SEGMENTATION_ATTR = "paint_color";
- // BBS
- static constexpr const char* FACE_PROPERTY_ATTR = "face_property";
- static constexpr const char* KEY_ATTR = "key";
- static constexpr const char* VALUE_ATTR = "value";
- static constexpr const char* FIRST_TRIANGLE_ID_ATTR = "firstid";
- static constexpr const char* LAST_TRIANGLE_ID_ATTR = "lastid";
- static constexpr const char* SUBTYPE_ATTR = "subtype";
- static constexpr const char* LOCK_ATTR = "locked";
- static constexpr const char* BED_TYPE_ATTR = "bed_type";
- static constexpr const char* PRINT_SEQUENCE_ATTR = "print_sequence";
- static constexpr const char* FIRST_LAYER_PRINT_SEQUENCE_ATTR = "first_layer_print_sequence";
- static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode";
- static constexpr const char* GCODE_FILE_ATTR = "gcode_file";
- static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file";
- static constexpr const char* TOP_FILE_ATTR = "top_file";
- static constexpr const char* PICK_FILE_ATTR = "pick_file";
- static constexpr const char* PATTERN_FILE_ATTR = "pattern_file";
- static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file";
- static constexpr const char* OBJECT_ID_ATTR = "object_id";
- static constexpr const char* INSTANCEID_ATTR = "instance_id";
- static constexpr const char* IDENTIFYID_ATTR = "identify_id";
- static constexpr const char* PLATERID_ATTR = "plater_id";
- static constexpr const char* PLATER_NAME_ATTR = "plater_name";
- static constexpr const char* PLATE_IDX_ATTR = "index";
- static constexpr const char* PRINTER_MODEL_ID_ATTR = "printer_model_id";
- static constexpr const char* NOZZLE_DIAMETERS_ATTR = "nozzle_diameters";
- static constexpr const char* SLICE_PREDICTION_ATTR = "prediction";
- static constexpr const char* SLICE_WEIGHT_ATTR = "weight";
- static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
- static constexpr const char* TIMELAPSE_ERROR_CODE_ATTR = "timelapse_error_code";
- static constexpr const char* OUTSIDE_ATTR = "outside";
- static constexpr const char* SUPPORT_USED_ATTR = "support_used";
- static constexpr const char* LABEL_OBJECT_ENABLED_ATTR = "label_object_enabled";
- static constexpr const char* SKIPPED_ATTR = "skipped";
- static constexpr const char* OBJECT_TYPE = "object";
- static constexpr const char* VOLUME_TYPE = "volume";
- static constexpr const char* PART_TYPE = "part";
- static constexpr const char* NAME_KEY = "name";
- static constexpr const char* VOLUME_TYPE_KEY = "volume_type";
- static constexpr const char* PART_TYPE_KEY = "part_type";
- static constexpr const char* MATRIX_KEY = "matrix";
- static constexpr const char* SOURCE_FILE_KEY = "source_file";
- static constexpr const char* SOURCE_OBJECT_ID_KEY = "source_object_id";
- static constexpr const char* SOURCE_VOLUME_ID_KEY = "source_volume_id";
- static constexpr const char* SOURCE_OFFSET_X_KEY = "source_offset_x";
- static constexpr const char* SOURCE_OFFSET_Y_KEY = "source_offset_y";
- static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z";
- static constexpr const char* SOURCE_IN_INCHES = "source_in_inches";
- static constexpr const char* SOURCE_IN_METERS = "source_in_meters";
- static constexpr const char* MESH_SHARED_KEY = "mesh_shared";
- static constexpr const char* MESH_STAT_EDGES_FIXED = "edges_fixed";
- static constexpr const char* MESH_STAT_DEGENERATED_FACETS = "degenerate_facets";
- static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed";
- static constexpr const char* MESH_STAT_FACETS_RESERVED = "facets_reversed";
- static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges";
- // Store / load of TextConfiguration
- static constexpr const char *TEXT_TAG = "slic3rpe:text";
- static constexpr const char *TEXT_DATA_ATTR = "text";
- // TextConfiguration::EmbossStyle
- static constexpr const char *STYLE_NAME_ATTR = "style_name";
- static constexpr const char *FONT_DESCRIPTOR_ATTR = "font_descriptor";
- static constexpr const char *FONT_DESCRIPTOR_TYPE_ATTR = "font_descriptor_type";
- // TextConfiguration::FontProperty
- static constexpr const char *CHAR_GAP_ATTR = "char_gap";
- static constexpr const char *LINE_GAP_ATTR = "line_gap";
- static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
- static constexpr const char *BOLDNESS_ATTR = "boldness";
- static constexpr const char *SKEW_ATTR = "skew";
- static constexpr const char *PER_GLYPH_ATTR = "per_glyph";
- static constexpr const char *HORIZONTAL_ALIGN_ATTR = "horizontal";
- static constexpr const char *VERTICAL_ALIGN_ATTR = "vertical";
- static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
- static constexpr const char *FONT_FAMILY_ATTR = "family";
- static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
- static constexpr const char *FONT_STYLE_ATTR = "style";
- static constexpr const char *FONT_WEIGHT_ATTR = "weight";
- // Store / load of EmbossShape
- static constexpr const char *SHAPE_TAG = "slic3rpe:shape";
- static constexpr const char *SHAPE_SCALE_ATTR = "scale";
- static constexpr const char *UNHEALED_ATTR = "unhealed";
- static constexpr const char *SVG_FILE_PATH_ATTR = "filepath";
- static constexpr const char *SVG_FILE_PATH_IN_3MF_ATTR = "filepath3mf";
- // EmbossProjection
- static constexpr const char *DEPTH_ATTR = "depth";
- static constexpr const char *USE_SURFACE_ATTR = "use_surface";
- // static constexpr const char *FIX_TRANSFORMATION_ATTR = "transform";
- const unsigned int BBS_VALID_OBJECT_TYPES_COUNT = 2;
- const char* BBS_VALID_OBJECT_TYPES[] =
- {
- "model",
- "other"
- };
- const char* BBS_INVALID_OBJECT_TYPES[] =
- {
- "solidsupport",
- "support",
- "surface"
- };
- template <typename T>
- struct hex_wrap
- {
- T t;
- };
- namespace std {
- template <class _Elem, class _Traits, class _Arg>
- basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& ostr,
- const hex_wrap<_Arg>& wrap) { // insert by calling function with output stream and argument
- auto of = ostr.fill('0');
- ostr << setw(sizeof(_Arg) * 2) << std::hex << wrap.t;
- ostr << std::dec << setw(0);
- ostr.fill(of);
- return ostr;
- }
- }
- class version_error : public Slic3r::FileIOError
- {
- public:
- version_error(const std::string& what_arg) : Slic3r::FileIOError(what_arg) {}
- version_error(const char* what_arg) : Slic3r::FileIOError(what_arg) {}
- };
- const char* bbs_get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key)
- {
- if ((attributes == nullptr) || (attributes_size == 0) || (attributes_size % 2 != 0) || (attribute_key == nullptr))
- return nullptr;
- for (unsigned int a = 0; a < attributes_size; a += 2) {
- if (::strcmp(attributes[a], attribute_key) == 0)
- return attributes[a + 1];
- }
- return nullptr;
- }
- std::string bbs_get_attribute_value_string(const char** attributes, unsigned int attributes_size, const char* attribute_key)
- {
- const char* text = bbs_get_attribute_value_charptr(attributes, attributes_size, attribute_key);
- return (text != nullptr) ? text : "";
- }
- float bbs_get_attribute_value_float(const char** attributes, unsigned int attributes_size, const char* attribute_key)
- {
- float value = 0.0f;
- if (const char *text = bbs_get_attribute_value_charptr(attributes, attributes_size, attribute_key); text != nullptr)
- fast_float::from_chars(text, text + strlen(text), value);
- return value;
- }
- int bbs_get_attribute_value_int(const char** attributes, unsigned int attributes_size, const char* attribute_key)
- {
- int value = 0;
- if (const char *text = bbs_get_attribute_value_charptr(attributes, attributes_size, attribute_key); text != nullptr)
- boost::spirit::qi::parse(text, text + strlen(text), boost::spirit::qi::int_, value);
- return value;
- }
- bool bbs_get_attribute_value_bool(const char** attributes, unsigned int attributes_size, const char* attribute_key)
- {
- const char* text = bbs_get_attribute_value_charptr(attributes, attributes_size, attribute_key);
- return (text != nullptr) ? (bool)::atoi(text) : true;
- }
- void add_vec3(std::stringstream &stream, const Slic3r::Vec3f &tr)
- {
- for (unsigned r = 0; r < 3; ++r) {
- stream << tr(r);
- if (r != 2)
- stream << " ";
- }
- }
- Slic3r::Vec3f get_vec3_from_string(const std::string &pos_str)
- {
- Slic3r::Vec3f pos(0, 0, 0);
- if (pos_str.empty())
- return pos;
- std::vector<std::string> values;
- boost::split(values, pos_str, boost::is_any_of(" "), boost::token_compress_on);
- if (values.size() != 3)
- return pos;
- for (int i = 0; i < 3; ++i)
- pos(i) = ::atof(values[i].c_str());
- return pos;
- }
- Slic3r::Transform3d bbs_get_transform_from_3mf_specs_string(const std::string& mat_str)
- {
- // check: https://3mf.io/3d-manufacturing-format/ or https://github.com/3MFConsortium/spec_core/blob/master/3MF%20Core%20Specification.md
- // to see how matrices are stored inside 3mf according to specifications
- Slic3r::Transform3d ret = Slic3r::Transform3d::Identity();
- if (mat_str.empty())
- // empty string means default identity matrix
- return ret;
- std::vector<std::string> mat_elements_str;
- boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on);
- unsigned int size = (unsigned int)mat_elements_str.size();
- if (size != 12)
- // invalid data, return identity matrix
- return ret;
- unsigned int i = 0;
- // matrices are stored into 3mf files as 4x3
- // we need to transpose them
- for (unsigned int c = 0; c < 4; ++c) {
- for (unsigned int r = 0; r < 3; ++r) {
- ret(r, c) = ::atof(mat_elements_str[i++].c_str());
- }
- }
- return ret;
- }
- Slic3r::Vec3d bbs_get_offset_from_3mf_specs_string(const std::string& vec_str)
- {
- Slic3r::Vec3d ofs2ass(0, 0, 0);
- if (vec_str.empty())
- // empty string means default zero offset
- return ofs2ass;
- std::vector<std::string> vec_elements_str;
- boost::split(vec_elements_str, vec_str, boost::is_any_of(" "), boost::token_compress_on);
- unsigned int size = (unsigned int)vec_elements_str.size();
- if (size != 3)
- // invalid data, return zero offset
- return ofs2ass;
- for (unsigned int i = 0; i < 3; i++) {
- ofs2ass(i) = ::atof(vec_elements_str[i].c_str());
- }
- return ofs2ass;
- }
- float bbs_get_unit_factor(const std::string& unit)
- {
- const char* text = unit.c_str();
- if (::strcmp(text, "micron") == 0)
- return 0.001f;
- else if (::strcmp(text, "centimeter") == 0)
- return 10.0f;
- else if (::strcmp(text, "inch") == 0)
- return 25.4f;
- else if (::strcmp(text, "foot") == 0)
- return 304.8f;
- else if (::strcmp(text, "meter") == 0)
- return 1000.0f;
- else
- // default "millimeters" (see specification)
- return 1.0f;
- }
- bool bbs_is_valid_object_type(const std::string& type)
- {
- // if the type is empty defaults to "model" (see specification)
- if (type.empty())
- return true;
- for (unsigned int i = 0; i < BBS_VALID_OBJECT_TYPES_COUNT; ++i) {
- if (::strcmp(type.c_str(), BBS_VALID_OBJECT_TYPES[i]) == 0)
- return true;
- }
- return false;
- }
- namespace Slic3r {
- void PlateData::parse_filament_info(GCodeProcessorResult *result)
- {
- if (!result) return;
- PrintEstimatedStatistics &ps = result->print_statistics;
- std::vector<float> m_filament_diameters = result->filament_diameters;
- std::vector<float> m_filament_densities = result->filament_densities;
- auto get_used_filament_from_volume = [m_filament_diameters, m_filament_densities](double volume, int extruder_id) {
- double koef = 0.001;
- std::pair<double, double> ret = {koef * volume / (PI * sqr(0.5 * m_filament_diameters[extruder_id])), volume * m_filament_densities[extruder_id] * 0.001};
- return ret;
- };
- for (auto it = ps.volumes_per_extruder.begin(); it != ps.volumes_per_extruder.end(); it++) {
- double volume = it->second;
- auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, it->first);
- FilamentInfo info;
- info.id = it->first;
- //if (ps.flush_per_filament.find(it->first) != ps.flush_per_filament.end()) {
- // volume = ps.flush_per_filament.at(it->first);
- // auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, it->first);
- // info.used_m = used_filament_m + flushed_filament_m;
- // info.used_g = used_filament_g + flushed_filament_g;
- //} else { //Susi_not_impl
- info.used_m = used_filament_m;
- info.used_g = used_filament_g;
- //}
- slice_filaments_info.push_back(info);
- }
- /* only for test
- GCodeProcessorResult::SliceWarning sw;
- sw.msg = BED_TEMP_TOO_HIGH_THAN_FILAMENT;
- sw.level = 1;
- result->warnings.push_back(sw);
- */
- //warnings = result->warnings; //Susi_not_impl
- }
- //! macro used to mark string used at localization,
- //! return same string
- #define L(s) (s)
- #define _(s) Slic3r::I18N::translate(s)
- // Base class with error messages management
- class _BBS_3MF_Base
- {
- mutable std::mutex mutex_error;
- mutable std::vector<std::string> m_errors;
- protected:
- void add_error(const std::string& error) const { std::lock_guard l(mutex_error); m_errors.push_back(error); }
- void clear_errors() { m_errors.clear(); }
- public:
- void log_errors()
- {
- for (const std::string& error : m_errors)
- BOOST_LOG_TRIVIAL(error) << error;
- }
- };
- class _BBS_3MF_Importer : public _BBS_3MF_Base
- {
- typedef std::pair<std::string, int> Id; // BBS: encrypt
- struct Component
- {
- Id object_id;
- Transform3d transform;
- explicit Component(Id object_id)
- : object_id(object_id)
- , transform(Transform3d::Identity())
- {
- }
- Component(Id object_id, const Transform3d& transform)
- : object_id(object_id)
- , transform(transform)
- {
- }
- };
- typedef std::vector<Component> ComponentsList;
- struct Geometry
- {
- std::vector<Vec3f> vertices;
- std::vector<Vec3i32> triangles;
- std::vector<std::string> custom_supports;
- std::vector<std::string> custom_seam;
- std::vector<std::string> mmu_segmentation;
- // BBS
- std::vector<std::string> face_properties;
- bool empty() { return vertices.empty() || triangles.empty(); }
- // backup & restore
- void swap(Geometry& o) {
- std::swap(vertices, o.vertices);
- std::swap(triangles, o.triangles);
- std::swap(custom_supports, o.custom_supports);
- std::swap(custom_seam, o.custom_seam);
- }
- void reset() {
- vertices.clear();
- triangles.clear();
- custom_supports.clear();
- custom_seam.clear();
- mmu_segmentation.clear();
- }
- };
- struct CurrentObject
- {
- // ID of the object inside the 3MF file, 1 based.
- int id;
- // Index of the ModelObject in its respective Model, zero based.
- int model_object_idx;
- Geometry geometry;
- ModelObject* object;
- ComponentsList components;
- //BBS: sub object id
- //int subobject_id;
- std::string name;
- std::string uuid;
- int pid{-1};
- //bool is_model_object;
- CurrentObject() { reset(); }
- void reset() {
- id = -1;
- model_object_idx = -1;
- geometry.reset();
- object = nullptr;
- components.clear();
- //BBS: sub object id
- uuid.clear();
- name.clear();
- }
- };
- struct CurrentConfig
- {
- int object_id {-1};
- int volume_id {-1};
- };
- struct CurrentInstance
- {
- int object_id;
- int instance_id;
- int identify_id;
- };
- struct Instance
- {
- ModelInstance* instance;
- Transform3d transform;
- Instance(ModelInstance* instance, const Transform3d& transform)
- : instance(instance)
- , transform(transform)
- {
- }
- };
- struct Metadata
- {
- std::string key;
- std::string value;
- Metadata(const std::string& key, const std::string& value)
- : key(key)
- , value(value)
- {
- }
- };
- typedef std::vector<Metadata> MetadataList;
- struct ObjectMetadata
- {
- struct VolumeMetadata
- {
- //BBS: refine the part logic
- unsigned int first_triangle_id;
- unsigned int last_triangle_id;
- int subobject_id;
- MetadataList metadata;
- RepairedMeshErrors mesh_stats;
- ModelVolumeType part_type;
- //std::optional<TextConfiguration> text_configuration; //Susi_not_impl
- //std::optional<EmbossShape> shape_configuration; //Susi_not_impl
- VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id, ModelVolumeType type = ModelVolumeType::MODEL_PART)
- : first_triangle_id(first_triangle_id)
- , last_triangle_id(last_triangle_id)
- , part_type(type)
- , subobject_id(-1)
- {
- }
- VolumeMetadata(int sub_id, ModelVolumeType type = ModelVolumeType::MODEL_PART)
- : subobject_id(sub_id)
- , part_type(type)
- , first_triangle_id(0)
- , last_triangle_id(0)
- {
- }
- };
- typedef std::vector<VolumeMetadata> VolumeMetadataList;
- MetadataList metadata;
- VolumeMetadataList volumes;
- };
- struct CutObjectInfo
- {
- struct Connector
- {
- int volume_id;
- int type;
- float r_tolerance;
- float h_tolerance;
- };
- CutObjectBase id;
- std::vector<Connector> connectors;
- };
- // Map from a 1 based 3MF object ID to a 0 based ModelObject index inside m_model->objects.
- //typedef std::pair<std::string, int> Id; // BBS: encrypt
- typedef std::map<Id, CurrentObject> IdToCurrentObjectMap;
- typedef std::map<int, std::string> IndexToPathMap;
- typedef std::map<Id, int> IdToModelObjectMap;
- //typedef std::map<Id, ComponentsList> IdToAliasesMap;
- typedef std::vector<Instance> InstancesList;
- typedef std::map<int, ObjectMetadata> IdToMetadataMap;
- //typedef std::map<Id, Geometry> IdToGeometryMap;
- typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
- typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
- typedef std::map<int, CutObjectInfo> IdToCutObjectInfoMap;
- /*typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
- typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;*/
- using PathToEmbossShapeFileMap = std::map<std::string, std::shared_ptr<std::string>>;
- struct ObjectImporter
- {
- IdToCurrentObjectMap object_list;
- CurrentObject *current_object{nullptr};
- std::string object_path;
- std::string zip_path;
- _BBS_3MF_Importer *top_importer{nullptr};
- XML_Parser object_xml_parser;
- bool obj_parse_error { false };
- std::string obj_parse_error_message;
- //local parsed datas
- std::string obj_curr_metadata_name;
- std::string obj_curr_characters;
- float object_unit_factor;
- int object_current_color_group{-1};
- std::map<int, std::string> object_group_id_to_color;
- bool is_bbl_3mf { false };
- ObjectImporter(_BBS_3MF_Importer *importer, std::string file_path, std::string obj_path)
- {
- top_importer = importer;
- object_path = obj_path;
- zip_path = file_path;
- }
- ~ObjectImporter()
- {
- _destroy_object_xml_parser();
- }
- void _destroy_object_xml_parser()
- {
- if (object_xml_parser != nullptr) {
- XML_ParserFree(object_xml_parser);
- object_xml_parser = nullptr;
- }
- }
- void _stop_object_xml_parser(const std::string& msg = std::string())
- {
- assert(! obj_parse_error);
- assert(obj_parse_error_message.empty());
- assert(object_xml_parser != nullptr);
- obj_parse_error = true;
- obj_parse_error_message = msg;
- XML_StopParser(object_xml_parser, false);
- }
- bool object_parse_error() const { return obj_parse_error; }
- const char* object_parse_error_message() const {
- return obj_parse_error ?
- // The error was signalled by the user code, not the expat parser.
- (obj_parse_error_message.empty() ? "Invalid 3MF format" : obj_parse_error_message.c_str()) :
- // The error was signalled by the expat parser.
- XML_ErrorString(XML_GetErrorCode(object_xml_parser));
- }
- bool _extract_object_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- bool extract_object_model()
- {
- mz_zip_archive archive;
- //mz_zip_archive_file_stat stat;
- mz_zip_zero_struct(&archive);
- if (!open_zip_reader(&archive, zip_path)) {
- top_importer->add_error("Unable to open the zipfile "+ zip_path);
- return false;
- }
- if (!top_importer->_extract_from_archive(archive, object_path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) {
- return _extract_object_from_archive(archive, stat);
- }, top_importer->m_load_restore)) {
- std::string error_msg = std::string("Archive does not contain a valid model for ") + object_path;
- top_importer->add_error(error_msg);
- close_zip_reader(&archive);
- return false;
- }
- close_zip_reader(&archive);
- if (obj_parse_error) {
- //already add_error inside
- //top_importer->add_error(object_parse_error_message());
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Found error while extrace object %1%\n")%object_path;
- return false;
- }
- return true;
- }
- bool _handle_object_start_model(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_model();
- bool _handle_object_start_resources(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_resources();
- bool _handle_object_start_object(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_object();
- bool _handle_object_start_color_group(const char **attributes, unsigned int num_attributes);
- bool _handle_object_end_color_group();
- bool _handle_object_start_color(const char **attributes, unsigned int num_attributes);
- bool _handle_object_end_color();
- bool _handle_object_start_mesh(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_mesh();
- bool _handle_object_start_vertices(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_vertices();
- bool _handle_object_start_vertex(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_vertex();
- bool _handle_object_start_triangles(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_triangles();
- bool _handle_object_start_triangle(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_triangle();
- bool _handle_object_start_components(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_components();
- bool _handle_object_start_component(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_component();
- bool _handle_object_start_metadata(const char** attributes, unsigned int num_attributes);
- bool _handle_object_end_metadata();
- void _handle_object_start_model_xml_element(const char* name, const char** attributes);
- void _handle_object_end_model_xml_element(const char* name);
- void _handle_object_xml_characters(const XML_Char* s, int len);
- // callbacks to parse the .model file of an object
- static void XMLCALL _handle_object_start_model_xml_element(void* userData, const char* name, const char** attributes);
- static void XMLCALL _handle_object_end_model_xml_element(void* userData, const char* name);
- static void XMLCALL _handle_object_xml_characters(void* userData, const XML_Char* s, int len);
- };
- // Version of the 3mf file
- unsigned int m_version;
- bool m_check_version = false;
- bool m_load_model = false;
- bool m_load_aux = false;
- bool m_load_config = false;
- // backup & restore
- bool m_load_restore = false;
- std::string m_backup_path;
- std::string m_origin_file;
- // Semantic version of Orca Slicer, that generated this 3MF.
- boost::optional<Semver> m_bambuslicer_generator_version;
- unsigned int m_fdm_supports_painting_version = 0;
- unsigned int m_seam_painting_version = 0;
- unsigned int m_mm_painting_version = 0;
- std::string m_model_id;
- std::string m_contry_code;
- std::string m_designer;
- std::string m_designer_user_id;
- std::string m_designer_cover;
- //ModelInfo model_info; //Susi_not_impl
- //BBLProject project_info; //Susi_not_impl
- std::string m_profile_title;
- std::string m_profile_cover;
- std::string m_Profile_description;
- std::string m_profile_user_id;
- std::string m_profile_user_name;
- XML_Parser m_xml_parser;
- // Error code returned by the application side of the parser. In that case the expat may not reliably deliver the error state
- // after returning from XML_Parse() function, thus we keep the error state here.
- bool m_parse_error { false };
- std::string m_parse_error_message;
- Model* m_model;
- float m_unit_factor;
- CurrentObject* m_curr_object{nullptr};
- IdToCurrentObjectMap m_current_objects;
- IndexToPathMap m_index_paths;
- IdToModelObjectMap m_objects;
- //IdToAliasesMap m_objects_aliases;
- InstancesList m_instances;
- //IdToGeometryMap m_geometries;
- //IdToGeometryMap m_orig_geometries; // backup & restore
- CurrentConfig m_curr_config;
- IdToMetadataMap m_objects_metadata;
- IdToCutObjectInfoMap m_cut_object_infos;
- IdToLayerHeightsProfileMap m_layer_heights_profiles;
- IdToLayerConfigRangesMap m_layer_config_ranges;
- /*IdToSlaSupportPointsMap m_sla_support_points;
- IdToSlaDrainHolesMap m_sla_drain_holes;*/
- PathToEmbossShapeFileMap m_path_to_emboss_shape_files;
- std::string m_curr_metadata_name;
- std::string m_curr_characters;
- std::string m_name;
- std::string m_sub_model_path;
- std::string m_start_part_path;
- std::string m_thumbnail_path;
- std::string m_thumbnail_middle;
- std::string m_thumbnail_small;
- std::vector<std::string> m_sub_model_paths;
- std::vector<ObjectImporter*> m_object_importers;
- std::map<int, ModelVolume*> m_shared_meshes;
- //BBS: plater related structures
- bool m_is_bbl_3mf { false };
- bool m_parsing_slice_info { false };
- PlateDataMaps m_plater_data;
- PlateData* m_curr_plater;
- CurrentInstance m_curr_instance;
- int m_current_color_group{-1};
- std::map<int, std::string> m_group_id_to_color;
- public:
- _BBS_3MF_Importer();
- ~_BBS_3MF_Importer();
- //BBS: add plate data related logic
- // add backup & restore logic
- bool load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config,
- ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn = nullptr, /*BBLProject *project = nullptr,*/ int plate_id = 0);
- bool get_thumbnail(const std::string &filename, std::string &data);
- bool load_gcode_3mf_from_stream(std::istream & data, Model& model, PlateDataPtrs& plate_data_list, DynamicPrintConfig& config, Semver& file_version);
- unsigned int version() const { return m_version; }
- private:
- void _destroy_xml_parser();
- void _stop_xml_parser(const std::string& msg = std::string());
- bool parse_error() const { return m_parse_error; }
- const char* parse_error_message() const {
- return m_parse_error ?
- // The error was signalled by the user code, not the expat parser.
- (m_parse_error_message.empty() ? "Invalid 3MF format" : m_parse_error_message.c_str()) :
- // The error was signalled by the expat parser.
- XML_ErrorString(XML_GetErrorCode(m_xml_parser));
- }
- //BBS: add plate data related logic
- // add backup & restore logic
- bool _load_model_from_file(std::string filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Import3mfProgressFn proFn = nullptr,
- /*BBLProject* project = nullptr, */int plate_id = 0);
- bool _is_svg_shape_file(const std::string &filename) const;
- bool _extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)>, bool restore = false);
- bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
- bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
- bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
- void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
- void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, const std::string& archive_filename);
- //BBS: add project config file logic
- void _extract_project_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, Model& model);
- //BBS: extract project embedded presets
- void _extract_project_embedded_presets_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, std::vector<Preset*>&project_presets, Model& model, Preset::Type type, bool use_json = true);
- void _extract_auxiliary_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
- void _extract_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
- void _extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat);
- // handlers to parse the .model file
- void _handle_start_model_xml_element(const char* name, const char** attributes);
- void _handle_end_model_xml_element(const char* name);
- void _handle_xml_characters(const XML_Char* s, int len);
- // handlers to parse the MODEL_CONFIG_FILE file
- void _handle_start_config_xml_element(const char* name, const char** attributes);
- void _handle_end_config_xml_element(const char* name);
- bool _handle_start_model(const char** attributes, unsigned int num_attributes);
- bool _handle_end_model();
- bool _handle_start_resources(const char** attributes, unsigned int num_attributes);
- bool _handle_end_resources();
- bool _handle_start_object(const char** attributes, unsigned int num_attributes);
- bool _handle_end_object();
- bool _handle_start_color_group(const char **attributes, unsigned int num_attributes);
- bool _handle_end_color_group();
- bool _handle_start_color(const char **attributes, unsigned int num_attributes);
- bool _handle_end_color();
- bool _handle_start_mesh(const char** attributes, unsigned int num_attributes);
- bool _handle_end_mesh();
- bool _handle_start_vertices(const char** attributes, unsigned int num_attributes);
- bool _handle_end_vertices();
- bool _handle_start_vertex(const char** attributes, unsigned int num_attributes);
- bool _handle_end_vertex();
- bool _handle_start_triangles(const char** attributes, unsigned int num_attributes);
- bool _handle_end_triangles();
- bool _handle_start_triangle(const char** attributes, unsigned int num_attributes);
- bool _handle_end_triangle();
- bool _handle_start_components(const char** attributes, unsigned int num_attributes);
- bool _handle_end_components();
- bool _handle_start_component(const char** attributes, unsigned int num_attributes);
- bool _handle_end_component();
- bool _handle_start_build(const char** attributes, unsigned int num_attributes);
- bool _handle_end_build();
- bool _handle_start_item(const char** attributes, unsigned int num_attributes);
- bool _handle_end_item();
- bool _handle_start_metadata(const char** attributes, unsigned int num_attributes);
- bool _handle_end_metadata();
- bool _handle_start_text_configuration(const char** attributes, unsigned int num_attributes);
- bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes);
- bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
- void _apply_transform(ModelInstance& instance, const Transform3d& transform);
- bool _handle_start_config(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config();
- bool _handle_start_config_object(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_object();
- bool _handle_start_config_volume(const char** attributes, unsigned int num_attributes);
- bool _handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_volume();
- bool _handle_end_config_volume_mesh();
- bool _handle_start_config_metadata(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_metadata();
- bool _handle_start_config_filament(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_filament();
- bool _handle_start_config_warning(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_warning();
- //BBS: add plater config parse functions
- bool _handle_start_config_plater(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_plater();
- bool _handle_start_config_plater_instance(const char** attributes, unsigned int num_attributes);
- bool _handle_end_config_plater_instance();
- bool _handle_start_assemble(const char** attributes, unsigned int num_attributes);
- bool _handle_end_assemble();
- bool _handle_start_assemble_item(const char** attributes, unsigned int num_attributes);
- bool _handle_end_assemble_item();
- bool _handle_start_text_info_item(const char **attributes, unsigned int num_attributes);
- bool _handle_end_text_info_item();
- // BBS: callbacks to parse the .rels file
- static void XMLCALL _handle_start_relationships_element(void* userData, const char* name, const char** attributes);
- static void XMLCALL _handle_end_relationships_element(void* userData, const char* name);
- void _handle_start_relationships_element(const char* name, const char** attributes);
- void _handle_end_relationships_element(const char* name);
- bool _handle_start_relationship(const char** attributes, unsigned int num_attributes);
- void _generate_current_object_list(std::vector<Component> &sub_objects, Id object_id, IdToCurrentObjectMap& current_objects);
- bool _generate_volumes_new(ModelObject& object, const std::vector<Component> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, const DynamicPrintConfig &config, ConfigSubstitutionContext& config_substitutions);
- //bool _generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions);
- // callbacks to parse the .model file
- static void XMLCALL _handle_start_model_xml_element(void* userData, const char* name, const char** attributes);
- static void XMLCALL _handle_end_model_xml_element(void* userData, const char* name);
- static void XMLCALL _handle_xml_characters(void* userData, const XML_Char* s, int len);
- // callbacks to parse the MODEL_CONFIG_FILE file
- static void XMLCALL _handle_start_config_xml_element(void* userData, const char* name, const char** attributes);
- static void XMLCALL _handle_end_config_xml_element(void* userData, const char* name);
- };
- _BBS_3MF_Importer::_BBS_3MF_Importer()
- : m_version(0)
- , m_check_version(false)
- , m_xml_parser(nullptr)
- , m_model(nullptr)
- , m_unit_factor(1.0f)
- , m_curr_metadata_name("")
- , m_curr_characters("")
- , m_name("")
- , m_curr_plater(nullptr)
- {
- }
- _BBS_3MF_Importer::~_BBS_3MF_Importer()
- {
- _destroy_xml_parser();
- clear_errors();
- if (m_curr_object) {
- delete m_curr_object;
- m_curr_object = nullptr;
- }
- m_current_objects.clear();
- m_index_paths.clear();
- m_objects.clear();
- m_instances.clear();
- m_objects_metadata.clear();
- m_curr_metadata_name.clear();
- m_curr_characters.clear();
- std::map<int, PlateData*>::iterator it = m_plater_data.begin();
- while (it != m_plater_data.end())
- {
- delete it->second;
- it++;
- }
- m_plater_data.clear();
- }
- //BBS: add plate data related logic
- // add backup & restore logic
- bool _BBS_3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config,
- ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn, /*BBLProject *project,*/ int plate_id)
- {
- m_version = 0;
- m_fdm_supports_painting_version = 0;
- m_seam_painting_version = 0;
- m_mm_painting_version = 0;
- m_check_version = strategy & LoadStrategy::CheckVersion;
- //BBS: auxiliary data
- m_load_model = strategy & LoadStrategy::LoadModel;
- m_load_aux = strategy & LoadStrategy::LoadAuxiliary;
- m_load_restore = strategy & LoadStrategy::Restore;
- m_load_config = strategy & LoadStrategy::LoadConfig;
- m_model = &model;
- m_unit_factor = 1.0f;
- m_curr_object = nullptr;
- m_current_objects.clear();
- m_index_paths.clear();
- m_objects.clear();
- //m_objects_aliases.clear();
- m_instances.clear();
- //m_geometries.clear();
- m_curr_config.object_id = -1;
- m_curr_config.volume_id = -1;
- m_objects_metadata.clear();
- m_layer_heights_profiles.clear();
- m_layer_config_ranges.clear();
- //m_sla_support_points.clear();
- m_curr_metadata_name.clear();
- m_curr_characters.clear();
- //BBS: plater data init
- m_plater_data.clear();
- m_curr_instance.object_id = -1;
- m_curr_instance.instance_id = -1;
- m_curr_instance.identify_id = 0;
- clear_errors();
- // restore
- //if (m_load_restore) {
- // m_backup_path = filename.substr(0, filename.size() - 5);
- // model.set_backup_path(m_backup_path);
- // try {
- // if (boost::filesystem::exists(model.get_backup_path() + "/origin.txt"))
- // load_string_file(model.get_backup_path() + "/origin.txt", m_origin_file);
- // } catch (...) {}
- // save_string_file(
- // model.get_backup_path() + "/lock.txt",
- // boost::lexical_cast<std::string>(get_current_pid()));
- //}
- //else {
- // m_backup_path = model.get_backup_path();
- //}
- bool result = _load_model_from_file(filename, model, plate_data_list, project_presets, config, config_substitutions, proFn, /*project,*/ plate_id);
- is_bbl_3mf = m_is_bbl_3mf;
- if (m_bambuslicer_generator_version)
- file_version = *m_bambuslicer_generator_version;
- if (result && plate_data_list.size() > 0) {
- if(config.opt<ConfigOptionBool>("gcode_label_objects") == nullptr)
- config.set_key_value("gcode_label_objects", config.get_option_def("gcode_label_objects")->default_value->clone());
- bool has_label_objests = config.opt<ConfigOptionBool>("gcode_label_objects")->value;
- for (PlateData *plate : plate_data_list)
- has_label_objests = has_label_objests || plate->is_label_object_enabled;
- config.opt<ConfigOptionBool>("gcode_label_objects")->value = has_label_objests;
- std::string print_vars = config.opt<ConfigOptionString>("print_custom_variables") == nullptr ? "" : config.opt<ConfigOptionString>("print_custom_variables")->value;
- if (print_vars.find("plate_name") == std::string::npos && plate_data_list.front()) {
- std::string plate_name = "";
- for (PlateData *plate : plate_data_list)
- plate_name += plate_name.empty() ? plate->plate_name : std::string(" ; ") + plate->plate_name;
- boost::replace_all(plate_name, "\"", "'");
- if (!print_vars.empty() && print_vars.back() != '\n')
- print_vars += std::string("\n");
- print_vars += std::string("plate_name=\"") + plate_name + std::string("\"\n");
- config.set_key_value("print_custom_variables", new ConfigOptionString(print_vars));
- }
- }
- // save for restore
- //if (result && m_load_aux && !m_load_restore) {
- // save_string_file(model.get_backup_path() + "/origin.txt", filename);
- //}
- //if (m_load_restore && !result) // not clear failed backup data for later analyze
- // model.set_backup_path("detach");
- return result;
- }
- bool _BBS_3MF_Importer::get_thumbnail(const std::string &filename, std::string &data)
- {
- mz_zip_archive archive;
- mz_zip_zero_struct(&archive);
- struct close_lock
- {
- mz_zip_archive *archive;
- void close()
- {
- if (archive) {
- close_zip_reader(archive);
- archive = nullptr;
- }
- }
- ~close_lock() { close(); }
- } lock{&archive};
- if (!open_zip_reader(&archive, filename)) {
- add_error("Unable to open the file "+filename);
- return false;
- }
- // BBS: load relationships
- if (!_extract_xml_from_archive(archive, RELATIONSHIPS_FILE, _handle_start_relationships_element, _handle_end_relationships_element))
- return false;
- if (m_thumbnail_middle.empty()) m_thumbnail_middle = m_thumbnail_path;
- if (!m_thumbnail_middle.empty()) {
- return _extract_from_archive(archive, m_thumbnail_middle, [&data](auto &archive, auto const &stat) -> bool {
- data.resize(stat.m_uncomp_size);
- return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, data.data(), data.size(), 0);
- });
- }
- return _extract_from_archive(archive, THUMBNAIL_FILE, [&data](auto &archive, auto const &stat) -> bool {
- data.resize(stat.m_uncomp_size);
- return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, data.data(), data.size(), 0);
- });
- }
- static size_t mz_zip_read_istream(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
- {
- auto & is = *reinterpret_cast<std::istream*>(pOpaque);
- is.seekg(file_ofs, std::istream::beg);
- if (!is)
- return 0;
- is.read((char *)pBuf, n);
- return is.gcount();
- }
- bool _BBS_3MF_Importer::load_gcode_3mf_from_stream(std::istream &data, Model &model, PlateDataPtrs &plate_data_list, DynamicPrintConfig &config, Semver &file_version)
- {
- mz_zip_archive archive;
- mz_zip_zero_struct(&archive);
- archive.m_pRead = mz_zip_read_istream;
- archive.m_pIO_opaque = &data;
- data.seekg(0, std::istream::end);
- mz_uint64 size = data.tellg();
- data.seekg(0, std::istream::beg);
- if (!mz_zip_reader_init(&archive, size, 0))
- return false;
- struct close_lock
- {
- mz_zip_archive *archive;
- void close()
- {
- if (archive) {
- mz_zip_reader_end(archive);
- archive = nullptr;
- }
- }
- ~close_lock() { close(); }
- } lock{&archive};
- // BBS: load relationships
- if (!_extract_xml_from_archive(archive, RELATIONSHIPS_FILE, _handle_start_relationships_element, _handle_end_relationships_element))
- return false;
- if (m_start_part_path.empty())
- return false;
- //extract model files
- m_model = &model;
- if (!_extract_from_archive(archive, m_start_part_path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) {
- return _extract_model_from_archive(archive, stat);
- })) {
- add_error("Archive does not contain a valid model");
- return false;
- }
- //if (!m_designer.empty()) {
- // m_model->design_info = std::make_shared<ModelDesignInfo>();
- // m_model->design_info->DesignerUserId = m_designer_user_id;
- // m_model->design_info->Designer = m_designer;
- //}
- //m_model->profile_info = std::make_shared<ModelProfileInfo>();
- //m_model->profile_info->ProfileTile = m_profile_title;
- //m_model->profile_info->ProfileCover = m_profile_cover;
- //m_model->profile_info->ProfileDescription = m_Profile_description;
- //m_model->profile_info->ProfileUserId = m_profile_user_id;
- //m_model->profile_info->ProfileUserName = m_profile_user_name;
- //m_model->model_info = std::make_shared<ModelInfo>();
- //m_model->model_info->load(model_info); //Susi_not_impl
- if (m_thumbnail_middle.empty()) m_thumbnail_middle = m_thumbnail_path;
- if (m_thumbnail_small.empty()) m_thumbnail_small = m_thumbnail_path;
- if (!m_thumbnail_small.empty() && m_thumbnail_small.front() == '/')
- m_thumbnail_small.erase(m_thumbnail_small.begin());
- if (!m_thumbnail_middle.empty() && m_thumbnail_middle.front() == '/')
- m_thumbnail_middle.erase(m_thumbnail_middle.begin());
- //m_model->model_info->metadata_items.emplace("Thumbnail", m_thumbnail_middle);
- //m_model->model_info->metadata_items.emplace("Poster", m_thumbnail_middle); //Susi_not_impl
- // we then loop again the entries to read other files stored in the archive
- mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
- mz_zip_archive_file_stat stat;
- for (mz_uint i = 0; i < num_entries; ++i) {
- if (mz_zip_reader_file_stat(&archive, i, &stat)) {
- std::string name(stat.m_filename);
- std::replace(name.begin(), name.end(), '\\', '/');
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract %1%th file %2%, total=%3%\n")%(i+1)%name%num_entries;
- if (boost::algorithm::iequals(name, BBS_PROJECT_CONFIG_FILE)) {
- // extract slic3r print config file
- ConfigSubstitutionContext config_substitutions(ForwardCompatibilitySubstitutionRule::Disable);
- _extract_project_config_from_archive(archive, stat, config, config_substitutions, model);
- }
- else if (boost::algorithm::iequals(name, BBS_MODEL_CONFIG_FILE)) {
- // extract slic3r model config file
- if (!_extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element)) {
- add_error("Archive does not contain a valid model config");
- return false;
- }
- }
- else if (boost::algorithm::iequals(name, SLICE_INFO_CONFIG_FILE)) {
- m_parsing_slice_info = true;
- //extract slice info from archive
- _extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element);
- m_parsing_slice_info = false;
- }
- }
- }
- //BBS: load the plate info into plate_data_list
- std::map<int, PlateData*>::iterator it = m_plater_data.begin();
- plate_data_list.clear();
- plate_data_list.reserve(m_plater_data.size());
- for (unsigned int i = 0; i < m_plater_data.size(); i++)
- {
- PlateData* plate = new PlateData();
- plate_data_list.push_back(plate);
- }
- while (it != m_plater_data.end())
- {
- if (it->first > m_plater_data.size())
- {
- add_error("invalid plate index");
- return false;
- }
- PlateData * plate = plate_data_list[it->first-1];
- plate->locked = it->second->locked;
- plate->plate_index = it->second->plate_index-1;
- plate->obj_inst_map = it->second->obj_inst_map;
- plate->gcode_file = it->second->gcode_file;
- plate->gcode_prediction = it->second->gcode_prediction;
- plate->gcode_weight = it->second->gcode_weight;
- plate->toolpath_outside = it->second->toolpath_outside;
- plate->is_support_used = it->second->is_support_used;
- plate->is_label_object_enabled = it->second->is_label_object_enabled;
- plate->skipped_objects = it->second->skipped_objects;
- plate->slice_filaments_info = it->second->slice_filaments_info;
- plate->warnings = it->second->warnings;
- plate->thumbnail_file = it->second->thumbnail_file;
- if (plate->thumbnail_file.empty()) {
- plate->thumbnail_file = plate->gcode_file;
- boost::algorithm::replace_all(plate->thumbnail_file, ".gcode", ".png");
- }
- //plate->pattern_file = it->second->pattern_file;
- plate->top_file = it->second->top_file;
- plate->pick_file = it->second->pick_file.empty();
- plate->pattern_bbox_file = it->second->pattern_bbox_file.empty();
- plate->config = it->second->config;
- if (!plate->thumbnail_file.empty())
- _extract_from_archive(archive, plate->thumbnail_file, [&pixels = plate_data_list[it->first - 1]->plate_thumbnail.pixels](auto &archive, auto const &stat) -> bool {
- pixels.resize(stat.m_uncomp_size);
- return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, pixels.data(), pixels.size(), 0);
- });
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate->thumbnail_file;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_file=%1%, pick_thumbnail_file=%2%")%plate->top_file %plate->pick_file;
- it++;
- }
- lock.close();
- return true;
- }
- void _BBS_3MF_Importer::_destroy_xml_parser()
- {
- if (m_xml_parser != nullptr) {
- XML_ParserFree(m_xml_parser);
- m_xml_parser = nullptr;
- }
- }
- void _BBS_3MF_Importer::_stop_xml_parser(const std::string &msg)
- {
- assert(! m_parse_error);
- assert(m_parse_error_message.empty());
- assert(m_xml_parser != nullptr);
- m_parse_error = true;
- m_parse_error_message = msg;
- XML_StopParser(m_xml_parser, false);
- }
- //BBS: add plate data related logic
- bool _BBS_3MF_Importer::_load_model_from_file(
- std::string filename,
- Model& model,
- PlateDataPtrs& plate_data_list,
- std::vector<Preset*>& project_presets,
- DynamicPrintConfig& config,
- ConfigSubstitutionContext& config_substitutions,
- Import3mfProgressFn proFn,
- /*BBLProject *project,*/ //Susi_not_impl
- int plate_id)
- {
- bool cb_cancel = false;
- //BBS progress point
- // prepare restore
- if (m_load_restore) {
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_RESTORE\n");
- if (proFn) {
- proFn(IMPORT_STAGE_RESTORE, 0, 1, cb_cancel);
- if (cb_cancel)
- return false;
- }
- }
- //BBS progress point
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_OPEN, m_load_restore=%1%\n")%m_load_restore;
- if (proFn) {
- proFn(IMPORT_STAGE_OPEN, 0, 1, cb_cancel);
- if (cb_cancel)
- return false;
- }
- mz_zip_archive archive;
- mz_zip_zero_struct(&archive);
- struct close_lock
- {
- mz_zip_archive * archive;
- void close() {
- if (archive) {
- close_zip_reader(archive);
- archive = nullptr;
- }
- }
- ~close_lock() {
- close();
- }
- } lock{ &archive };
- if (!open_zip_reader(&archive, filename)) {
- add_error("Unable to open the file"+filename);
- return false;
- }
- mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
- mz_zip_archive_file_stat stat;
- m_name = boost::filesystem::path(filename).stem().string();
- //BBS progress point
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_READ_FILES\n");
- if (proFn) {
- proFn(IMPORT_STAGE_READ_FILES, 0, 3, cb_cancel);
- if (cb_cancel)
- return false;
- }
- // BBS: load relationships
- if (!_extract_xml_from_archive(archive, RELATIONSHIPS_FILE, _handle_start_relationships_element, _handle_end_relationships_element))
- return false;
- if (m_start_part_path.empty())
- return false;
- // BBS: load sub models (Production Extension)
- std::string sub_rels = m_start_part_path;
- sub_rels.insert(boost::find_last(sub_rels, "/").end() - sub_rels.begin(), "_rels/");
- sub_rels.append(".rels");
- if (sub_rels.front() == '/') sub_rels = sub_rels.substr(1);
- //check whether sub relation file is exist or not
- int sub_index = mz_zip_reader_locate_file(&archive, sub_rels.c_str(), nullptr, 0);
- if (sub_index == -1) {
- //no submodule files found, use only one 3dmodel.model
- }
- else {
- _extract_xml_from_archive(archive, sub_rels, _handle_start_relationships_element, _handle_end_relationships_element);
- int index = 0;
- #if 0
- for (auto path : m_sub_model_paths) {
- if (proFn) {
- proFn(IMPORT_STAGE_READ_FILES, ++index, 3 + m_sub_model_paths.size(), cb_cancel);
- if (cb_cancel)
- return false;
- }
- else
- ++index;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", read %1%th sub model file %2%\n")%index %path;
- m_sub_model_path = path;
- if (!_extract_from_archive(archive, path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) {
- return _extract_model_from_archive(archive, stat);
- }, m_load_restore)) {
- add_error("Archive does not contain a valid model");
- return false;
- }
- m_sub_model_path.clear();
- }
- #else
- for (auto path : m_sub_model_paths) {
- ObjectImporter *object_importer = new ObjectImporter(this, filename, path);
- m_object_importers.push_back(object_importer);
- }
- bool object_load_result = true;
- std::mutex mutex_load;
- tbb::parallel_for(
- tbb::blocked_range<size_t>(0, m_object_importers.size()),
- [this, &mutex_load, &object_load_result](const tbb::blocked_range<size_t>& importer_range) {
- CNumericLocalesSetter locales_setter;
- for (size_t object_index = importer_range.begin(); object_index < importer_range.end(); ++ object_index) {
- bool result = m_object_importers[object_index]->extract_object_model();
- {
- std::lock_guard l(mutex_load);
- object_load_result &= result;
- }
- }
- }
- );
- if (!object_load_result) {
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", loading sub-objects error\n");
- return false;
- }
- //merge these objects into one
- for (auto obj_importer : m_object_importers) {
- for (const IdToCurrentObjectMap::value_type& obj : obj_importer->object_list)
- m_current_objects.insert({ std::move(obj.first), std::move(obj.second)});
- for (auto group_color : obj_importer->object_group_id_to_color)
- m_group_id_to_color.insert(std::move(group_color));
- delete obj_importer;
- }
- m_object_importers.clear();
- #endif
- // BBS: load root model
- if (proFn) {
- proFn(IMPORT_STAGE_READ_FILES, 2, 3, cb_cancel);
- if (cb_cancel)
- return false;
- }
- }
- //extract model files
- if (!_extract_from_archive(archive, m_start_part_path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) {
- return _extract_model_from_archive(archive, stat);
- })) {
- add_error("Archive does not contain a valid model");
- return false;
- }
- //if (!m_designer.empty()) {
- // m_model->design_info = std::make_shared<ModelDesignInfo>();
- // m_model->design_info->DesignerUserId = m_designer_user_id;
- // m_model->design_info->Designer = m_designer;
- //} //Susi_not_impl
- //m_model->profile_info = std::make_shared<ModelProfileInfo>();
- //m_model->profile_info->ProfileTile = m_profile_title;
- //m_model->profile_info->ProfileCover = m_profile_cover;
- //m_model->profile_info->ProfileDescription = m_Profile_description;
- //m_model->profile_info->ProfileUserId = m_profile_user_id;
- //m_model->profile_info->ProfileUserName = m_profile_user_name; //Susi_not_impl
- //m_model->model_info = std::make_shared<ModelInfo>();
- //m_model->model_info->load(model_info);
- //if (!m_thumbnail_small.empty()) m_model->model_info->metadata_items.emplace("Thumbnail_Small", m_thumbnail_small);
- //if (!m_thumbnail_middle.empty()) m_model->model_info->metadata_items.emplace("Thumbnail_Middle", m_thumbnail_middle); //Susi_not_impl
- //got project id
- //if (project) {
- // project->project_model_id = m_model_id;
- // project->project_country_code = m_contry_code;
- //}
- // Orca: skip version check
- bool dont_load_config = !m_load_config;
- // if (m_bambuslicer_generator_version) {
- // Semver app_version = *(Semver::parse(SoftFever_VERSION));
- // Semver file_version = *m_bambuslicer_generator_version;
- // if (file_version.maj() != app_version.maj())
- // dont_load_config = true;
- // }
- // else {
- // m_bambuslicer_generator_version = Semver::parse("0.0.0.0");
- // dont_load_config = true;
- // }
- // we then loop again the entries to read other files stored in the archive
- for (mz_uint i = 0; i < num_entries; ++i) {
- if (mz_zip_reader_file_stat(&archive, i, &stat)) {
- //BBS progress point
- if (proFn) {
- proFn(IMPORT_STAGE_EXTRACT, i, num_entries, cb_cancel);
- if (cb_cancel)
- return false;
- }
- std::string name(stat.m_filename);
- std::replace(name.begin(), name.end(), '\\', '/');
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract %1%th file %2%, total=%3%")%(i+1)%name%num_entries;
- if (name.find("/../") != std::string::npos) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", find file path including /../, not valid, skip it\n");
- continue;
- }
- if (boost::algorithm::iequals(name, BBS_LAYER_HEIGHTS_PROFILE_FILE)) {
- // extract slic3r layer heights profile file
- _extract_layer_heights_profile_config_from_archive(archive, stat);
- }
- else
- if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) {
- // extract slic3r layer config ranges file
- _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
- }
- //BBS: disable SLA related files currently
- /*else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE)) {
- // extract sla support points file
- _extract_sla_support_points_from_archive(archive, stat);
- }
- else if (boost::algorithm::iequals(name, SLA_DRAIN_HOLES_FILE)) {
- // extract sla support points file
- _extract_sla_drain_holes_from_archive(archive, stat);
- }*/
- //BBS: project setting file
- //if (!dont_load_config && boost::algorithm::iequals(name, BBS_PRINT_CONFIG_FILE)) {
- // extract slic3r print config file
- // _extract_print_config_from_archive(archive, stat, config, config_substitutions, filename);
- //} else
- if (!dont_load_config && boost::algorithm::iequals(name, BBS_PROJECT_CONFIG_FILE)) {
- // extract slic3r print config file
- _extract_project_config_from_archive(archive, stat, config, config_substitutions, model);
- }
- else if (boost::algorithm::iequals(name, CUT_INFORMATION_FILE)) {
- // extract object cut info
- _extract_cut_information_from_archive(archive, stat, config_substitutions);
- }
- //BBS: project embedded presets
- else if (!dont_load_config && boost::algorithm::istarts_with(name, PROJECT_EMBEDDED_PRINT_PRESETS_FILE)) {
- // extract slic3r layer config ranges file
- _extract_project_embedded_presets_from_archive(archive, stat, project_presets, model, Preset::TYPE_FFF_PRINT, false);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, PROJECT_EMBEDDED_SLICE_PRESETS_FILE)) {
- // extract slic3r layer config ranges file
- _extract_project_embedded_presets_from_archive(archive, stat, project_presets, model, Preset::TYPE_FFF_PRINT);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, PROJECT_EMBEDDED_FILAMENT_PRESETS_FILE)) {
- // extract slic3r layer config ranges file
- _extract_project_embedded_presets_from_archive(archive, stat, project_presets, model, Preset::TYPE_FFF_FILAMENT);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, PROJECT_EMBEDDED_PRINTER_PRESETS_FILE)) {
- // extract slic3r layer config ranges file
- _extract_project_embedded_presets_from_archive(archive, stat, project_presets, model, Preset::TYPE_PRINTER);
- }
- else if (!dont_load_config && boost::algorithm::iequals(name, CUSTOM_GCODE_PER_PRINT_Z_FILE)) {
- // extract slic3r layer config ranges file
- _extract_custom_gcode_per_print_z_from_archive(archive, stat);
- }
- else if (boost::algorithm::iequals(name, BBS_MODEL_CONFIG_FILE)) {
- // extract slic3r model config file
- if (!_extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element)) {
- add_error("Archive does not contain a valid model config");
- return false;
- }
- }
- else if (_is_svg_shape_file(name)) {
- _extract_embossed_svg_shape_file(name, archive, stat);
- }
- else if (!dont_load_config && boost::algorithm::iequals(name, SLICE_INFO_CONFIG_FILE)) {
- m_parsing_slice_info = true;
- //extract slice info from archive
- _extract_xml_from_archive(archive, stat, _handle_start_config_xml_element, _handle_end_config_xml_element);
- m_parsing_slice_info = false;
- }
- else if (boost::algorithm::istarts_with(name, AUXILIARY_DIR)) {
- // extract auxiliary directory to temp directory, do nothing for restore
- if (m_load_aux && !m_load_restore)
- _extract_auxiliary_file_from_archive(archive, stat, model);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, METADATA_DIR) && boost::algorithm::iends_with(name, GCODE_EXTENSION)) {
- //load gcode files
- _extract_file_from_archive(archive, stat);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, METADATA_DIR) && boost::algorithm::iends_with(name, THUMBNAIL_EXTENSION)) {
- //BBS parsing pattern thumbnail and plate thumbnails
- _extract_file_from_archive(archive, stat);
- }
- else if (!dont_load_config && boost::algorithm::istarts_with(name, METADATA_DIR) && boost::algorithm::iends_with(name, CALIBRATION_INFO_EXTENSION)) {
- //BBS parsing pattern config files
- _extract_file_from_archive(archive, stat);
- }
- else {
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", %1% skipped, already parsed or a directory or not supported\n")%name;
- }
- }
- }
- lock.close();
- if (!m_is_bbl_3mf) {
- // if the 3mf was not produced by OrcaSlicer and there is more than one instance,
- // split the object in as many objects as instances
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", found 3mf from other vendor, split as instance");
- for (const IdToModelObjectMap::value_type& object : m_objects) {
- if (object.second >= int(m_model->objects.size())) {
- add_error("3rd 3mf, invalid object, id: "+std::to_string(object.first.second));
- return false;
- }
- ModelObject* model_object = m_model->objects[object.second];
- if (model_object->instances.size() > 1) {
- IdToCurrentObjectMap::const_iterator current_object = m_current_objects.find(object.first);
- if (current_object == m_current_objects.end()) {
- add_error("3rd 3mf, can not find object, id " + std::to_string(object.first.second));
- return false;
- }
- std::vector<Component> object_id_list;
- _generate_current_object_list(object_id_list, object.first, m_current_objects);
- ObjectMetadata::VolumeMetadataList volumes;
- ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr;
- for (int k = 0; k < object_id_list.size(); k++)
- {
- Id object_id = object_id_list[k].object_id;
- volumes.emplace_back(object_id.second);
- }
- // select as volumes
- volumes_ptr = &volumes;
- // for each instance after the 1st, create a new model object containing only that instance
- // and copy into it the geometry
- while (model_object->instances.size() > 1) {
- ModelObject* new_model_object = m_model->add_object(*model_object);
- new_model_object->clear_instances();
- new_model_object->add_instance(*model_object->instances.back());
- model_object->delete_last_instance();
- if (!_generate_volumes_new(*new_model_object, object_id_list, *volumes_ptr, config, config_substitutions))
- return false;
- }
- }
- }
- }
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", process group colors, size %1%\n")%m_group_id_to_color.size();
- std::map<int, int> color_group_id_to_extruder_id_map;
- std::map<std::string, int> color_to_extruder_id_map;
- int extruder_id = 0;
- for (auto group_iter = m_group_id_to_color.begin(); group_iter != m_group_id_to_color.end(); ++group_iter) {
- auto color_iter = color_to_extruder_id_map.find(group_iter->second);
- if (color_iter == color_to_extruder_id_map.end()) {
- ++extruder_id;
- color_to_extruder_id_map[group_iter->second] = extruder_id;
- color_group_id_to_extruder_id_map[group_iter->first] = extruder_id;
- } else {
- color_group_id_to_extruder_id_map[group_iter->first] = color_iter->second;
- }
- }
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", begin to assemble objects, size %1%\n")%m_objects.size();
- //only load objects in plate_id
- PlateData* current_plate_data = nullptr;
- if ((plate_id > 0) && (plate_id <= m_plater_data.size())) {
- std::map<int, PlateData*>::iterator it =m_plater_data.find(plate_id);
- if (it != m_plater_data.end()) {
- current_plate_data = it->second;
- }
- }
- for (const IdToModelObjectMap::value_type& object : m_objects) {
- if (object.second >= int(m_model->objects.size())) {
- add_error("invalid object, id: "+std::to_string(object.first.second));
- return false;
- }
- if (current_plate_data) {
- std::map<int, std::pair<int, int>>::iterator it = current_plate_data->obj_inst_map.find(object.first.second);
- if (it == current_plate_data->obj_inst_map.end()) {
- //not in current plate, skip
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", could not find object %1% in plate %2%, skip it\n")%object.first.second %plate_id;
- continue;
- }
- }
- ModelObject* model_object = m_model->objects[object.second];
- /*IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
- if (obj_geometry == m_geometries.end()) {
- add_error("Unable to find object geometry");
- return false;
- }*/
- // m_layer_heights_profiles are indexed by a 1 based model object index.
- IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1);
- if (obj_layer_heights_profile != m_layer_heights_profiles.end())
- model_object->layer_height_profile.set(std::move(obj_layer_heights_profile->second));
- // m_layer_config_ranges are indexed by a 1 based model object index.
- IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
- if (obj_layer_config_ranges != m_layer_config_ranges.end())
- model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second);
- // m_sla_support_points are indexed by a 1 based model object index.
- /*IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
- if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
- model_object->sla_support_points = std::move(obj_sla_support_points->second);
- model_object->sla_points_status = sla::PointsStatus::UserModified;
- }
- IdToSlaDrainHolesMap::iterator obj_drain_holes = m_sla_drain_holes.find(object.second + 1);
- if (obj_drain_holes != m_sla_drain_holes.end() && !obj_drain_holes->second.empty()) {
- model_object->sla_drain_holes = std::move(obj_drain_holes->second);
- }*/
- std::vector<Component> object_id_list;
- _generate_current_object_list(object_id_list, object.first, m_current_objects);
- ObjectMetadata::VolumeMetadataList volumes;
- ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr;
- IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first.second);
- if (obj_metadata != m_objects_metadata.end()) {
- // config data has been found, this model was saved using slic3r pe
- std::map<std::string, std::string> key_values_to_deserialize;
- // apply object's name and config data
- for (const Metadata& metadata : obj_metadata->second.metadata) {
- if (metadata.key == "name")
- model_object->name = metadata.value;
- //BBS: add module name
- else if (metadata.key == "module")
- ; //model_object->module_name = metadata.value; //Susi_not_impl
- else
- key_values_to_deserialize[metadata.key] = metadata.value;
- //model_object->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
- }
- convert_settings_from_bambu(key_values_to_deserialize, config, model_object->config, config_substitutions, false);
- // select object's detected volumes
- volumes_ptr = &obj_metadata->second.volumes;
- }
- else {
- // config data not found, this model was not saved using slic3r pe
- // add the entire geometry as the single volume to generate
- //volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1);
- for (int k = 0; k < object_id_list.size(); k++)
- {
- Id object_id = object_id_list[k].object_id;
- volumes.emplace_back(object_id.second);
- }
- IdToCurrentObjectMap::const_iterator current_object = m_current_objects.find(object.first);
- if (current_object != m_current_objects.end()) {
- // get name
- if (!current_object->second.name.empty())
- model_object->name = current_object->second.name;
- else
- model_object->name = "Object_"+std::to_string(object.second+1);
- // get color
- auto extruder_itor = color_group_id_to_extruder_id_map.find(current_object->second.pid);
- if (extruder_itor != color_group_id_to_extruder_id_map.end()) {
- model_object->config.set_key_value("extruder", new ConfigOptionInt(extruder_itor->second));
- }
- }
- // select as volumes
- volumes_ptr = &volumes;
- }
- if (!_generate_volumes_new(*model_object, object_id_list, *volumes_ptr, config, config_substitutions))
- return false;
- // Apply cut information for object if any was loaded
- // m_cut_object_ids are indexed by a 1 based model object index.
- IdToCutObjectInfoMap::iterator cut_object_info = m_cut_object_infos.find(object.second + 1);
- if (cut_object_info != m_cut_object_infos.end()) {
- //model_object->cut_id = cut_object_info->second.id; //Susi_not_impl
- int vol_cnt = int(model_object->volumes.size());
- for (auto connector : cut_object_info->second.connectors) {
- if (connector.volume_id < 0 || connector.volume_id >= vol_cnt) {
- add_error("Invalid connector is found");
- continue;
- }
- //model_object->volumes[connector.volume_id]->cut_info =
- // ModelVolume::CutInfo(CutConnectorType(connector.type), connector.r_tolerance, connector.h_tolerance, true); //Susi_not_impl
- }
- }
- }
- // If instances contain a single volume, the volume offset should be 0,0,0
- // This equals to say that instance world position and volume world position should match
- // Correct all instances/volumes for which this does not hold
- for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
- ModelObject *o = model.objects[obj_id];
- if (o->volumes.size() == 1) {
- ModelVolume * v = o->volumes.front();
- const Slic3r::Geometry::Transformation &first_inst_trafo = o->instances.front()->get_transformation();
- const Vec3d world_vol_offset = (first_inst_trafo * v->get_transformation()).get_offset();
- const Vec3d world_inst_offset = first_inst_trafo.get_offset();
- if (!world_vol_offset.isApprox(world_inst_offset)) {
- const Slic3r::Geometry::Transformation &vol_trafo = v->get_transformation();
- for (int inst_id = 0; inst_id < int(o->instances.size()); ++inst_id) {
- ModelInstance * i = o->instances[inst_id];
- const Slic3r::Geometry::Transformation &inst_trafo = i->get_transformation();
- i->set_offset((inst_trafo * vol_trafo).get_offset());
- }
- v->set_offset(Vec3d::Zero());
- }
- }
- }
- int object_idx = 0;
- for (ModelObject* o : model.objects) {
- int volume_idx = 0;
- for (ModelVolume* v : o->volumes) {
- if (v->source.input_file.empty() && v->type() == ModelVolumeType::MODEL_PART) {
- v->source.input_file = filename;
- if (v->source.volume_idx == -1)
- v->source.volume_idx = volume_idx;
- if (v->source.object_idx == -1)
- v->source.object_idx = object_idx;
- }
- ++volume_idx;
- }
- ++object_idx;
- }
- const ConfigOptionStrings* filament_ids_opt = config.option<ConfigOptionStrings>("filament_settings_id");
- int max_filament_id = filament_ids_opt ? filament_ids_opt->size() : std::numeric_limits<int>::max();
- for (ModelObject* mo : m_model->objects) {
- const ConfigOptionInt* extruder_opt = dynamic_cast<const ConfigOptionInt*>(mo->config.option("extruder"));
- int extruder_id = 0;
- if (extruder_opt != nullptr)
- extruder_id = extruder_opt->get_int();
- if (extruder_id == 0 || extruder_id > max_filament_id)
- mo->config.set_key_value("extruder", new ConfigOptionInt(1));
- if (mo->volumes.size() == 1) {
- mo->volumes[0]->config.erase("extruder");
- }
- else {
- for (ModelVolume* mv : mo->volumes) {
- const ConfigOptionInt* vol_extruder_opt = dynamic_cast<const ConfigOptionInt*>(mv->config.option("extruder"));
- if (vol_extruder_opt == nullptr)
- continue;
- if (vol_extruder_opt->get_int() == 0)
- mv->config.erase("extruder");
- else if (vol_extruder_opt->get_int() > max_filament_id)
- mv->config.set_key_value("extruder", new ConfigOptionInt(1));
- }
- }
- }
- // // fixes the min z of the model if negative
- // model.adjust_min_z();
- //BBS progress point
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_LOADING_PLATES, m_plater_data size %1%, m_backup_path %2%\n")%m_plater_data.size() %m_backup_path;
- if (proFn) {
- proFn(IMPORT_STAGE_LOADING_PLATES, 0, 1, cb_cancel);
- if (cb_cancel)
- return false;
- }
- //BBS: load the plate info into plate_data_list
- std::map<int, PlateData*>::iterator it = m_plater_data.begin();
- plate_data_list.clear();
- plate_data_list.reserve(m_plater_data.size());
- for (unsigned int i = 0; i < m_plater_data.size(); i++)
- {
- PlateData* plate = new PlateData();
- plate_data_list.push_back(plate);
- }
- while (it != m_plater_data.end())
- {
- if (it->first > m_plater_data.size())
- {
- add_error("invalid plate index");
- return false;
- }
- plate_data_list[it->first-1]->locked = it->second->locked;
- plate_data_list[it->first-1]->plate_index = it->second->plate_index-1;
- plate_data_list[it->first-1]->plate_name = it->second->plate_name;
- plate_data_list[it->first-1]->obj_inst_map = it->second->obj_inst_map;
- plate_data_list[it->first-1]->gcode_file = (m_load_restore || it->second->gcode_file.empty()) ? it->second->gcode_file : m_backup_path + "/" + it->second->gcode_file;
- plate_data_list[it->first-1]->gcode_prediction = it->second->gcode_prediction;
- plate_data_list[it->first-1]->gcode_weight = it->second->gcode_weight;
- plate_data_list[it->first-1]->toolpath_outside = it->second->toolpath_outside;
- plate_data_list[it->first-1]->is_support_used = it->second->is_support_used;
- plate_data_list[it->first-1]->is_label_object_enabled = it->second->is_label_object_enabled;
- plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info;
- plate_data_list[it->first-1]->skipped_objects = it->second->skipped_objects;
- plate_data_list[it->first-1]->warnings = it->second->warnings;
- plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file;
- //plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file;
- plate_data_list[it->first-1]->top_file = (m_load_restore || it->second->top_file.empty()) ? it->second->top_file : m_backup_path + "/" + it->second->top_file;
- plate_data_list[it->first-1]->pick_file = (m_load_restore || it->second->pick_file.empty()) ? it->second->pick_file : m_backup_path + "/" + it->second->pick_file;
- plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file;
- plate_data_list[it->first-1]->config = it->second->config;
- current_plate_data = plate_data_list[it->first - 1];
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate_data_list[it->first-1]->thumbnail_file;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_file=%1%, pick_thumbnail_file=%2%")%plate_data_list[it->first-1]->top_file %plate_data_list[it->first-1]->pick_file;
- it++;
- //update the arrange order
- std::map<int, std::pair<int, int>>::iterator map_it = current_plate_data->obj_inst_map.begin();
- while (map_it != current_plate_data->obj_inst_map.end()) {
- int obj_index, obj_id = map_it->first, inst_index = map_it->second.first;
- IndexToPathMap::iterator index_iter = m_index_paths.find(obj_id);
- if (index_iter == m_index_paths.end()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__
- << boost::format(", can not find object from plate's obj_map, id=%1%, skip this object")%obj_id;
- map_it++;
- continue;
- }
- Id temp_id = std::make_pair(index_iter->second, index_iter->first);
- IdToModelObjectMap::iterator object_item = m_objects.find(temp_id);
- if (object_item == m_objects.end()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__
- << boost::format(", can not find object from plate's obj_map, ID <%1%, %2%>, skip this object")%index_iter->second %index_iter->first;
- map_it++;
- continue;
- }
- obj_index = object_item->second;
- if (obj_index >= m_model->objects.size()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_index;
- map_it++;
- continue;
- }
- ModelObject* obj = m_model->objects[obj_index];
- if (inst_index >= obj->instances.size()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_index;
- map_it++;
- continue;
- }
- ModelInstance* inst = obj->instances[inst_index];
- //inst->loaded_id = map_it->second.second; //Susi_not_impl
- map_it++;
- }
- }
- if ((plate_id > 0) && (plate_id <= m_plater_data.size())) {
- //remove the no need objects
- std::vector<size_t> delete_ids;
- for (int index = 0; index < m_model->objects.size(); index++) {
- ModelObject* obj = m_model->objects[index];
- if (obj->volumes.size() == 0) {
- //remove this model objects
- delete_ids.push_back(index);
- }
- }
- for (int index = delete_ids.size() - 1; index >= 0; index--)
- m_model->delete_object(delete_ids[index]);
- }
- //BBS progress point
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_FINISH\n");
- if (proFn) {
- proFn(IMPORT_STAGE_FINISH, 0, 1, cb_cancel);
- if (cb_cancel)
- return false;
- }
- return true;
- }
- bool _BBS_3MF_Importer::_is_svg_shape_file(const std::string &name) const {
- return boost::starts_with(name, MODEL_FOLDER) && boost::ends_with(name, ".svg");
- }
- bool _BBS_3MF_Importer::_extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)> extract, bool restore)
- {
- mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
- mz_zip_archive_file_stat stat;
- std::string path2 = path;
- if (path2.front() == '/') path2 = path2.substr(1);
- // try utf8 encoding
- int index = mz_zip_reader_locate_file(&archive, path2.c_str(), nullptr, 0);
- if (index < 0) {
- // try native encoding
- std::string native_path = encode_path(path2.c_str());
- index = mz_zip_reader_locate_file(&archive, native_path.c_str(), nullptr, 0);
- }
- if (index < 0) {
- // try unicode path extra
- std::string extra(1024, 0);
- for (mz_uint i = 0; i < archive.m_total_files; ++i) {
- size_t n = mz_zip_reader_get_extra(&archive, i, extra.data(), extra.size());
- if (n > 0 && path2 == ZipUnicodePathExtraField::decode(extra.substr(0, n))) {
- index = i;
- break;
- }
- }
- }
- if (index < 0 || !mz_zip_reader_file_stat(&archive, index, &stat)) {
- if (restore) {
- std::vector<std::string> paths = {m_backup_path + path};
- if (!m_origin_file.empty()) paths.push_back(m_origin_file);
- for (auto & path2 : paths) {
- bool result = false;
- if (boost::filesystem::exists(path2)) {
- mz_zip_archive archive;
- mz_zip_zero_struct(&archive);
- if (open_zip_reader(&archive, path2)) {
- result = _extract_from_archive(archive, path, extract);
- close_zip_reader(&archive);
- }
- }
- if (result) return result;
- }
- }
- char error_buf[1024];
- ::snprintf(error_buf, 1024, "File %s not found from archive", path.c_str());
- add_error(error_buf);
- return false;
- }
- try
- {
- if (!extract(archive, stat)) {
- return false;
- }
- }
- catch (const std::exception& e)
- {
- // ensure the zip archive is closed and rethrow the exception
- add_error(e.what());
- return false;
- }
- return true;
- }
- bool _BBS_3MF_Importer::_extract_xml_from_archive(mz_zip_archive& archive, const std::string & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler)
- {
- return _extract_from_archive(archive, path, [this, start_handler, end_handler](mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) {
- return _extract_xml_from_archive(archive, stat, start_handler, end_handler);
- });
- }
- bool _BBS_3MF_Importer::_extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler)
- {
- if (stat.m_uncomp_size == 0) {
- add_error("Found invalid size");
- return false;
- }
- _destroy_xml_parser();
- m_xml_parser = XML_ParserCreate(nullptr);
- if (m_xml_parser == nullptr) {
- add_error("Unable to create parser");
- return false;
- }
- XML_SetUserData(m_xml_parser, (void*)this);
- XML_SetElementHandler(m_xml_parser, start_handler, end_handler);
- XML_SetCharacterDataHandler(m_xml_parser, _BBS_3MF_Importer::_handle_xml_characters);
- void* parser_buffer = XML_GetBuffer(m_xml_parser, (int)stat.m_uncomp_size);
- if (parser_buffer == nullptr) {
- add_error("Unable to create buffer");
- return false;
- }
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading config data to buffer");
- return false;
- }
- if (!XML_ParseBuffer(m_xml_parser, (int)stat.m_uncomp_size, 1)) {
- char error_buf[1024];
- ::snprintf(error_buf, 1024, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
- add_error(error_buf);
- return false;
- }
- return true;
- }
- bool _BBS_3MF_Importer::_extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size == 0) {
- add_error("Found invalid size");
- return false;
- }
- _destroy_xml_parser();
- m_xml_parser = XML_ParserCreate(nullptr);
- if (m_xml_parser == nullptr) {
- add_error("Unable to create parser");
- return false;
- }
- XML_SetUserData(m_xml_parser, (void*)this);
- XML_SetElementHandler(m_xml_parser, _BBS_3MF_Importer::_handle_start_model_xml_element, _BBS_3MF_Importer::_handle_end_model_xml_element);
- XML_SetCharacterDataHandler(m_xml_parser, _BBS_3MF_Importer::_handle_xml_characters);
- struct CallbackData
- {
- XML_Parser& parser;
- _BBS_3MF_Importer& importer;
- const mz_zip_archive_file_stat& stat;
- CallbackData(XML_Parser& parser, _BBS_3MF_Importer& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {}
- };
- CallbackData data(m_xml_parser, *this, stat);
- mz_bool res = 0;
- try
- {
- mz_file_write_func callback = [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
- CallbackData* data = (CallbackData*)pOpaque;
- if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
- char error_buf[1024];
- ::snprintf(error_buf, 1024, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
- throw Slic3r::FileIOError(error_buf);
- }
- return n;
- };
- void* opaque = &data;
- res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, callback, opaque, 0);
- }
- catch (const version_error& e)
- {
- // rethrow the exception
- throw Slic3r::FileIOError(e.what());
- }
- catch (std::exception& e)
- {
- add_error(e.what());
- return false;
- }
- if (res == 0) {
- add_error("Error while extracting model data from zip archive");
- return false;
- }
- return true;
- }
- void _BBS_3MF_Importer::_extract_cut_information_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void *) buffer.data(), (size_t) stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading cut information data to buffer");
- return;
- }
- std::istringstream iss(buffer); // wrap returned xml to istringstream
- pt::ptree objects_tree;
- pt::read_xml(iss, objects_tree);
- for (const auto& object : objects_tree.get_child("objects")) {
- pt::ptree object_tree = object.second;
- int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
- if (obj_idx <= 0) {
- add_error("Found invalid object id");
- continue;
- }
- IdToCutObjectInfoMap::iterator object_item = m_cut_object_infos.find(obj_idx);
- if (object_item != m_cut_object_infos.end()) {
- add_error("Found duplicated cut_object_id");
- continue;
- }
- CutObjectBase cut_id;
- std::vector<CutObjectInfo::Connector> connectors;
- for (const auto& obj_cut_info : object_tree) {
- if (obj_cut_info.first == "cut_id") {
- pt::ptree cut_id_tree = obj_cut_info.second;
- cut_id = CutObjectBase(ObjectID( cut_id_tree.get<size_t>("<xmlattr>.id")),
- cut_id_tree.get<size_t>("<xmlattr>.check_sum"),
- cut_id_tree.get<size_t>("<xmlattr>.connectors_cnt"));
- }
- if (obj_cut_info.first == "connectors") {
- pt::ptree cut_connectors_tree = obj_cut_info.second;
- for (const auto& cut_connector : cut_connectors_tree) {
- if (cut_connector.first != "connector")
- continue;
- pt::ptree connector_tree = cut_connector.second;
- CutObjectInfo::Connector connector = {connector_tree.get<int>("<xmlattr>.volume_id"),
- connector_tree.get<int>("<xmlattr>.type"),
- connector_tree.get<float>("<xmlattr>.r_tolerance"),
- connector_tree.get<float>("<xmlattr>.h_tolerance")};
- connectors.emplace_back(connector);
- }
- }
- }
- CutObjectInfo cut_info {cut_id, connectors};
- m_cut_object_infos.insert({ obj_idx, cut_info });
- }
- }
- }
- void _BBS_3MF_Importer::_extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, const std::string& archive_filename)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading config data to buffer");
- return;
- }
- ConfigBase::load_from_gcode_string_legacy(config, buffer.data(), config_substitutions);
- }
- }
- //BBS: extract project config from json files
- void _BBS_3MF_Importer::_extract_project_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Model& model)
- {
- if (stat.m_uncomp_size > 0) {
-
- std_path temp_file = extract_file(model, archive, stat);
- bool ok = read_json_file_bambu(temp_file, config, config_substitutions, true);
- if (!ok) {
- add_error("Error load config from bambu/orca json");
- return;
- }
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", load project config file successfully from %1%\n") % temp_file.string();
- }
- }
- //BBS: extract project embedded presets
- void _BBS_3MF_Importer::_extract_project_embedded_presets_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, std::vector<Preset*>&project_presets, Model& model, Preset::Type type, bool use_json)
- {
- if (stat.m_uncomp_size > 0) {
-
- std_path dest_file_path = extract_file(model, archive, stat);
- std::string dest_file = dest_file_path.string();
- //load presets
- DynamicPrintConfig config;
- ConfigSubstitutionContext config_substitution_context(ForwardCompatibilitySubstitutionRule::Enable);
- std::map<std::string, std::string> key_values;
- bool ok = false;
- if (use_json) {
- ok = read_json_file_bambu(dest_file_path, config, config_substitution_context, true);
- } else {
- key_values = read_ini_file_bambu(dest_file_path);
- ok = convert_settings_from_bambu(key_values, config, config_substitution_context, true);
- }
- if (!ok) {
- add_error("Error load config from bambu/orca json");
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", load project embedded config from %1% failed\n") % dest_file;
- //skip this file
- return;
- }
- /*std::string src_file = decode_path(stat.m_filename);
- std::size_t found = src_file.find(METADATA_DIR);
- if (found != std::string::npos)
- src_file = src_file.substr(found + METADATA_STR_LEN);
- else
- return;*/
- //std::string dest_file = m_backup_path + std::string("/") + "_temp_2.config";;
- //std::string dest_zip_file = encode_path(dest_file.c_str());
- //mz_bool res = mz_zip_reader_extract_to_file(&archive, stat.m_file_index, dest_zip_file.c_str(), 0);
- //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", extract %1% from 3mf %2%, ret %3%\n") % dest_file % stat.m_filename % res;
- //if (res == 0) {
- // add_error("Error while extract auxiliary file to file");
- // return;
- //}
- ////load presets
- //DynamicPrintConfig config;
- ////ConfigSubstitutions config_substitutions = config.load_from_ini(dest_file, Enable);
- //std::map<std::string, std::string> key_values;
- //std::string reason;
- //ConfigSubstitutions config_substitutions = use_json? config.load_from_json(dest_file, Enable, key_values, reason) : config.load_from_ini(dest_file, Enable);
- //if (!reason.empty()) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", load project embedded config from %1% failed\n") % dest_file;
- // //skip this file
- // return;
- //}
- ConfigOptionString* print_name;
- ConfigOptionStrings* filament_names;
- std::string preset_name;
- if (type == Preset::TYPE_FFF_PRINT) {
- print_name = dynamic_cast < ConfigOptionString* > (config.option("print_settings_id"));
- if (!print_name) {
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", can not found print_settings_id from %1%\n") % dest_file;
- //skip this file
- return;
- }
- preset_name = print_name->value;
- }
- else if (type == Preset::TYPE_FFF_FILAMENT) {
- filament_names = dynamic_cast < ConfigOptionStrings* > (config.option("filament_settings_id"));
- if (!filament_names) {
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", can not found filament_settings_id from %1%\n") % dest_file;
- //skip this file
- return;
- }
- preset_name = filament_names->values[0];
- }
- else if (type == Preset::TYPE_PRINTER) {
- print_name = dynamic_cast < ConfigOptionString* > (config.option("printer_settings_id"));
- if (!print_name) {
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", can not found printer_settings_id from %1%\n") % dest_file;
- //skip this file
- return;
- }
- preset_name = print_name->value;
- }
- else {
- BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", invalid type %1% from file %2%\n")% Preset::type_name(type) % dest_file;
- //skip this file
- return;
- }
-
- //Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}
- Preset *preset = new Preset(type, preset_name, false);
- preset->file = dest_file;
- preset->config = std::move(config);
- preset->loaded = true;
- //preset->is_project_embedded = true; //Susi_not_impl
- preset->is_external = true;
- preset->is_dirty = false;
- std::string version_str = key_values[BBL_JSON_KEY_VERSION];
- boost::optional<Semver> version = Semver::parse(version_str);
- if (version) {
- //preset->version = *version; //Susi_not_impl
- } else {
- //preset->version = this->m_bambuslicer_generator_version?*this->m_bambuslicer_generator_version: Semver(); //Susi_not_impl
- }
- /*for (int i = 0; i < config_substitutions.size(); i++)
- {
- //ConfigSubstitution config_substitution;
- //config_substitution.opt_def = optdef;
- //config_substitution.old_value = value;
- //config_substitution.new_value = ConfigOptionUniquePtr(opt->clone());
- preset->loading_substitutions.emplace_back(std::move(config_substitutions[i]));
- }*/
- //if (!config_substitutions.empty()) {
- // preset->loading_substitutions = new ConfigSubstitutions();
- // *(preset->loading_substitutions) = std::move(config_substitutions);
- //} //Susi_not_impl
- project_presets.push_back(preset);
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", create one project embedded preset: %1% from %2%, type %3%\n") % preset_name % dest_file %Preset::type_name(type);
- }
- }
- void _BBS_3MF_Importer::_extract_auxiliary_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
- {
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", stat.m_uncomp_size is %1%")%stat.m_uncomp_size;
- if (stat.m_uncomp_size > 0) {
- std::string dest_file;
- if (stat.m_is_utf8) {
- dest_file = stat.m_filename;
- } else {
- std::string extra(1024, 0);
- size_t n = mz_zip_reader_get_extra(&archive, stat.m_file_index, extra.data(), extra.size());
- dest_file = ZipUnicodePathExtraField::decode(extra.substr(0, n), stat.m_filename);
- }
- //aux directory from model
- std_path dir = get_temp_file(model);
- std::size_t found = dest_file.find(AUXILIARY_DIR);
- if (found != std::string::npos)
- dest_file = dest_file.substr(found + AUXILIARY_STR_LEN);
- else
- return;
- if (dest_file.find('/') != std::string::npos) {
- boost::filesystem::path src_path = boost::filesystem::path(dest_file);
- boost::filesystem::path parent_path = src_path.parent_path();
- std::string temp_path = dir.string() + std::string("/") + parent_path.string();
- boost::filesystem::path parent_full_path = boost::filesystem::path(temp_path);
- if (!boost::filesystem::exists(parent_full_path))
- boost::filesystem::create_directories(parent_full_path);
- }
- dest_file = dir.string() + std::string("/") + dest_file;
- std::string dest_zip_file = encode_path(dest_file.c_str());
- mz_bool res = mz_zip_reader_extract_to_file(&archive, stat.m_file_index, dest_zip_file.c_str(), 0);
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", extract %1% from 3mf %2%, ret %3%\n") % dest_file % stat.m_filename % res;
- if (res == 0) {
- add_error("Error while extract auxiliary file to file");
- return;
- }
- }
- }
- void _BBS_3MF_Importer::_extract_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size > 0) {
- std::string src_file = decode_path(stat.m_filename);
- // BBS: use backup path
- //aux directory from model
- boost::filesystem::path dest_path = boost::filesystem::path(m_backup_path + "/" + src_file);
- std::string dest_zip_file = encode_path(dest_path.string().c_str());
- mz_bool res = mz_zip_reader_extract_to_file(&archive, stat.m_file_index, dest_zip_file.c_str(), 0);
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", extract %1% from 3mf %2%, ret %3%\n") % dest_path % stat.m_filename % res;
- if (res == 0) {
- add_error("Error while extract file to temp directory");
- return;
- }
- }
- return;
- }
- void _BBS_3MF_Importer::_extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading layer heights profile data to buffer");
- return;
- }
- if (buffer.back() == '\n')
- buffer.pop_back();
- std::vector<std::string> objects;
- boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
- for (const std::string& object : objects) {
- std::vector<std::string> object_data;
- boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
- if (object_data.size() != 2) {
- add_error("Error while reading object data");
- continue;
- }
- std::vector<std::string> object_data_id;
- boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
- if (object_data_id.size() != 2) {
- add_error("Error while reading object id");
- continue;
- }
- int object_id = std::atoi(object_data_id[1].c_str());
- if (object_id == 0) {
- add_error("Found invalid object id");
- continue;
- }
- IdToLayerHeightsProfileMap::iterator object_item = m_layer_heights_profiles.find(object_id);
- if (object_item != m_layer_heights_profiles.end()) {
- add_error("Found duplicated layer heights profile");
- continue;
- }
- std::vector<std::string> object_data_profile;
- boost::split(object_data_profile, object_data[1], boost::is_any_of(";"), boost::token_compress_off);
- if (object_data_profile.size() <= 4 || object_data_profile.size() % 2 != 0) {
- add_error("Found invalid layer heights profile");
- continue;
- }
- std::vector<coordf_t> profile;
- profile.reserve(object_data_profile.size());
- for (const std::string& value : object_data_profile) {
- profile.push_back((coordf_t)std::atof(value.c_str()));
- }
- m_layer_heights_profiles.insert({ object_id, profile });
- }
- }
- }
-
- void _BBS_3MF_Importer::_extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading layer config ranges data to buffer");
- return;
- }
- std::istringstream iss(buffer); // wrap returned xml to istringstream
- pt::ptree objects_tree;
- pt::read_xml(iss, objects_tree);
- for (const auto& object : objects_tree.get_child("objects")) {
- pt::ptree object_tree = object.second;
- int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
- if (obj_idx <= 0) {
- add_error("Found invalid object id");
- continue;
- }
- IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(obj_idx);
- if (object_item != m_layer_config_ranges.end()) {
- add_error("Found duplicated layer config range");
- continue;
- }
- t_layer_config_ranges config_ranges;
- for (const auto& range : object_tree) {
- if (range.first != "range")
- continue;
- pt::ptree range_tree = range.second;
- double min_z = range_tree.get<double>("<xmlattr>.min_z");
- double max_z = range_tree.get<double>("<xmlattr>.max_z");
- // get Z range information
- DynamicPrintConfig config;
-
- std::map<std::string, std::string> key_values_to_deserialize;
- for (const auto& option : range_tree) {
- if (option.first != "option")
- continue;
- std::string opt_key = option.second.get<std::string>("<xmlattr>.opt_key");
- std::string value = option.second.data();
- //config.set_deserialize(opt_key, value, config_substitutions);
- key_values_to_deserialize[opt_key] = value;
- }
- assert(key_values_to_deserialize.find("extruder") != key_values_to_deserialize.end());
- assert(key_values_to_deserialize.find("layer_height") != key_values_to_deserialize.end());
- convert_settings_from_bambu(key_values_to_deserialize, config, config_substitutions, false);
- config_ranges[{ min_z, max_z }].assign_config(std::move(config));
- }
- if (!config_ranges.empty())
- m_layer_config_ranges.insert({ obj_idx, std::move(config_ranges) });
- }
- }
- }
- /*
- void _BBS_3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading sla support points data to buffer");
- return;
- }
- if (buffer.back() == '\n')
- buffer.pop_back();
- std::vector<std::string> objects;
- boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
- // Info on format versioning - see 3mf.hpp
- int version = 0;
- std::string key("support_points_format_version=");
- if (!objects.empty() && objects[0].find(key) != std::string::npos) {
- objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
- version = std::stoi(objects[0]);
- objects.erase(objects.begin()); // pop the header
- }
- for (const std::string& object : objects) {
- std::vector<std::string> object_data;
- boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
- if (object_data.size() != 2) {
- add_error("Error while reading object data");
- continue;
- }
- std::vector<std::string> object_data_id;
- boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
- if (object_data_id.size() != 2) {
- add_error("Error while reading object id");
- continue;
- }
- int object_id = std::atoi(object_data_id[1].c_str());
- if (object_id == 0) {
- add_error("Found invalid object id");
- continue;
- }
- IdToSlaSupportPointsMap::iterator object_item = m_sla_support_points.find(object_id);
- if (object_item != m_sla_support_points.end()) {
- add_error("Found duplicated SLA support points");
- continue;
- }
- std::vector<std::string> object_data_points;
- boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
- std::vector<sla::SupportPoint> sla_support_points;
- if (version == 0) {
- for (unsigned int i=0; i<object_data_points.size(); i+=3)
- sla_support_points.emplace_back(float(std::atof(object_data_points[i+0].c_str())),
- float(std::atof(object_data_points[i+1].c_str())),
- float(std::atof(object_data_points[i+2].c_str())),
- 0.4f,
- false);
- }
- if (version == 1) {
- for (unsigned int i=0; i<object_data_points.size(); i+=5)
- sla_support_points.emplace_back(float(std::atof(object_data_points[i+0].c_str())),
- float(std::atof(object_data_points[i+1].c_str())),
- float(std::atof(object_data_points[i+2].c_str())),
- float(std::atof(object_data_points[i+3].c_str())),
- //FIXME storing boolean as 0 / 1 and importing it as float.
- std::abs(std::atof(object_data_points[i+4].c_str()) - 1.) < EPSILON);
- }
- if (!sla_support_points.empty())
- m_sla_support_points.insert({ object_id, sla_support_points });
- }
- }
- }
- void _BBS_3MF_Importer::_extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size > 0) {
- std::string buffer(size_t(stat.m_uncomp_size), 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading sla support points data to buffer");
- return;
- }
- if (buffer.back() == '\n')
- buffer.pop_back();
- std::vector<std::string> objects;
- boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
- // Info on format versioning - see 3mf.hpp
- int version = 0;
- std::string key("drain_holes_format_version=");
- if (!objects.empty() && objects[0].find(key) != std::string::npos) {
- objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
- version = std::stoi(objects[0]);
- objects.erase(objects.begin()); // pop the header
- }
- for (const std::string& object : objects) {
- std::vector<std::string> object_data;
- boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
- if (object_data.size() != 2) {
- add_error("Error while reading object data");
- continue;
- }
- std::vector<std::string> object_data_id;
- boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
- if (object_data_id.size() != 2) {
- add_error("Error while reading object id");
- continue;
- }
- int object_id = std::atoi(object_data_id[1].c_str());
- if (object_id == 0) {
- add_error("Found invalid object id");
- continue;
- }
- IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id);
- if (object_item != m_sla_drain_holes.end()) {
- add_error("Found duplicated SLA drain holes");
- continue;
- }
- std::vector<std::string> object_data_points;
- boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
- sla::DrainHoles sla_drain_holes;
- if (version == 1) {
- for (unsigned int i=0; i<object_data_points.size(); i+=8)
- sla_drain_holes.emplace_back(Vec3f{float(std::atof(object_data_points[i+0].c_str())),
- float(std::atof(object_data_points[i+1].c_str())),
- float(std::atof(object_data_points[i+2].c_str()))},
- Vec3f{float(std::atof(object_data_points[i+3].c_str())),
- float(std::atof(object_data_points[i+4].c_str())),
- float(std::atof(object_data_points[i+5].c_str()))},
- float(std::atof(object_data_points[i+6].c_str())),
- float(std::atof(object_data_points[i+7].c_str())));
- }
- // The holes are saved elevated above the mesh and deeper (bad idea indeed).
- // This is retained for compatibility.
- // Place the hole to the mesh and make it shallower to compensate.
- // The offset is 1 mm above the mesh.
- for (sla::DrainHole& hole : sla_drain_holes) {
- hole.pos += hole.normal.normalized();
- hole.height -= 1.f;
- }
- if (!sla_drain_holes.empty())
- m_sla_drain_holes.insert({ object_id, sla_drain_holes });
- }
- }
- }*/
- void _BBS_3MF_Importer::_extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat){
- assert(m_path_to_emboss_shape_files.find(filename) == m_path_to_emboss_shape_files.end());
- auto file = std::make_unique<std::string>(stat.m_uncomp_size, '\0');
- mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void *) file->data(), stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading svg shape for emboss");
- return;
- }
-
- // store for case svg is loaded before volume
- m_path_to_emboss_shape_files[filename] = std::move(file);
-
- // find embossed volume, for case svg is loaded after volume
- //for (const ModelObject* object : m_model->objects)
- //for (ModelVolume *volume : object->volumes) {
- // std::optional<EmbossShape> &es = volume->emboss_shape;
- // if (!es.has_value())
- // continue;
- // std::optional<EmbossShape::SvgFile> &svg = es->svg_file;
- // if (!svg.has_value())
- // continue;
- // if (filename.compare(svg->path_in_3mf) == 0)
- // svg->file_data = m_path_to_emboss_shape_files[filename];
- //} //Susi_not_impl
- }
- void _BBS_3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
- {
- //BBS: add plate tree related logic
- if (stat.m_uncomp_size > 0) {
- std::string buffer((size_t)stat.m_uncomp_size, 0);
- mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == 0) {
- add_error("Error while reading custom Gcodes per height data to buffer");
- return;
- }
- std::istringstream iss(buffer); // wrap returned xml to istringstream
- pt::ptree main_tree;
- pt::read_xml(iss, main_tree);
- if (main_tree.front().first != "custom_gcodes_per_layer")
- return;
- auto extract_code = [this](int plate_id, pt::ptree code_tree) {
- for (const auto& code : code_tree) {
- if (code.first == "mode") {
- pt::ptree tree = code.second;
- std::string mode = tree.get<std::string>("<xmlattr>.value");
- //m_model->plates_custom_gcodes[plate_id - 1].mode = mode == CustomGCode::SingleExtruderMode ? CustomGCode::Mode::SingleExtruder :
- // mode == CustomGCode::MultiAsSingleMode ? CustomGCode::Mode::MultiAsSingle :
- // CustomGCode::Mode::MultiExtruder; //Susi_not_impl
- }
- if (code.first == "layer") {
- pt::ptree tree = code.second;
- double print_z = tree.get<double>("<xmlattr>.top_z");
- int extruder = tree.get<int>("<xmlattr>.extruder");
- std::string color = tree.get<std::string>("<xmlattr>.color");
- CustomGCode::Type type;
- std::string extra;
- pt::ptree attr_tree = tree.find("<xmlattr>")->second;
- if (attr_tree.find("type") == attr_tree.not_found()) {
- // It means that data was saved in old version (2.2.0 and older) of PrusaSlicer
- // read old data ...
- std::string gcode = tree.get<std::string>("<xmlattr>.gcode");
- // ... and interpret them to the new data
- type = gcode == "M600" ? CustomGCode::ColorChange :
- gcode == "M601" ? CustomGCode::PausePrint :
- gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom;
- extra = type == CustomGCode::PausePrint ? color :
- type == CustomGCode::Custom ? gcode : "";
- }
- else {
- type = static_cast<CustomGCode::Type>(tree.get<int>("<xmlattr>.type"));
- extra = tree.get<std::string>("<xmlattr>.extra");
- }
- //m_model->plates_custom_gcodes[plate_id - 1].gcodes.push_back(CustomGCode::Item{ print_z, type, extruder, color, extra }); //Susi_not_impl
- }
- }
- };
- //m_model->plates_custom_gcodes.clear(); //Susi_not_impl
- bool has_plate_info = false;
- for (const auto& element : main_tree.front().second) {
- if (element.first == "plate") {
- has_plate_info = true;
- int plate_id = -1;
- pt::ptree code_tree = element.second;
- for (const auto& code : code_tree) {
- if (code.first == "plate_info") {
- plate_id = code.second.get<int>("<xmlattr>.id");
- }
- }
- if (plate_id == -1)
- continue;
- extract_code(plate_id, code_tree);
- }
- }
- if (!has_plate_info) {
- int plate_id = 1;
- pt::ptree code_tree = main_tree.front().second;
- extract_code(plate_id, code_tree);
- }
- }
- }
- void _BBS_3MF_Importer::_handle_start_model_xml_element(const char* name, const char** attributes)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(m_xml_parser);
- if (::strcmp(MODEL_TAG, name) == 0)
- res = _handle_start_model(attributes, num_attributes);
- else if (::strcmp(RESOURCES_TAG, name) == 0)
- res = _handle_start_resources(attributes, num_attributes);
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_start_object(attributes, num_attributes);
- else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
- res = _handle_start_color_group(attributes, num_attributes);
- else if (::strcmp(COLOR_TAG, name) == 0)
- res = _handle_start_color(attributes, num_attributes);
- else if (::strcmp(MESH_TAG, name) == 0)
- res = _handle_start_mesh(attributes, num_attributes);
- else if (::strcmp(VERTICES_TAG, name) == 0)
- res = _handle_start_vertices(attributes, num_attributes);
- else if (::strcmp(VERTEX_TAG, name) == 0)
- res = _handle_start_vertex(attributes, num_attributes);
- else if (::strcmp(TRIANGLES_TAG, name) == 0)
- res = _handle_start_triangles(attributes, num_attributes);
- else if (::strcmp(TRIANGLE_TAG, name) == 0)
- res = _handle_start_triangle(attributes, num_attributes);
- else if (::strcmp(COMPONENTS_TAG, name) == 0)
- res = _handle_start_components(attributes, num_attributes);
- else if (::strcmp(COMPONENT_TAG, name) == 0)
- res = _handle_start_component(attributes, num_attributes);
- else if (::strcmp(BUILD_TAG, name) == 0)
- res = _handle_start_build(attributes, num_attributes);
- else if (::strcmp(ITEM_TAG, name) == 0)
- res = _handle_start_item(attributes, num_attributes);
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_start_metadata(attributes, num_attributes);
- if (!res)
- _stop_xml_parser();
- }
- void _BBS_3MF_Importer::_handle_end_model_xml_element(const char* name)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- if (::strcmp(MODEL_TAG, name) == 0)
- res = _handle_end_model();
- else if (::strcmp(RESOURCES_TAG, name) == 0)
- res = _handle_end_resources();
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_end_object();
- else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
- res = _handle_end_color_group();
- else if (::strcmp(COLOR_TAG, name) == 0)
- res = _handle_end_color();
- else if (::strcmp(MESH_TAG, name) == 0)
- res = _handle_end_mesh();
- else if (::strcmp(VERTICES_TAG, name) == 0)
- res = _handle_end_vertices();
- else if (::strcmp(VERTEX_TAG, name) == 0)
- res = _handle_end_vertex();
- else if (::strcmp(TRIANGLES_TAG, name) == 0)
- res = _handle_end_triangles();
- else if (::strcmp(TRIANGLE_TAG, name) == 0)
- res = _handle_end_triangle();
- else if (::strcmp(COMPONENTS_TAG, name) == 0)
- res = _handle_end_components();
- else if (::strcmp(COMPONENT_TAG, name) == 0)
- res = _handle_end_component();
- else if (::strcmp(BUILD_TAG, name) == 0)
- res = _handle_end_build();
- else if (::strcmp(ITEM_TAG, name) == 0)
- res = _handle_end_item();
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_end_metadata();
- if (!res)
- _stop_xml_parser();
- }
- void _BBS_3MF_Importer::_handle_xml_characters(const XML_Char* s, int len)
- {
- m_curr_characters.append(s, len);
- }
- void _BBS_3MF_Importer::_handle_start_config_xml_element(const char* name, const char** attributes)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(m_xml_parser);
- if (::strcmp(CONFIG_TAG, name) == 0)
- res = _handle_start_config(attributes, num_attributes);
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_start_config_object(attributes, num_attributes);
- else if (::strcmp(VOLUME_TAG, name) == 0)
- res = _handle_start_config_volume(attributes, num_attributes);
- else if (::strcmp(PART_TAG, name) == 0)
- res = _handle_start_config_volume(attributes, num_attributes);
- else if (::strcmp(MESH_STAT_TAG, name) == 0)
- res = _handle_start_config_volume_mesh(attributes, num_attributes);
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_start_config_metadata(attributes, num_attributes);
- else if (::strcmp(SHAPE_TAG, name) == 0)
- res = _handle_start_shape_configuration(attributes, num_attributes);
- else if (::strcmp(TEXT_TAG, name) == 0)
- res = _handle_start_text_configuration(attributes, num_attributes);
- else if (::strcmp(PLATE_TAG, name) == 0)
- res = _handle_start_config_plater(attributes, num_attributes);
- else if (::strcmp(INSTANCE_TAG, name) == 0)
- res = _handle_start_config_plater_instance(attributes, num_attributes);
- else if (::strcmp(FILAMENT_TAG, name) == 0)
- res = _handle_start_config_filament(attributes, num_attributes);
- else if (::strcmp(SLICE_WARNING_TAG, name) == 0)
- res = _handle_start_config_warning(attributes, num_attributes);
- else if (::strcmp(ASSEMBLE_TAG, name) == 0)
- res = _handle_start_assemble(attributes, num_attributes);
- else if (::strcmp(ASSEMBLE_ITEM_TAG, name) == 0)
- res = _handle_start_assemble_item(attributes, num_attributes);
- else if (::strcmp(TEXT_INFO_TAG, name) == 0)
- res = _handle_start_text_info_item(attributes, num_attributes);
- if (!res)
- _stop_xml_parser();
- }
- void _BBS_3MF_Importer::_handle_end_config_xml_element(const char* name)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- if (::strcmp(CONFIG_TAG, name) == 0)
- res = _handle_end_config();
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_end_config_object();
- else if (::strcmp(VOLUME_TAG, name) == 0)
- res = _handle_end_config_volume();
- else if (::strcmp(PART_TAG, name) == 0)
- res = _handle_end_config_volume();
- else if (::strcmp(MESH_STAT_TAG, name) == 0)
- res = _handle_end_config_volume_mesh();
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_end_config_metadata();
- else if (::strcmp(PLATE_TAG, name) == 0)
- res = _handle_end_config_plater();
- else if (::strcmp(FILAMENT_TAG, name) == 0)
- res = _handle_end_config_filament();
- else if (::strcmp(INSTANCE_TAG, name) == 0)
- res = _handle_end_config_plater_instance();
- else if (::strcmp(ASSEMBLE_TAG, name) == 0)
- res = _handle_end_assemble();
- else if (::strcmp(ASSEMBLE_ITEM_TAG, name) == 0)
- res = _handle_end_assemble_item();
- if (!res)
- _stop_xml_parser();
- }
- bool _BBS_3MF_Importer::_handle_start_model(const char** attributes, unsigned int num_attributes)
- {
- m_unit_factor = bbs_get_unit_factor(bbs_get_attribute_value_string(attributes, num_attributes, UNIT_ATTR));
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_model()
- {
- // BBS: Production Extension
- if (!m_sub_model_path.empty())
- return true;
- // deletes all non-built or non-instanced objects
- for (const IdToModelObjectMap::value_type& object : m_objects) {
- if (object.second >= int(m_model->objects.size())) {
- add_error("Unable to find object");
- return false;
- }
- ModelObject *model_object = m_model->objects[object.second];
- if (model_object != nullptr && model_object->instances.size() == 0)
- m_model->delete_object(model_object);
- }
- //construct the index maps
- for (const IdToCurrentObjectMap::value_type& object : m_current_objects) {
- m_index_paths.insert({ object.first.second, object.first.first});
- }
- if (!m_is_bbl_3mf) {
- // if the 3mf was not produced by OrcaSlicer and there is only one object,
- // set the object name to match the filename
- if (m_model->objects.size() == 1)
- m_model->objects.front()->name = m_name;
- }
- // applies instances' matrices
- for (Instance& instance : m_instances) {
- if (instance.instance != nullptr && instance.instance->get_object() != nullptr)
- // apply the transform to the instance
- _apply_transform(*instance.instance, instance.transform);
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_resources(const char** attributes, unsigned int num_attributes)
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_resources()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_object(const char** attributes, unsigned int num_attributes)
- {
- // reset current object data
- if (m_curr_object) {
- delete m_curr_object;
- m_curr_object = nullptr;
- }
- std::string object_type = bbs_get_attribute_value_string(attributes, num_attributes, TYPE_ATTR);
- if (bbs_is_valid_object_type(object_type)) {
- if (!m_curr_object) {
- m_curr_object = new CurrentObject();
- // create new object (it may be removed later if no instances are generated from it)
- /*m_curr_object->model_object_idx = (int)m_model->objects.size();
- m_curr_object.object = m_model->add_object();
- if (m_curr_object.object == nullptr) {
- add_error("Unable to create object");
- return false;
- }*/
- }
- m_curr_object->id = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- m_curr_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
- m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
- if (m_curr_object->uuid.empty()) {
- m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
- }
- m_curr_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_object()
- {
- if (!m_load_model) {
- delete m_curr_object;
- m_curr_object = nullptr;
- return true;
- }
- if (!m_curr_object || (m_curr_object->id == -1)) {
- add_error("Found invalid object");
- return false;
- }
- else {
- if (m_is_bbl_3mf && boost::ends_with(m_curr_object->uuid, OBJECT_UUID_SUFFIX) && m_load_restore) {
- // Adjust backup object/volume id
- std::istringstream iss(m_curr_object->uuid);
- int backup_id;
- bool need_replace = false;
- if (iss >> std::hex >> backup_id) {
- need_replace = (m_curr_object->id != backup_id);
- m_curr_object->id = backup_id;
- }
- if (!m_curr_object->components.empty())
- {
- Id first_id = m_curr_object->components.front().object_id;
- first_id.second = 0;
- IdToCurrentObjectMap::iterator current_object = m_current_objects.lower_bound(first_id);
- IdToCurrentObjectMap new_map;
- for (int index = 0; index < m_curr_object->components.size(); index++)
- {
- Component& component = m_curr_object->components[index];
- Id new_id = component.object_id;
- new_id.second = (index + 1) << 16 | backup_id;
- if (current_object != m_current_objects.end()
- && (new_id.first.empty() || new_id.first == current_object->first.first)) {
- current_object->second.id = new_id.second;
- new_map.insert({new_id, std::move(current_object->second)});
- current_object = m_current_objects.erase(current_object);
- }
- else {
- add_error("can not find object for component, id=" + std::to_string(component.object_id.second));
- delete m_curr_object;
- m_curr_object = nullptr;
- return false;
- }
- component.object_id.second = new_id.second;
- }
- for (auto & obj : new_map)
- m_current_objects.insert({obj.first, std::move(obj.second)});
- }
- }
- Id id = std::make_pair(m_sub_model_path, m_curr_object->id);
- if (m_current_objects.find(id) == m_current_objects.end()) {
- m_current_objects.insert({ id, std::move(*m_curr_object) });
- delete m_curr_object;
- m_curr_object = nullptr;
- }
- else {
- add_error("Found object with duplicate id");
- delete m_curr_object;
- m_curr_object = nullptr;
- return false;
- }
- }
- /*if (m_curr_object.object != nullptr) {
- if (m_curr_object.id != -1) {
- if (m_curr_object.geometry.empty()) {
- // no geometry defined
- // remove the object from the model
- m_model->delete_object(m_curr_object.object);
- if (m_curr_object.components.empty()) {
- // no components defined -> invalid object, delete it
- IdToModelObjectMap::iterator object_item = m_objects.find(id);
- if (object_item != m_objects.end())
- m_objects.erase(object_item);
- IdToAliasesMap::iterator alias_item = m_objects_aliases.find(id);
- if (alias_item != m_objects_aliases.end())
- m_objects_aliases.erase(alias_item);
- }
- else
- // adds components to aliases
- m_objects_aliases.insert({ id, m_curr_object.components });
- }
- else {
- // geometry defined, store it for later use
- m_geometries.insert({ id, std::move(m_curr_object.geometry) });
- // stores the object for later use
- if (m_objects.find(id) == m_objects.end()) {
- m_objects.insert({ id, m_curr_object.model_object_idx });
- m_objects_aliases.insert({ id, { 1, Component(m_curr_object.id) } }); // aliases itself
- }
- else {
- add_error("Found object with duplicate id");
- return false;
- }
- }
- }
- else {
- //sub objects
- }
- }*/
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_color_group(const char **attributes, unsigned int num_attributes)
- {
- m_current_color_group = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_color_group()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_color(const char **attributes, unsigned int num_attributes)
- {
- std::string color = bbs_get_attribute_value_string(attributes, num_attributes, COLOR_ATTR);
- m_group_id_to_color[m_current_color_group] = color;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_color()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_mesh(const char** attributes, unsigned int num_attributes)
- {
- // reset current geometry
- if (m_curr_object)
- m_curr_object->geometry.reset();
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_mesh()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_vertices(const char** attributes, unsigned int num_attributes)
- {
- // reset current vertices
- if (m_curr_object)
- m_curr_object->geometry.vertices.clear();
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_vertices()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_vertex(const char** attributes, unsigned int num_attributes)
- {
- // appends the vertex coordinates
- // missing values are set equal to ZERO
- if (m_curr_object)
- m_curr_object->geometry.vertices.emplace_back(
- m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR),
- m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR),
- m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR));
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_vertex()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_triangles(const char** attributes, unsigned int num_attributes)
- {
- // reset current triangles
- if (m_curr_object)
- m_curr_object->geometry.triangles.clear();
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_triangles()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_triangle(const char** attributes, unsigned int num_attributes)
- {
- // we are ignoring the following attributes:
- // p1
- // p2
- // p3
- // pid
- // see specifications
- // appends the triangle's vertices indices
- // missing values are set equal to ZERO
- if (m_curr_object) {
- m_curr_object->geometry.triangles.emplace_back(
- bbs_get_attribute_value_int(attributes, num_attributes, V1_ATTR),
- bbs_get_attribute_value_int(attributes, num_attributes, V2_ATTR),
- bbs_get_attribute_value_int(attributes, num_attributes, V3_ATTR));
- m_curr_object->geometry.custom_supports.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
- m_curr_object->geometry.custom_seam.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
- m_curr_object->geometry.mmu_segmentation.push_back(bbs_get_attribute_value_string(attributes, num_attributes, MMU_SEGMENTATION_ATTR));
- // BBS
- m_curr_object->geometry.face_properties.push_back(bbs_get_attribute_value_string(attributes, num_attributes, FACE_PROPERTY_ATTR));
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_triangle()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_components(const char** attributes, unsigned int num_attributes)
- {
- // reset current components
- if (m_curr_object)
- m_curr_object->components.clear();
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_components()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes)
- {
- std::string path = xml_unescape(bbs_get_attribute_value_string(attributes, num_attributes, PPATH_ATTR));
- int object_id = bbs_get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
- Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
- /*Id id = std::make_pair(m_sub_model_path, object_id);
- IdToModelObjectMap::iterator object_item = m_objects.find(id);
- if (object_item == m_objects.end()) {
- IdToAliasesMap::iterator alias_item = m_objects_aliases.find(id);
- if (alias_item == m_objects_aliases.end()) {
- add_error("Found component with invalid object id");
- return false;
- }
- }*/
- if (m_curr_object) {
- Id id = std::make_pair(m_sub_model_path.empty() ? path : m_sub_model_path, object_id);
- m_curr_object->components.emplace_back(id, transform);
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_component()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_build(const char** attributes, unsigned int num_attributes)
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_build()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_item(const char** attributes, unsigned int num_attributes)
- {
- // we are ignoring the following attributes
- // thumbnail
- // partnumber
- // pid
- // pindex
- // see specifications
- int object_id = bbs_get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
- std::string path = bbs_get_attribute_value_string(attributes, num_attributes, PPATH_ATTR);
- Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
- int printable = bbs_get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR);
- return !m_load_model || _create_object_instance(path, object_id, transform, printable, 1);
- }
- bool _BBS_3MF_Importer::_handle_end_item()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_metadata(const char** attributes, unsigned int num_attributes)
- {
- m_curr_characters.clear();
- std::string name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
- if (!name.empty()) {
- m_curr_metadata_name = name;
- }
- return true;
- }
- inline static void check_painting_version(unsigned int loaded_version, unsigned int highest_supported_version, const std::string &error_msg)
- {
- if (loaded_version > highest_supported_version)
- throw version_error(error_msg);
- }
- bool _BBS_3MF_Importer::_handle_end_metadata()
- {
- if ((m_curr_metadata_name == BBS_3MF_VERSION)||(m_curr_metadata_name == BBS_3MF_VERSION1)) {
- //m_is_bbl_3mf = true;
- m_version = (unsigned int)atoi(m_curr_characters.c_str());
- /*if (m_check_version && (m_version > VERSION_BBS_3MF_COMPATIBLE)) {
- // std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
- // throw version_error(msg.c_str());
- const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str();
- throw version_error(msg);
- }*/
- } else if (m_curr_metadata_name == BBL_APPLICATION_TAG) {
- // Generator application of the 3MF.
- // SLIC3R_APP_KEY - SoftFever_VERSION
- if (boost::starts_with(m_curr_characters, "BambuStudio-")) {
- m_is_bbl_3mf = true;
- m_bambuslicer_generator_version = Semver::parse(m_curr_characters.substr(12));
- }
- else if (boost::starts_with(m_curr_characters, "OrcaSlicer-")) {
- m_is_bbl_3mf = true;
- m_bambuslicer_generator_version = Semver::parse(m_curr_characters.substr(11));
- }
- //TODO: currently use version 0, no need to load&&save this string
- /*} else if (m_curr_metadata_name == BBS_FDM_SUPPORTS_PAINTING_VERSION) {
- m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
- check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION,
- _(L("The selected 3MF contains FDM supports painted object using a newer version of OrcaSlicer and is not compatible.")));
- } else if (m_curr_metadata_name == BBS_SEAM_PAINTING_VERSION) {
- m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
- check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION,
- _(L("The selected 3MF contains seam painted object using a newer version of OrcaSlicer and is not compatible.")));
- } else if (m_curr_metadata_name == BBS_MM_PAINTING_VERSION) {
- m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
- check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION,
- _(L("The selected 3MF contains multi-material painted object using a newer version of OrcaSlicer and is not compatible.")));*/
- } else if (m_curr_metadata_name == BBL_MODEL_ID_TAG) {
- m_model_id = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_MODEL_NAME_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters;
- //model_info.model_name = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_ORIGIN_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found model name = " << m_curr_characters;
- //model_info.origin = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_DESIGNER_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer = " << m_curr_characters;
- m_designer = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_DESIGNER_USER_ID_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer_user_id = " << m_curr_characters;
- m_designer_user_id = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_DESIGNER_COVER_FILE_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found designer_cover = " << m_curr_characters;
- //model_info.cover_file = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_DESCRIPTION_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found description = " << m_curr_characters;
- //model_info.description = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_LICENSE_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found license = " << m_curr_characters;
- //model_info.license = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_COPYRIGHT_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found CopyRight = " << m_curr_characters;
- //model_info.copyright = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_COPYRIGHT_NORMATIVE_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found Copyright = " << m_curr_characters;
- //model_info.copyright = xml_unescape(m_curr_characters); //Susi_not_impl
- } else if (m_curr_metadata_name == BBL_REGION_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters;
- m_contry_code = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_PROFILE_TITLE_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_title = " << m_curr_characters;
- m_profile_title = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_PROFILE_COVER_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_cover = " << m_curr_characters;
- m_profile_cover = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_PROFILE_DESCRIPTION_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_description = " << m_curr_characters;
- m_Profile_description = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_PROFILE_USER_ID_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_user_id = " << m_curr_characters;
- m_profile_user_id = xml_unescape(m_curr_characters);
- }else if (m_curr_metadata_name == BBL_PROFILE_USER_NAME_TAG) {
- BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found profile_user_name = " << m_curr_characters;
- m_profile_user_name = xml_unescape(m_curr_characters);
- } else if (m_curr_metadata_name == BBL_CREATION_DATE_TAG) {
- ;
- } else if (m_curr_metadata_name == BBL_MODIFICATION_TAG) {
- ;
- } else {
- ;
- }
- if (!m_curr_metadata_name.empty()) {
- BOOST_LOG_TRIVIAL(info) << "load_3mf found metadata key = " << m_curr_metadata_name << ", value = " << xml_unescape(m_curr_characters);
- //model_info.metadata_items[m_curr_metadata_name] = xml_unescape(m_curr_characters); //Susi_not_impl
- }
- return true;
- }
- //struct TextConfigurationSerialization
- //{
- //public:
- // TextConfigurationSerialization() = delete;
- //
- // using TypeToName = boost::bimap<EmbossStyle::Type, std::string_view>;
- // static const TypeToName type_to_name;
- // using HorizontalAlignToName = boost::bimap<FontProp::HorizontalAlign, std::string_view>;
- // static const HorizontalAlignToName horizontal_align_to_name;
- // using VerticalAlignToName = boost::bimap<FontProp::VerticalAlign, std::string_view>;
- // static const VerticalAlignToName vertical_align_to_name;
- //
- // static EmbossStyle::Type get_type(std::string_view type) {
- // const auto& to_type = TextConfigurationSerialization::type_to_name.right;
- // auto type_item = to_type.find(type);
- // assert(type_item != to_type.end());
- // if (type_item == to_type.end()) return EmbossStyle::Type::undefined;
- // return type_item->second;
- // }
- // static std::string_view get_name(EmbossStyle::Type type) {
- // const auto& to_name = TextConfigurationSerialization::type_to_name.left;
- // auto type_name = to_name.find(type);
- // assert(type_name != to_name.end());
- // if (type_name == to_name.end()) return "unknown type";
- // return type_name->second;
- // }
- // static void to_xml(std::stringstream &stream, const TextConfiguration &tc);
- // static std::optional<TextConfiguration> read(const char **attributes, unsigned int num_attributes);
- // static EmbossShape read_old(const char **attributes, unsigned int num_attributes);
- //}; //Susi_not_impl
- bool _BBS_3MF_Importer::_handle_start_text_configuration(const char **attributes, unsigned int num_attributes)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("Can not assign volume mesh to a valid object");
- return false;
- }
- if (object->second.volumes.empty()) {
- add_error("Can not assign mesh to a valid volume");
- return false;
- }
- ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back();
- //volume.text_configuration = TextConfigurationSerialization::read(attributes, num_attributes); //Susi_not_impl
- //if (!volume.text_configuration.has_value()) //Susi_not_impl
- // return false;
- // Is 3mf version with shapes?
- //if (volume.shape_configuration.has_value()) //Susi_not_impl
- // return true;
- // Back compatibility for 3mf version without shapes
- //volume.shape_configuration = TextConfigurationSerialization::read_old(attributes, num_attributes); //Susi_not_impl
- return true;
- }
- // Definition of read/write method for EmbossShape
- static void to_xml(std::stringstream &stream, /*const EmbossShape &es, */const ModelVolume &volume, mz_zip_archive &archive);
- //static std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes); //Susi_not_impl
- bool _BBS_3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("Can not assign volume mesh to a valid object");
- return false;
- }
- auto &volumes = object->second.volumes;
- if (volumes.empty()) {
- add_error("Can not assign mesh to a valid volume");
- return false;
- }
- ObjectMetadata::VolumeMetadata &volume = volumes.back();
- //volume.shape_configuration = read_emboss_shape(attributes, num_attributes);
- //if (!volume.shape_configuration.has_value())
- // return false; //Susi_not_impl
- // Fill svg file content into shape_configuration
- //std::optional<EmbossShape::SvgFile> &svg = volume.shape_configuration->svg_file;
- //if (!svg.has_value())
- // return true; // do not contain svg file //Susi_not_impl
- //const std::string &path = svg->path_in_3mf;
- //if (path.empty())
- // return true; // do not contain svg file //Susi_not_impl
- //auto it = m_path_to_emboss_shape_files.find(path);
- //if (it == m_path_to_emboss_shape_files.end())
- // return true; // svg file is not loaded yet //Susi_not_impl
- //svg->file_data = it->second; //Susi_not_impl
- return true;
- }
- bool _BBS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
- {
- static const unsigned int MAX_RECURSIONS = 10;
- // escape from circular aliasing
- if (recur_counter > MAX_RECURSIONS) {
- add_error("Too many recursions");
- return false;
- }
- Id id{path, object_id};
- IdToCurrentObjectMap::iterator it = m_current_objects.find(id);
- if (it == m_current_objects.end()) {
- add_error("can not find object id " + std::to_string(object_id) + " to builditem");
- return false;
- }
- IdToModelObjectMap::iterator object_item = m_objects.find(id);
- if (object_item == m_objects.end()) {
- //add object
- CurrentObject& current_object = it->second;
- int object_index = (int)m_model->objects.size();
- ModelObject* model_object = m_model->add_object();
- if (model_object == nullptr) {
- add_error("Unable to create object for builditem, id " + std::to_string(object_id));
- return false;
- }
- m_objects.insert({ id, object_index });
- current_object.model_object_idx = object_index;
- current_object.object = model_object;
- ModelInstance* instance = m_model->objects[object_index]->add_instance();
- if (instance == nullptr) {
- add_error("error when add object instance for id " + std::to_string(object_id));
- return false;
- }
- instance->printable = printable;
- m_instances.emplace_back(instance, transform);
- if (m_is_bbl_3mf && boost::ends_with(current_object.uuid, OBJECT_UUID_SUFFIX)) {
- std::istringstream iss(current_object.uuid);
- int backup_id;
- if (iss >> std::hex >> backup_id) {
- //m_model->set_object_backup_id(*model_object, backup_id); //Susi_not_impl
- }
- }
- /*if (!current_object.geometry.empty()) {
- }
- else if (!current_object.components.empty()) {
- // recursively process nested components
- for (const Component& component : it->second) {
- if (!_create_object_instance(path, component.object_id, transform * component.transform, printable, recur_counter + 1))
- return false;
- }
- }
- else {
- add_error("can not construct build items with invalid object, id " + std::to_string(object_id));
- return false;
- }*/
- }
- else {
- //add instance
- ModelInstance* instance = m_model->objects[object_item->second]->add_instance();
- if (instance == nullptr) {
- add_error("error when add object instance for id " + std::to_string(object_id));
- return false;
- }
- instance->printable = printable;
- m_instances.emplace_back(instance, transform);
- }
- /*if (it->second.size() == 1 && it->second[0].object_id == object_id) {
- // aliasing to itself
- IdToModelObjectMap::iterator object_item = m_objects.find(id);
- if (object_item == m_objects.end() || object_item->second == -1) {
- add_error("Found invalid object");
- return false;
- }
- else {
- ModelInstance* instance = m_model->objects[object_item->second]->add_instance();
- if (instance == nullptr) {
- add_error("Unable to add object instance");
- return false;
- }
- instance->printable = printable;
- m_instances.emplace_back(instance, transform);
- }
- }
- else {
- // recursively process nested components
- for (const Component& component : it->second) {
- if (!_create_object_instance(path, component.object_id, transform * component.transform, printable, recur_counter + 1))
- return false;
- }
- }*/
- return true;
- }
- void _BBS_3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform)
- {
- Slic3r::Geometry::Transformation t(transform);
- // invalid scale value, return
- if (!t.get_scaling_factor().all())
- return;
- instance.set_transformation(t);
- }
- bool _BBS_3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes)
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_object(const char** attributes, unsigned int num_attributes)
- {
- if (m_parsing_slice_info)
- return true;
- int object_id = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- IdToMetadataMap::iterator object_item = m_objects_metadata.find(object_id);
- if (object_item != m_objects_metadata.end()) {
- add_error("Duplicated object id: " + std::to_string(object_id) + " in model_settings.config");
- return false;
- }
- // Added because of github #3435, currently not used by PrusaSlicer
- // int instances_count_id = bbs_get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
- m_objects_metadata.insert({ object_id, ObjectMetadata() });
- m_curr_config.object_id = object_id;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_object()
- {
- m_curr_config.object_id = -1;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_volume(const char** attributes, unsigned int num_attributes)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("can not find object for part, id " + std::to_string(m_curr_config.object_id) );
- return false;
- }
- m_curr_config.volume_id = (int)object->second.volumes.size();
- unsigned int first_triangle_id = (unsigned int)bbs_get_attribute_value_int(attributes, num_attributes, FIRST_TRIANGLE_ID_ATTR);
- unsigned int last_triangle_id = (unsigned int)bbs_get_attribute_value_int(attributes, num_attributes, LAST_TRIANGLE_ID_ATTR);
- //BBS: refine the part type logic
- std::string subtype_str = bbs_get_attribute_value_string(attributes, num_attributes, SUBTYPE_ATTR);
- if( "normal_part" == subtype_str)
- subtype_str = "ModelPart";
- else if("negative_part" == subtype_str)
- subtype_str = "NegativeVolume";
- else if("modifier_part" == subtype_str)
- subtype_str = "ParameterModifier";
- else if("support_enforcer" == subtype_str)
- subtype_str = "SupportEnforcer";
- else if("support_blocker" == subtype_str)
- subtype_str = "SupportBlocker";
- ModelVolumeType type = ModelVolume::type_from_string(subtype_str);
- int subbject_id = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- if (last_triangle_id > 0)
- object->second.volumes.emplace_back(first_triangle_id, last_triangle_id, type);
- else
- object->second.volumes.emplace_back(subbject_id, type);
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("can not find object for mesh_stats, id " + std::to_string(m_curr_config.object_id) );
- return false;
- }
- if ((m_curr_config.volume_id == -1) || ((object->second.volumes.size() - 1) < m_curr_config.volume_id)) {
- add_error("can not find part for mesh_stats");
- return false;
- }
- ObjectMetadata::VolumeMetadata& volume = object->second.volumes[m_curr_config.volume_id];
- int edges_fixed = bbs_get_attribute_value_int(attributes, num_attributes, MESH_STAT_EDGES_FIXED );
- int degenerate_facets = bbs_get_attribute_value_int(attributes, num_attributes, MESH_STAT_DEGENERATED_FACETS);
- int facets_removed = bbs_get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_REMOVED );
- int facets_reversed = bbs_get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_RESERVED );
- int backwards_edges = bbs_get_attribute_value_int(attributes, num_attributes, MESH_STAT_BACKWARDS_EDGES );
- volume.mesh_stats = { edges_fixed, degenerate_facets, facets_removed, facets_reversed, backwards_edges };
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_volume()
- {
- m_curr_config.volume_id = -1;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_volume_mesh()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_metadata(const char** attributes, unsigned int num_attributes)
- {
- //std::string type = bbs_get_attribute_value_string(attributes, num_attributes, TYPE_ATTR);
- std::string key = bbs_get_attribute_value_string(attributes, num_attributes, KEY_ATTR);
- std::string value = bbs_get_attribute_value_string(attributes, num_attributes, VALUE_ATTR);
- if ((m_curr_plater == nullptr)&&!m_parsing_slice_info)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("Cannot find object for metadata, id " + std::to_string(m_curr_config.object_id));
- return false;
- }
- if (m_curr_config.volume_id == -1)
- object->second.metadata.emplace_back(key, value);
- else {
- if (size_t(m_curr_config.volume_id) < object->second.volumes.size())
- object->second.volumes[m_curr_config.volume_id].metadata.emplace_back(key, value);
- }
- }
- else
- {
- //plater
- if (key == PLATERID_ATTR)
- {
- m_curr_plater->plate_index = atoi(value.c_str());
- }
- else if (key == PLATER_NAME_ATTR) {
- m_curr_plater->plate_name = xml_unescape(value.c_str());
- }
- else if (key == LOCK_ATTR)
- {
- std::istringstream(value) >> std::boolalpha >> m_curr_plater->locked;
- }
- else if (key == BED_TYPE_ATTR)
- {
- //BedType bed_type = BedType::btPC;
- //ConfigOptionEnum<BedType>::from_string(value, bed_type);
- //m_curr_plater->config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type)); //Susi_not_impl
- }
- else if (key == PRINT_SEQUENCE_ATTR)
- {
- //PrintSequence print_sequence = PrintSequence::ByLayer;
- //ConfigOptionEnum<PrintSequence>::from_string(value, print_sequence);
- //m_curr_plater->config.set_key_value("print_sequence", new ConfigOptionEnum<PrintSequence>(print_sequence));
- if (value == "by layer")
- m_curr_plater->config.set_key_value("complete_objects", new ConfigOptionBool(false));
- else if (value == "by object")
- m_curr_plater->config.set_key_value("complete_objects", new ConfigOptionBool(true));
- else
- assert(false);
- }
- else if (key == FIRST_LAYER_PRINT_SEQUENCE_ATTR) {
- auto get_vector_from_string = [](const std::string &str) -> std::vector<int> {
- std::stringstream stream(str);
- int value;
- std::vector<int> results;
- while (stream >> value) {
- results.push_back(value);
- }
- return results;
- };
- //m_curr_plater->config.set_key_value("first_layer_print_sequence", new ConfigOptionInts(get_vector_from_string(value))); //Susi_not_impl
- }
- else if (key == SPIRAL_VASE_MODE) {
- bool spiral_mode = false;
- std::istringstream(value) >> std::boolalpha >> spiral_mode;
- m_curr_plater->config.set_key_value("spiral_vase"/*"spiral_mode"*/, new ConfigOptionBool(spiral_mode));
- }
- else if (key == GCODE_FILE_ATTR)
- {
- m_curr_plater->gcode_file = value;
- }
- else if (key == THUMBNAIL_FILE_ATTR)
- {
- m_curr_plater->thumbnail_file = value;
- }
- else if (key == TOP_FILE_ATTR)
- {
- m_curr_plater->top_file = value;
- }
- else if (key == PICK_FILE_ATTR)
- {
- m_curr_plater->pick_file = value;
- }
- //else if (key == PATTERN_FILE_ATTR)
- //{
- // m_curr_plater->pattern_file = value;
- //}
- else if (key == PATTERN_BBOX_FILE_ATTR)
- {
- m_curr_plater->pattern_bbox_file = value;
- }
- else if (key == INSTANCEID_ATTR)
- {
- m_curr_instance.instance_id = atoi(value.c_str());
- }
- else if (key == IDENTIFYID_ATTR)
- {
- m_curr_instance.identify_id = atoi(value.c_str());
- }
- else if (key == OBJECT_ID_ATTR)
- {
- m_curr_instance.object_id = atoi(value.c_str());
- /*int obj_id = atoi(value.c_str());
- m_curr_instance.object_id = -1;
- IndexToPathMap::iterator index_iter = m_index_paths.find(obj_id);
- if (index_iter == m_index_paths.end()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__
- << boost::format(", can not find object for plate's item, id=%1%, skip this object")%obj_id;
- return true;
- }
- Id temp_id = std::make_pair(index_iter->second, index_iter->first);
- IdToModelObjectMap::iterator object_item = m_objects.find(temp_id);
- if (object_item == m_objects.end()) {
- BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__
- << boost::format(", can not find object for plate's item, ID <%1%, %2%>, skip this object")%index_iter->second %index_iter->first;
- return true;
- }
- m_curr_instance.object_id = object_item->second;*/
- }
- else if (key == PLATE_IDX_ATTR)
- {
- int plate_index = atoi(value.c_str());
- std::map<int, PlateData*>::iterator it = m_plater_data.find(plate_index);
- if (it != m_plater_data.end())
- m_curr_plater = it->second;
- }
- else if (key == SLICE_PREDICTION_ATTR)
- {
- if (m_curr_plater)
- m_curr_plater->gcode_prediction = value;
- }
- else if (key == SLICE_WEIGHT_ATTR)
- {
- if (m_curr_plater)
- m_curr_plater->gcode_weight = value;
- }
- else if (key == OUTSIDE_ATTR)
- {
- if (m_curr_plater)
- std::istringstream(value) >> std::boolalpha >> m_curr_plater->toolpath_outside;
- }
- else if (key == SUPPORT_USED_ATTR)
- {
- if (m_curr_plater)
- std::istringstream(value) >> std::boolalpha >> m_curr_plater->is_support_used;
- }
- else if (key == LABEL_OBJECT_ENABLED_ATTR)
- {
- if (m_curr_plater)
- std::istringstream(value) >> std::boolalpha >> m_curr_plater->is_label_object_enabled;
- }
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_metadata()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_filament(const char** attributes, unsigned int num_attributes)
- {
- if (m_curr_plater) {
- std::string id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_ID_TAG);
- std::string type = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_TYPE_TAG);
- std::string color = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_COLOR_TAG);
- std::string used_m = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_M_TAG);
- std::string used_g = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_G_TAG);
- FilamentInfo filament_info;
- filament_info.id = atoi(id.c_str()) - 1;
- filament_info.type = type;
- filament_info.color = color;
- filament_info.used_m = atof(used_m.c_str());
- filament_info.used_g = atof(used_g.c_str());
- m_curr_plater->slice_filaments_info.push_back(filament_info);
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_filament()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_warning(const char** attributes, unsigned int num_attributes)
- {
- if (m_curr_plater) {
- std::string msg = bbs_get_attribute_value_string(attributes, num_attributes, WARNING_MSG_TAG);
- std::string lvl_str = bbs_get_attribute_value_string(attributes, num_attributes, "level");
- //GCodeProcessorResult::SliceWarning sw;
- //sw.msg = msg;
- //try {
- // sw.level = atoi(lvl_str.c_str());
- //}
- //catch(...) {
- //}; //Susi_not_impl
- m_curr_plater->warnings.push_back(msg);
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_warning()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_plater(const char** attributes, unsigned int num_attributes)
- {
- if (!m_parsing_slice_info) {
- m_curr_plater = new PlateData();
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_plater()
- {
- if (!m_curr_plater)
- {
- add_error("_handle_end_config_plater: don't find plate created before");
- return false;
- }
- m_plater_data.emplace(m_curr_plater->plate_index, m_curr_plater);
- m_curr_plater = nullptr;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_config_plater_instance(const char** attributes, unsigned int num_attributes)
- {
- if (!m_curr_plater)
- {
- add_error("_handle_start_config_plater_instance: don't find plate created before");
- return false;
- }
- //do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_config_plater_instance()
- {
- if (!m_curr_plater)
- {
- add_error("_handle_end_config_plater_instance: don't find plate created before");
- return false;
- }
- if ((m_curr_instance.object_id == -1) || (m_curr_instance.instance_id == -1))
- {
- //add_error("invalid object id/instance id");
- //skip this instance
- m_curr_instance.object_id = m_curr_instance.instance_id = -1;
- m_curr_instance.identify_id = 0;
- return true;
- }
- m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, std::make_pair(m_curr_instance.instance_id, m_curr_instance.identify_id));
- m_curr_instance.object_id = m_curr_instance.instance_id = -1;
- m_curr_instance.identify_id = 0;
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_assemble(const char** attributes, unsigned int num_attributes)
- {
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_assemble()
- {
- //do nothing
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_assemble_item(const char** attributes, unsigned int num_attributes)
- {
- if (!m_load_model) return true;
- int object_id = bbs_get_attribute_value_int(attributes, num_attributes, OBJECT_ID_ATTR);
- int instance_id = bbs_get_attribute_value_int(attributes, num_attributes, INSTANCEID_ATTR);
- IndexToPathMap::iterator index_iter = m_index_paths.find(object_id);
- if (index_iter == m_index_paths.end()) {
- add_error("can not find object for assemble item, id= " + std::to_string(object_id));
- return false;
- }
- Id temp_id = std::make_pair(index_iter->second, index_iter->first);
- IdToModelObjectMap::iterator object_item = m_objects.find(temp_id);
- if (object_item == m_objects.end()) {
- add_error("can not find object for assemble item, id= " + std::to_string(object_id));
- return false;
- }
- object_id = object_item->second;
- Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
- Vec3d ofs2ass = bbs_get_offset_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, OFFSET_ATTR));
- if (object_id < m_model->objects.size()) {
- if (instance_id < m_model->objects[object_id]->instances.size()) {
- //m_model->objects[object_id]->instances[instance_id]->set_assemble_from_transform(transform); //Susi_not_impl
- //m_model->objects[object_id]->instances[instance_id]->set_offset_to_assembly(ofs2ass); //Susi_not_impl
- }
- }
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_assemble_item()
- {
- return true;
- }
- bool _BBS_3MF_Importer::_handle_start_text_info_item(const char **attributes, unsigned int num_attributes)
- {
- IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
- if (object == m_objects_metadata.end()) {
- add_error("can not find object for text_info, id " + std::to_string(m_curr_config.object_id));
- return false;
- }
- if ((m_curr_config.volume_id == -1) || ((object->second.volumes.size() - 1) < m_curr_config.volume_id)) {
- add_error("can not find part for text_info");
- return false;
- }
- ObjectMetadata::VolumeMetadata &volume = object->second.volumes[m_curr_config.volume_id];
- //if (volume.text_configuration.has_value()) {
- // add_error("Both text_info and text_configuration found, ignore legacy text_info");
- // return true;
- //} //Susi_not_impl
- // TODO: Orca: support legacy text info
- /*
- TextInfo text_info;
- text_info.m_text = xml_unescape(bbs_get_attribute_value_string(attributes, num_attributes, TEXT_ATTR));
- text_info.m_font_name = bbs_get_attribute_value_string(attributes, num_attributes, FONT_NAME_ATTR);
- text_info.m_curr_font_idx = bbs_get_attribute_value_int(attributes, num_attributes, FONT_INDEX_ATTR);
- text_info.m_font_size = bbs_get_attribute_value_float(attributes, num_attributes, FONT_SIZE_ATTR);
- text_info.m_thickness = bbs_get_attribute_value_float(attributes, num_attributes, THICKNESS_ATTR);
- text_info.m_embeded_depth = bbs_get_attribute_value_float(attributes, num_attributes, EMBEDED_DEPTH_ATTR);
- text_info.m_rotate_angle = bbs_get_attribute_value_float(attributes, num_attributes, ROTATE_ANGLE_ATTR);
- text_info.m_text_gap = bbs_get_attribute_value_float(attributes, num_attributes, TEXT_GAP_ATTR);
- text_info.m_bold = bbs_get_attribute_value_int(attributes, num_attributes, BOLD_ATTR);
- text_info.m_italic = bbs_get_attribute_value_int(attributes, num_attributes, ITALIC_ATTR);
- text_info.m_is_surface_text = bbs_get_attribute_value_int(attributes, num_attributes, SURFACE_TEXT_ATTR);
- text_info.m_keep_horizontal = bbs_get_attribute_value_int(attributes, num_attributes, KEEP_HORIZONTAL_ATTR);
- text_info.m_rr.mesh_id = bbs_get_attribute_value_int(attributes, num_attributes, HIT_MESH_ATTR);
- std::string hit_pos = bbs_get_attribute_value_string(attributes, num_attributes, HIT_POSITION_ATTR);
- if (!hit_pos.empty())
- text_info.m_rr.hit = get_vec3_from_string(hit_pos);
- std::string hit_normal = bbs_get_attribute_value_string(attributes, num_attributes, HIT_NORMAL_ATTR);
- if (!hit_normal.empty())
- text_info.m_rr.normal = get_vec3_from_string(hit_normal);
- volume.text_info = text_info;*/
- return true;
- }
- bool _BBS_3MF_Importer::_handle_end_text_info_item()
- {
- return true;
- }
- void XMLCALL _BBS_3MF_Importer::_handle_start_relationships_element(void* userData, const char* name, const char** attributes)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_start_relationships_element(name, attributes);
- }
- void XMLCALL _BBS_3MF_Importer::_handle_end_relationships_element(void* userData, const char* name)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_end_relationships_element(name);
- }
- void _BBS_3MF_Importer::_handle_start_relationships_element(const char* name, const char** attributes)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(m_xml_parser);
- if (::strcmp(RELATIONSHIP_TAG, name) == 0)
- res = _handle_start_relationship(attributes, num_attributes);
- m_curr_characters.clear();
- if (!res)
- _stop_xml_parser();
- }
- void _BBS_3MF_Importer::_handle_end_relationships_element(const char* name)
- {
- if (m_xml_parser == nullptr)
- return;
- bool res = true;
- if (!res)
- _stop_xml_parser();
- }
- bool _BBS_3MF_Importer::_handle_start_relationship(const char** attributes, unsigned int num_attributes)
- {
- std::string path = bbs_get_attribute_value_string(attributes, num_attributes, TARGET_ATTR);
- std::string type = bbs_get_attribute_value_string(attributes, num_attributes, RELS_TYPE_ATTR);
- if (boost::starts_with(type, "http://schemas.microsoft.com/3dmanufacturing/") && boost::ends_with(type, "3dmodel")) {
- if (m_start_part_path.empty()) m_start_part_path = path;
- else m_sub_model_paths.push_back(path);
- } else if (boost::starts_with(type, "http://schemas.openxmlformats.org/") && boost::ends_with(type, "thumbnail")) {
- if (boost::algorithm::ends_with(path, ".png"))
- m_thumbnail_path = path;
- } else if (boost::starts_with(type, "http://schemas.bambulab.com/") && boost::ends_with(type, "cover-thumbnail-middle")) {
- m_thumbnail_middle = path;
- } else if (boost::starts_with(type, "http://schemas.bambulab.com/") && boost::ends_with(type, "cover-thumbnail-small")) {
- m_thumbnail_small = path;
- }
- return true;
- }
- void _BBS_3MF_Importer::_generate_current_object_list(std::vector<Component> &sub_objects, Id object_id, IdToCurrentObjectMap ¤t_objects)
- {
- std::list<std::pair<Component, Transform3d>> id_list; // ???? it's filled then deleted? [merill]
- id_list.push_back(std::make_pair(Component(object_id, Transform3d::Identity()), Transform3d::Identity()));
- while (!id_list.empty())
- {
- auto current_item = id_list.front();
- Component current_id = current_item.first;
- id_list.pop_front();
- IdToCurrentObjectMap::iterator current_object = current_objects.find(current_id.object_id);
- if (current_object != current_objects.end()) {
- //found one
- if (!current_object->second.components.empty()) {
- for (const Component &comp : current_object->second.components) {
- id_list.push_back(std::pair(comp, current_item.second * comp.transform));
- }
- }
- else if (!(current_object->second.geometry.empty())) {
- //CurrentObject* ptr = &(current_objects[current_id]);
- //CurrentObject* ptr2 = &(current_object->second);
- sub_objects.push_back({ current_object->first, current_item.second});
- }
- }
- }
- }
- bool _BBS_3MF_Importer::_generate_volumes_new(ModelObject& object, const std::vector<Component> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, const DynamicPrintConfig &config, ConfigSubstitutionContext& config_substitutions)
- {
- if (!object.volumes.empty()) {
- add_error("object already built with parts");
- return false;
- }
- //unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
- unsigned int renamed_volumes_count = 0;
- for (unsigned int index = 0; index < sub_objects.size(); index++)
- {
- //find the volume metadata firstly
- Component sub_comp = sub_objects[index];
- Id object_id = sub_comp.object_id;
- IdToCurrentObjectMap::iterator current_object = m_current_objects.find(object_id);
- if (current_object == m_current_objects.end()) {
- add_error("sub_objects can not be found, id=" + std::to_string(object_id.second));
- return false;
- }
- CurrentObject* sub_object = &(current_object->second);
- const ObjectMetadata::VolumeMetadata* volume_data = nullptr;
- ObjectMetadata::VolumeMetadata default_volume_data(sub_object->id);
- if (index < volumes.size() && volumes[index].subobject_id == sub_object->id)
- volume_data = &volumes[index];
- else for (const ObjectMetadata::VolumeMetadata& volume_iter : volumes) {
- if (volume_iter.subobject_id == sub_object->id) {
- volume_data = &volume_iter;
- break;
- }
- }
- Transform3d volume_matrix_to_object = Transform3d::Identity();
- bool has_transform = false;
- int shared_mesh_id = object_id.second;
- if (volume_data)
- {
- int found_count = 0;
- // extract the volume transformation from the volume's metadata, if present
- for (const Metadata& metadata : volume_data->metadata) {
- if (metadata.key == MATRIX_KEY) {
- volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
- has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
- found_count++;
- }
- else if (metadata.key == MESH_SHARED_KEY){
- //add the shared mesh logic
- shared_mesh_id = ::atoi(metadata.value.c_str());
- found_count++;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": line %1%, shared_mesh_id %2%")%__LINE__%shared_mesh_id;
- }
- if (found_count >= 2)
- break;
- }
- }
- else {
- //create a volume_data
- volume_data = &default_volume_data;
- }
- ModelVolume* volume = nullptr;
- ModelVolume *shared_volume = nullptr;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": line %1%, subobject_id %2%, shared_mesh_id %3%")%__LINE__ %sub_object->id %shared_mesh_id;
- if (shared_mesh_id != -1) {
- std::map<int, ModelVolume*>::iterator iter = m_shared_meshes.find(shared_mesh_id);
- if (iter != m_shared_meshes.end()) {
- shared_volume = iter->second;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": line %1%, found shared mesh, id %2%, mesh %3%")%__LINE__%shared_mesh_id%shared_volume;
- }
- }
- else {
- //for some cases, object point to this shared mesh already loaded, treat that one as the root
- std::map<int, ModelVolume*>::iterator iter = m_shared_meshes.find(sub_object->id);
- if (iter != m_shared_meshes.end()) {
- shared_volume = iter->second;
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": line %1%, already loaded copy-share mesh before, id %2%, mesh %3%")%__LINE__%sub_object->id%shared_volume;
- }
- }
- const size_t triangles_count = sub_object->geometry.triangles.size();
- if (triangles_count == 0) {
- add_error("found no trianges in the object " + std::to_string(sub_object->id));
- return false;
- }
- if (!shared_volume){
- // splits volume out of imported geometry
- indexed_triangle_set its;
- its.indices.assign(sub_object->geometry.triangles.begin(), sub_object->geometry.triangles.end());
- //const size_t triangles_count = its.indices.size();
- //if (triangles_count == 0) {
- // add_error("found no trianges in the object " + std::to_string(sub_object->id));
- // return false;
- //}
- for (const Vec3i32& face : its.indices) {
- for (const int tri_id : face) {
- if (tri_id < 0 || tri_id >= int(sub_object->geometry.vertices.size())) {
- add_error("invalid vertex id in object " + std::to_string(sub_object->id));
- return false;
- }
- }
- }
- its.vertices.assign(sub_object->geometry.vertices.begin(), sub_object->geometry.vertices.end());
- // BBS
- //for (const std::string prop_str : sub_object->geometry.face_properties) {
- // FaceProperty face_prop;
- // face_prop.from_string(prop_str);
- // its.properties.push_back(face_prop);
- //} //Susi_not_impl
- TriangleMesh triangle_mesh(std::move(its), volume_data->mesh_stats);
- // BBS: no need to multiply the instance matrix into the volume
- //if (!m_is_bbl_3mf) {
- // // if the 3mf was not produced by BambuStudio and there is only one instance,
- // // bake the transformation into the geometry to allow the reload from disk command
- // // to work properly
- // if (object.instances.size() == 1) {
- // triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
- // object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
- // //FIXME do the mesh fixing?
- // }
- //}
- if (triangle_mesh.volume() < 0)
- triangle_mesh.flip_triangles();
- volume = object.add_volume(std::move(triangle_mesh));
- if (shared_mesh_id != -1)
- //for some cases the shared mesh is in other plate and not loaded in cli slicing
- //we need to use the first one in the same plate instead
- m_shared_meshes[shared_mesh_id] = volume;
- else
- m_shared_meshes[sub_object->id] = volume;
- }
- else {
- // create volume to use shared mesh
- //volume = object.add_volume_with_shared_mesh(*shared_volume); //orca -> use susi equivalent
- volume = object.add_volume(shared_volume->mesh(), ModelVolumeType::MODEL_PART, false);
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": line %1%, create volume using shared_mesh %2%")%__LINE__%shared_volume;
- }
- // stores the volume matrix taken from the metadata, if present
- if (has_transform)
- volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
- volume->calculate_convex_hull();
- //set transform from 3mf
- Slic3r::Geometry::Transformation comp_transformatino(sub_comp.transform);
- volume->set_transformation(comp_transformatino * volume->get_transformation());
- if (shared_volume) {
- const TriangleMesh& trangle_mesh = volume->mesh();
- Vec3d shift = trangle_mesh.get_init_shift();
- if (!shift.isApprox(Vec3d::Zero()))
- volume->translate(shift);
- }
- // recreate custom supports, seam and mmu segmentation from previously loaded attribute
- {
- volume->supported_facets.reserve(triangles_count);
- volume->seam_facets.reserve(triangles_count);
- volume->mmu_segmentation_facets.reserve(triangles_count);
- for (size_t i=0; i<triangles_count; ++i) {
- assert(i < sub_object->geometry.custom_supports.size());
- assert(i < sub_object->geometry.custom_seam.size());
- assert(i < sub_object->geometry.mmu_segmentation.size());
- if (! sub_object->geometry.custom_supports[i].empty())
- volume->supported_facets.set_triangle_from_string(i, sub_object->geometry.custom_supports[i]);
- if (! sub_object->geometry.custom_seam[i].empty())
- volume->seam_facets.set_triangle_from_string(i, sub_object->geometry.custom_seam[i]);
- if (! sub_object->geometry.mmu_segmentation[i].empty())
- volume->mmu_segmentation_facets.set_triangle_from_string(i, sub_object->geometry.mmu_segmentation[i]);
- }
- volume->supported_facets.shrink_to_fit();
- volume->seam_facets.shrink_to_fit();
- volume->mmu_segmentation_facets.shrink_to_fit();
- volume->mmu_segmentation_facets.touch();
- }
- volume->set_type(volume_data->part_type);
-
- //if (auto &es = volume_data->shape_configuration; es.has_value())
- // volume->emboss_shape = std::move(es);
- //if (auto &tc = volume_data->text_configuration; tc.has_value())
- // volume->text_configuration = std::move(tc); //Susi_not_impl
-
- std::map<std::string, std::string> key_values_to_deserialize;
- // apply the remaining volume's metadata
- for (const Metadata& metadata : volume_data->metadata) {
- if (metadata.key == NAME_KEY)
- volume->name = metadata.value;
- //else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1"))
- // volume->set_type(ModelVolumeType::PARAMETER_MODIFIER);
- //for old format
- else if ((metadata.key == VOLUME_TYPE_KEY) || (metadata.key == PART_TYPE_KEY)) {
- std::string subtype_str = metadata.value;
- if( "normal_part" == subtype_str)
- subtype_str = "ModelPart";
- else if("negative_part" == subtype_str)
- subtype_str = "NegativeVolume";
- else if("modifier_part" == subtype_str)
- subtype_str = "ParameterModifier";
- else if("support_enforcer" == subtype_str)
- subtype_str = "SupportEnforcer";
- else if("support_blocker" == subtype_str)
- subtype_str = "SupportBlocker";
- volume->set_type(ModelVolume::type_from_string(subtype_str));
- } else if (metadata.key == SOURCE_FILE_KEY)
- volume->source.input_file = metadata.value;
- else if (metadata.key == SOURCE_OBJECT_ID_KEY)
- volume->source.object_idx = ::atoi(metadata.value.c_str());
- else if (metadata.key == SOURCE_VOLUME_ID_KEY)
- volume->source.volume_idx = ::atoi(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_X_KEY)
- volume->source.mesh_offset(0) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_Y_KEY)
- volume->source.mesh_offset(1) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_Z_KEY)
- volume->source.mesh_offset(2) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_IN_INCHES)
- volume->source.is_converted_from_inches = metadata.value == "1";
- else if (metadata.key == SOURCE_IN_METERS)
- volume->source.is_converted_from_meters = metadata.value == "1";
- else if ((metadata.key == MATRIX_KEY) || (metadata.key == MESH_SHARED_KEY))
- continue;
- else
- //volume->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
- key_values_to_deserialize[metadata.key] = metadata.value;
- }
- convert_settings_from_bambu(key_values_to_deserialize, config, volume->config, config_substitutions, false);
- // this may happen for 3mf saved by 3rd part softwares
- if (volume->name.empty()) {
- volume->name = object.name;
- if (renamed_volumes_count > 0)
- volume->name += "_" + std::to_string(renamed_volumes_count + 1);
- ++renamed_volumes_count;
- }
- }
- return true;
- }
- /*
- bool _BBS_3MF_Importer::_generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions)
- {
- if (!object.volumes.empty()) {
- add_error("Found invalid volumes count");
- return false;
- }
- unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
- unsigned int renamed_volumes_count = 0;
- for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) {
- if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) {
- add_error("Found invalid triangle id");
- return false;
- }
- Transform3d volume_matrix_to_object = Transform3d::Identity();
- bool has_transform = false;
- // extract the volume transformation from the volume's metadata, if present
- for (const Metadata& metadata : volume_data.metadata) {
- if (metadata.key == MATRIX_KEY) {
- volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
- has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
- break;
- }
- }
- // splits volume out of imported geometry
- indexed_triangle_set its;
- its.indices.assign(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1);
- const size_t triangles_count = its.indices.size();
- if (triangles_count == 0) {
- add_error("An empty triangle mesh found");
- return false;
- }
- {
- int min_id = its.indices.front()[0];
- int max_id = min_id;
- for (const Vec3i& face : its.indices) {
- for (const int tri_id : face) {
- if (tri_id < 0 || tri_id >= int(geometry.vertices.size())) {
- add_error("Found invalid vertex id");
- return false;
- }
- min_id = std::min(min_id, tri_id);
- max_id = std::max(max_id, tri_id);
- }
- }
- its.vertices.assign(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1);
- // BBS
- for (const std::string prop_str : geometry.face_properties) {
- FaceProperty face_prop;
- face_prop.from_string(prop_str);
- its.properties.push_back(face_prop);
- }
- // rebase indices to the current vertices list
- for (Vec3i& face : its.indices)
- for (int& tri_id : face)
- tri_id -= min_id;
- }
- TriangleMesh triangle_mesh(std::move(its), volume_data.mesh_stats);
- if (!m_is_bbl_3mf) {
- // if the 3mf was not produced by OrcaSlicer and there is only one instance,
- // bake the transformation into the geometry to allow the reload from disk command
- // to work properly
- if (object.instances.size() == 1) {
- triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
- object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
- //FIXME do the mesh fixing?
- }
- }
- if (triangle_mesh.volume() < 0)
- triangle_mesh.flip_triangles();
- ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
- // stores the volume matrix taken from the metadata, if present
- if (has_transform)
- volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
- volume->calculate_convex_hull();
- // recreate custom supports, seam and mmu segmentation from previously loaded attribute
- volume->supported_facets.reserve(triangles_count);
- volume->seam_facets.reserve(triangles_count);
- volume->mmu_segmentation_facets.reserve(triangles_count);
- for (size_t i=0; i<triangles_count; ++i) {
- size_t index = volume_data.first_triangle_id + i;
- assert(index < geometry.custom_supports.size());
- assert(index < geometry.custom_seam.size());
- assert(index < geometry.mmu_segmentation.size());
- if (! geometry.custom_supports[index].empty())
- volume->supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
- if (! geometry.custom_seam[index].empty())
- volume->seam_facets.set_triangle_from_string(i, geometry.custom_seam[index]);
- if (! geometry.mmu_segmentation[index].empty())
- volume->mmu_segmentation_facets.set_triangle_from_string(i, geometry.mmu_segmentation[index]);
- }
- volume->supported_facets.shrink_to_fit();
- volume->seam_facets.shrink_to_fit();
- volume->mmu_segmentation_facets.shrink_to_fit();
- volume->set_type(volume_data.part_type);
- // apply the remaining volume's metadata
- for (const Metadata& metadata : volume_data.metadata) {
- if (metadata.key == NAME_KEY)
- volume->name = metadata.value;
- //else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1"))
- // volume->set_type(ModelVolumeType::PARAMETER_MODIFIER);
- //for old format
- else if ((metadata.key == VOLUME_TYPE_KEY) || (metadata.key == PART_TYPE_KEY))
- volume->set_type(ModelVolume::type_from_string(metadata.value));
- else if (metadata.key == SOURCE_FILE_KEY)
- volume->source.input_file = metadata.value;
- else if (metadata.key == SOURCE_OBJECT_ID_KEY)
- volume->source.object_idx = ::atoi(metadata.value.c_str());
- else if (metadata.key == SOURCE_VOLUME_ID_KEY)
- volume->source.volume_idx = ::atoi(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_X_KEY)
- volume->source.mesh_offset(0) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_Y_KEY)
- volume->source.mesh_offset(1) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_OFFSET_Z_KEY)
- volume->source.mesh_offset(2) = ::atof(metadata.value.c_str());
- else if (metadata.key == SOURCE_IN_INCHES)
- volume->source.is_converted_from_inches = metadata.value == "1";
- else if (metadata.key == SOURCE_IN_METERS)
- volume->source.is_converted_from_meters = metadata.value == "1";
- else
- volume->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
- }
- // this may happen for 3mf saved by 3rd part softwares
- if (volume->name.empty()) {
- volume->name = object.name;
- if (renamed_volumes_count > 0)
- volume->name += "_" + std::to_string(renamed_volumes_count + 1);
- ++renamed_volumes_count;
- }
- }
- return true;
- }
- */
- void XMLCALL _BBS_3MF_Importer::_handle_start_model_xml_element(void* userData, const char* name, const char** attributes)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_start_model_xml_element(name, attributes);
- }
- void XMLCALL _BBS_3MF_Importer::_handle_end_model_xml_element(void* userData, const char* name)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_end_model_xml_element(name);
- }
- void XMLCALL _BBS_3MF_Importer::_handle_xml_characters(void* userData, const XML_Char* s, int len)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_xml_characters(s, len);
- }
- void XMLCALL _BBS_3MF_Importer::_handle_start_config_xml_element(void* userData, const char* name, const char** attributes)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_start_config_xml_element(name, attributes);
- }
- void XMLCALL _BBS_3MF_Importer::_handle_end_config_xml_element(void* userData, const char* name)
- {
- _BBS_3MF_Importer* importer = (_BBS_3MF_Importer*)userData;
- if (importer != nullptr)
- importer->_handle_end_config_xml_element(name);
- }
- /* functions of ObjectImporter */
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model(const char** attributes, unsigned int num_attributes)
- {
- object_unit_factor = bbs_get_unit_factor(bbs_get_attribute_value_string(attributes, num_attributes, UNIT_ATTR));
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_resources(const char** attributes, unsigned int num_attributes)
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_resources()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_object(const char** attributes, unsigned int num_attributes)
- {
- // reset current object data
- if (current_object) {
- delete current_object;
- current_object = nullptr;
- }
- std::string object_type = bbs_get_attribute_value_string(attributes, num_attributes, TYPE_ATTR);
- if (bbs_is_valid_object_type(object_type)) {
- if (!current_object) {
- current_object = new CurrentObject();
- }
- current_object->id = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- current_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
- current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
- if (current_object->uuid.empty()) {
- current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
- }
- current_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
- }
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_object()
- {
- if (!current_object || (current_object->id == -1)) {
- top_importer->add_error("Found invalid object for "+ object_path);
- return false;
- }
- else {
- if (is_bbl_3mf && boost::ends_with(current_object->uuid, OBJECT_UUID_SUFFIX) && top_importer->m_load_restore) {
- std::istringstream iss(current_object->uuid);
- int backup_id;
- bool need_replace = false;
- if (iss >> std::hex >> backup_id) {
- need_replace = (current_object->id != backup_id);
- current_object->id = backup_id;
- }
- //if (need_replace)
- {
- for (int index = 0; index < current_object->components.size(); index++)
- {
- int temp_id = (index + 1) << 16 | backup_id;
- Component& component = current_object->components[index];
- std::string new_path = component.object_id.first;
- Id new_id = std::make_pair(new_path, temp_id);
- IdToCurrentObjectMap::iterator object_it = object_list.find(component.object_id);
- if (object_it != object_list.end()) {
- CurrentObject new_object;
- new_object.geometry = std::move(object_it->second.geometry);
- new_object.id = temp_id;
- new_object.model_object_idx = object_it->second.model_object_idx;
- new_object.name = object_it->second.name;
- new_object.uuid = object_it->second.uuid;
- object_list.erase(object_it);
- object_list.insert({ new_id, std::move(new_object) });
- }
- else {
- top_importer->add_error("can not find object for component, id=" + std::to_string(component.object_id.second));
- delete current_object;
- current_object = nullptr;
- return false;
- }
- component.object_id.second = temp_id;
- }
- }
- }
- Id id = std::make_pair(object_path, current_object->id);
- if (object_list.find(id) == object_list.end()) {
- object_list.insert({ id, std::move(*current_object) });
- delete current_object;
- current_object = nullptr;
- }
- else {
- top_importer->add_error("Found object with duplicate id for "+object_path);
- delete current_object;
- current_object = nullptr;
- return false;
- }
- }
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_color_group(const char **attributes, unsigned int num_attributes)
- {
- object_current_color_group = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR);
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_color_group()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_color(const char **attributes, unsigned int num_attributes)
- {
- std::string color = bbs_get_attribute_value_string(attributes, num_attributes, COLOR_ATTR);
- object_group_id_to_color[object_current_color_group] = color;
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_color()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_mesh(const char** attributes, unsigned int num_attributes)
- {
- // reset current geometry
- if (current_object)
- current_object->geometry.reset();
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_mesh()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_vertices(const char** attributes, unsigned int num_attributes)
- {
- // reset current vertices
- if (current_object)
- current_object->geometry.vertices.clear();
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_vertices()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_vertex(const char** attributes, unsigned int num_attributes)
- {
- // appends the vertex coordinates
- // missing values are set equal to ZERO
- if (current_object)
- current_object->geometry.vertices.emplace_back(
- object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR),
- object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR),
- object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR));
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_vertex()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_triangles(const char** attributes, unsigned int num_attributes)
- {
- // reset current triangles
- if (current_object)
- current_object->geometry.triangles.clear();
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_triangles()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_triangle(const char** attributes, unsigned int num_attributes)
- {
- // we are ignoring the following attributes:
- // p1
- // p2
- // p3
- // pid
- // see specifications
- // appends the triangle's vertices indices
- // missing values are set equal to ZERO
- if (current_object) {
- current_object->geometry.triangles.emplace_back(
- bbs_get_attribute_value_int(attributes, num_attributes, V1_ATTR),
- bbs_get_attribute_value_int(attributes, num_attributes, V2_ATTR),
- bbs_get_attribute_value_int(attributes, num_attributes, V3_ATTR));
- current_object->geometry.custom_supports.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
- current_object->geometry.custom_seam.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
- current_object->geometry.mmu_segmentation.push_back(bbs_get_attribute_value_string(attributes, num_attributes, MMU_SEGMENTATION_ATTR));
- // BBS
- current_object->geometry.face_properties.push_back(bbs_get_attribute_value_string(attributes, num_attributes, FACE_PROPERTY_ATTR));
- }
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_triangle()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_components(const char** attributes, unsigned int num_attributes)
- {
- // reset current components
- if (current_object)
- current_object->components.clear();
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_components()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_component(const char** attributes, unsigned int num_attributes)
- {
- int object_id = bbs_get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
- Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
- /*Id id = std::make_pair(m_sub_model_path, object_id);
- IdToModelObjectMap::iterator object_item = m_objects.find(id);
- if (object_item == m_objects.end()) {
- IdToAliasesMap::iterator alias_item = m_objects_aliases.find(id);
- if (alias_item == m_objects_aliases.end()) {
- add_error("Found component with invalid object id");
- return false;
- }
- }*/
- if (current_object) {
- Id id = std::make_pair(object_path, object_id);
- current_object->components.emplace_back(id, transform);
- }
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_component()
- {
- // do nothing
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_metadata(const char** attributes, unsigned int num_attributes)
- {
- obj_curr_metadata_name.clear();
- std::string name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
- if (!name.empty()) {
- obj_curr_metadata_name = name;
- }
- return true;
- }
- bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_metadata()
- {
- if ((obj_curr_metadata_name == BBS_3MF_VERSION)||(obj_curr_metadata_name == BBS_3MF_VERSION1)) {
- is_bbl_3mf = true;
- }
- return true;
- }
- void _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element(const char* name, const char** attributes)
- {
- if (object_xml_parser == nullptr)
- return;
- bool res = true;
- unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(object_xml_parser);
- if (::strcmp(MODEL_TAG, name) == 0)
- res = _handle_object_start_model(attributes, num_attributes);
- else if (::strcmp(RESOURCES_TAG, name) == 0)
- res = _handle_object_start_resources(attributes, num_attributes);
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_object_start_object(attributes, num_attributes);
- else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
- res = _handle_object_start_color_group(attributes, num_attributes);
- else if (::strcmp(COLOR_TAG, name) == 0)
- res = _handle_object_start_color(attributes, num_attributes);
- else if (::strcmp(MESH_TAG, name) == 0)
- res = _handle_object_start_mesh(attributes, num_attributes);
- else if (::strcmp(VERTICES_TAG, name) == 0)
- res = _handle_object_start_vertices(attributes, num_attributes);
- else if (::strcmp(VERTEX_TAG, name) == 0)
- res = _handle_object_start_vertex(attributes, num_attributes);
- else if (::strcmp(TRIANGLES_TAG, name) == 0)
- res = _handle_object_start_triangles(attributes, num_attributes);
- else if (::strcmp(TRIANGLE_TAG, name) == 0)
- res = _handle_object_start_triangle(attributes, num_attributes);
- else if (::strcmp(COMPONENTS_TAG, name) == 0)
- res = _handle_object_start_components(attributes, num_attributes);
- else if (::strcmp(COMPONENT_TAG, name) == 0)
- res = _handle_object_start_component(attributes, num_attributes);
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_object_start_metadata(attributes, num_attributes);
- if (!res)
- _stop_object_xml_parser();
- }
- void _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element(const char* name)
- {
- if (object_xml_parser == nullptr)
- return;
- bool res = true;
- if (::strcmp(MODEL_TAG, name) == 0)
- res = _handle_object_end_model();
- else if (::strcmp(RESOURCES_TAG, name) == 0)
- res = _handle_object_end_resources();
- else if (::strcmp(OBJECT_TAG, name) == 0)
- res = _handle_object_end_object();
- else if (::strcmp(COLOR_GROUP_TAG, name) == 0)
- res = _handle_object_end_color_group();
- else if (::strcmp(COLOR_TAG, name) == 0)
- res = _handle_object_end_color();
- else if (::strcmp(MESH_TAG, name) == 0)
- res = _handle_object_end_mesh();
- else if (::strcmp(VERTICES_TAG, name) == 0)
- res = _handle_object_end_vertices();
- else if (::strcmp(VERTEX_TAG, name) == 0)
- res = _handle_object_end_vertex();
- else if (::strcmp(TRIANGLES_TAG, name) == 0)
- res = _handle_object_end_triangles();
- else if (::strcmp(TRIANGLE_TAG, name) == 0)
- res = _handle_object_end_triangle();
- else if (::strcmp(COMPONENTS_TAG, name) == 0)
- res = _handle_object_end_components();
- else if (::strcmp(COMPONENT_TAG, name) == 0)
- res = _handle_object_end_component();
- else if (::strcmp(METADATA_TAG, name) == 0)
- res = _handle_object_end_metadata();
- if (!res)
- _stop_object_xml_parser();
- }
- void _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters(const XML_Char* s, int len)
- {
- obj_curr_characters.append(s, len);
- }
- void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element(void* userData, const char* name, const char** attributes)
- {
- ObjectImporter* importer = (ObjectImporter*)userData;
- if (importer != nullptr)
- importer->_handle_object_start_model_xml_element(name, attributes);
- }
- void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element(void* userData, const char* name)
- {
- ObjectImporter* importer = (ObjectImporter*)userData;
- if (importer != nullptr)
- importer->_handle_object_end_model_xml_element(name);
- }
- void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters(void* userData, const XML_Char* s, int len)
- {
- ObjectImporter* importer = (ObjectImporter*)userData;
- if (importer != nullptr)
- importer->_handle_object_xml_characters(s, len);
- }
- bool _BBS_3MF_Importer::ObjectImporter::_extract_object_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
- {
- if (stat.m_uncomp_size == 0) {
- top_importer->add_error("Found invalid size for "+object_path);
- return false;
- }
- object_xml_parser = XML_ParserCreate(nullptr);
- if (object_xml_parser == nullptr) {
- top_importer->add_error("Unable to create parser for "+object_path);
- return false;
- }
- XML_SetUserData(object_xml_parser, (void*)this);
- XML_SetElementHandler(object_xml_parser, _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element, _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element);
- XML_SetCharacterDataHandler(object_xml_parser, _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters);
- struct CallbackData
- {
- XML_Parser& parser;
- _BBS_3MF_Importer::ObjectImporter& importer;
- const mz_zip_archive_file_stat& stat;
- CallbackData(XML_Parser& parser, _BBS_3MF_Importer::ObjectImporter& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {}
- };
- CallbackData data(object_xml_parser, *this, stat);
- mz_bool res = 0;
- try
- {
- mz_file_write_func callback = [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
- CallbackData* data = (CallbackData*)pOpaque;
- if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.object_parse_error()) {
- char error_buf[1024];
- ::snprintf(error_buf, 1024, "Error (%s) while parsing '%s' at line %d", data->importer.object_parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
- throw Slic3r::FileIOError(error_buf);
- }
- return n;
- };
- void* opaque = &data;
- res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, callback, opaque, 0);
- }
- catch (const version_error& e)
- {
- // rethrow the exception
- std::string error_message = std::string(e.what()) + " for " + object_path;
- throw Slic3r::FileIOError(error_message);
- }
- catch (std::exception& e)
- {
- std::string error_message = std::string(e.what()) + " for " + object_path;
- top_importer->add_error(error_message);
- return false;
- }
- if (res == 0) {
- top_importer->add_error("Error while extracting model data from zip archive for "+object_path);
- return false;
- }
- return true;
- }
- //////////////////////////////////////////////////// EXPORTER /////////////////////////////////////////////////////
- //
- // class _BBS_3MF_Exporter : public _BBS_3MF_Base
- // {
- // struct BuildItem
- // {
- // std::string path;
- // unsigned int id;
- // Transform3d transform;
- // bool printable;
- //
- // BuildItem(std::string const & path, unsigned int id, const Transform3d& transform, const bool printable)
- // : path(path)
- // , id(id)
- // , transform(transform)
- // , printable(printable)
- // {
- // }
- // };
- //
- // //BBS: change volume to seperate objects
- // /*struct Offsets
- // {
- // unsigned int first_vertex_id;
- // unsigned int first_triangle_id;
- // unsigned int last_triangle_id;
- //
- // Offsets(unsigned int first_vertex_id)
- // : first_vertex_id(first_vertex_id)
- // , first_triangle_id(-1)
- // , last_triangle_id(-1)
- // {
- // }
- // };*/
- //
- // //typedef std::map<const ModelVolume*, Offsets> VolumeToOffsetsMap;
- // typedef std::map<const ModelVolume*, int> VolumeToObjectIDMap;
- //
- // struct ObjectData
- // {
- // ModelObject const * object;
- // int backup_id;
- // int object_id = 0;
- // std::string sub_path;
- // bool share_mesh = false;
- // VolumeToObjectIDMap volumes_objectID;
- // };
- //
- // typedef std::vector<BuildItem> BuildItemsList;
- // typedef std::map<ModelObject const *, ObjectData> ObjectToObjectDataMap;
- //
- // bool m_fullpath_sources{ true };
- // bool m_zip64 { true };
- // bool m_production_ext { false }; // save with Production Extention
- // bool m_skip_static{ false }; // not save mesh and other big static contents
- // bool m_from_backup_save{ false }; // the object save is from backup store
- // bool m_split_model { false }; // save object per file with Production Extention
- // bool m_save_gcode { false }; // whether to save gcode for normal save
- // bool m_skip_model { false }; // skip model when exporting .gcode.3mf
- // bool m_skip_auxiliary { false }; // skip normal axuiliary files
- // bool m_use_loaded_id { false }; // whether to use loaded id for identify_id
- // bool m_share_mesh { false }; // whether to share mesh between objects
- // std::string m_thumbnail_middle = PRINTER_THUMBNAIL_MIDDLE_FILE;
- // std::string m_thumbnail_small = PRINTER_THUMBNAIL_SMALL_FILE;
- // std::map<void const *, std::pair<ObjectData*, ModelVolume const *>> m_shared_meshes;
- // std::map<ModelVolume const *, std::pair<std::string, int>> m_volume_paths;
- // public:
- // //BBS: add plate data related logic
- //
- // // add backup logic
- // //bool save_model_to_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, const DynamicPrintConfig* config, bool fullpath_sources, const std::vector<ThumbnailData*>& thumbnail_data, bool zip64, bool skip_static, Export3mfProgressFn proFn = nullptr, bool silence = false);
- //
- // bool save_model_to_file(StoreParams& store_params);
- // // add backup logic
- // bool save_object_mesh(const std::string& temp_path, ModelObject const & object, int obj_id);
- // static void add_transformation(std::stringstream &stream, const Transform3d &tr);
- //
- // private:
- // //BBS: add plate data related logic
- // bool _save_model_to_file(const std::string& filename,
- // Model& model, PlateDataPtrs& plate_data_list,
- // std::vector<Preset*>& project_presets,
- // const DynamicPrintConfig* config,
- // const std::vector<ThumbnailData*>& thumbnail_data,
- // const std::vector<ThumbnailData*>& top_thumbnail_data,
- // const std::vector<ThumbnailData*>& pick_thumbnail_data,
- // Export3mfProgressFn proFn,
- // const std::vector<ThumbnailData*>& calibration_data,
- // //const std::vector<PlateBBoxData*>& id_bboxes, //Susi_not_impl
- // //BBLProject* project = nullptr, //Susi_not_impl
- // int export_plate_idx = -1);
- //
- // bool _add_file_to_archive(mz_zip_archive& archive, const std::string & path_in_zip, const std::string & file_path);
- //
- // bool _add_content_types_file_to_archive(mz_zip_archive& archive);
- //
- // bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index, bool generate_small_thumbnail = false);
- // bool _add_calibration_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index);
- // bool _add_bbox_file_to_archive(mz_zip_archive& archive, /*const PlateBBoxData& id_bboxes,*/ int index);
- // bool _add_relationships_file_to_archive(mz_zip_archive & archive,
- // std::string const & from = {},
- // std::vector<std::string> const &targets = {},
- // std::vector<std::string> const &types = {},
- // PackingTemporaryData data = PackingTemporaryData(),
- // int export_plate_idx = -1) const;
- // bool _add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, ObjectToObjectDataMap& objects_data, Export3mfProgressFn proFn = nullptr, /*BBLProject* project = nullptr*/) const;
- // bool _add_object_to_model_stream(mz_zip_writer_staged_context &context, ObjectData const &object_data) const;
- // void _add_object_components_to_stream(std::stringstream &stream, ObjectData const &object_data) const;
- // //BBS: change volume to seperate objects
- // bool _add_mesh_to_object_stream(std::function<bool(std::string &, bool)> const &flush, ObjectData const &object_data) const;
- // bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const;
- // bool _add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model);
- // bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
- // bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
- // bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
- // bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
- // bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
- // //BBS: add project config file logic for json format
- // bool _add_project_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, Model& model);
- // //BBS: add project embedded preset files
- // bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector<Preset*> project_presets);
- // bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false);
- // bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config);
- // bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr);
- // bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
- // bool _add_auxiliary_dir_to_archive(mz_zip_archive &archive, const std::string &aux_dir, PackingTemporaryData &data);
- //
- // static int convert_instance_id_to_resource_id(const Model& model, int obj_id, int instance_id)
- // {
- // int resource_id = 1;
- //
- // for (int i = 0; i < obj_id; ++i)
- // {
- // resource_id += model.objects[i]->volumes.size() + 1;
- // }
- //
- // resource_id += model.objects[obj_id]->volumes.size();
- //
- // return resource_id;
- // }
- // };
- //
- // bool _BBS_3MF_Exporter::save_model_to_file(StoreParams& store_params)
- // {
- // clear_errors();
- // m_fullpath_sources = store_params.strategy & SaveStrategy::FullPathSources;
- // m_zip64 = store_params.strategy & SaveStrategy::Zip64;
- // m_production_ext = store_params.strategy & SaveStrategy::ProductionExt;
- //
- // m_skip_static = store_params.strategy & SaveStrategy::SkipStatic;
- // m_split_model = store_params.strategy & SaveStrategy::SplitModel;
- // m_save_gcode = store_params.strategy & SaveStrategy::WithGcode;
- // m_skip_model = store_params.strategy & SaveStrategy::SkipModel;
- // m_skip_auxiliary = store_params.strategy & SaveStrategy::SkipAuxiliary;
- // m_share_mesh = store_params.strategy & SaveStrategy::ShareMesh;
- // m_from_backup_save = store_params.strategy & SaveStrategy::Backup;
- //
- // m_use_loaded_id = store_params.strategy & SaveStrategy::UseLoadedId;
- //
- // //if (auto info = store_params.model->model_info) {
- // // if (auto iter = info->metadata_items.find("Thumbnail_Small"); iter != info->metadata_items.end())
- // // m_thumbnail_small = iter->second;
- // // if (auto iter = info->metadata_items.find("Thumbnail_Middle"); iter != info->metadata_items.end())
- // // m_thumbnail_middle = iter->second;
- // //} //Susi_not_impl
- // boost::system::error_code ec;
- // std::string filename = std::string(store_params.path);
- // boost::filesystem::remove(filename + ".tmp", ec);
- //
- // bool result = _save_model_to_file(filename + ".tmp", *store_params.model, store_params.plate_data_list, store_params.project_presets, store_params.config,
- // store_params.thumbnail_data, store_params.top_thumbnail_data, store_params.pick_thumbnail_data, store_params.proFn,
- // store_params.calibration_thumbnail_data, /*store_params.id_bboxes, store_params.project, */store_params.export_plate_idx);
- // if (result) {
- // boost::filesystem::rename(filename + ".tmp", filename, ec);
- // if (ec) {
- // add_error("Failed to rename file: " + ec.message());
- // boost::filesystem::remove(filename + ".tmp", ec);
- // return false;
- // }
- // if (!(store_params.strategy & SaveStrategy::Silence))
- // //save_string_file(store_params.model->get_backup_path() + "/origin.txt", filename);
- // save_string_file(get_temp_file(*store_params.model) / "origin.txt", filename);
- // }
- // return result;
- // }
- //
- // // backup mesh-only
- // bool _BBS_3MF_Exporter::save_object_mesh(const std::string& temp_path, ModelObject const & object, int obj_id)
- // {
- // m_production_ext = true;
- // m_from_backup_save = true;
- // Model const & model = *object.get_model();
- //
- // mz_zip_archive archive;
- // mz_zip_zero_struct(&archive);
- //
- // auto filename = boost::format("3D/Objects/%s_%d.model") % object.name % obj_id;
- // std::string filepath = temp_path + "/" + filename.str();
- // std::string filepath_tmp = filepath + ".tmp";
- // boost::system::error_code ec;
- // boost::filesystem::remove(filepath_tmp, ec);
- // if (!open_zip_writer(&archive, filepath_tmp)) {
- // add_error("Unable to open the file"+filepath_tmp);
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to open the file\n");
- // return false;
- // }
- //
- // struct close_lock
- // {
- // mz_zip_archive & archive;
- // std::string const * filename;
- // void close() {
- // close_zip_writer(&archive);
- // filename = nullptr;
- // }
- // ~close_lock() {
- // if (filename) {
- // close_zip_writer(&archive);
- // boost::system::error_code ec;
- // boost::filesystem::remove(*filename, ec);
- // }
- // }
- // } lock{archive, &filepath_tmp};
- //
- // ObjectToObjectDataMap objects_data;
- // auto & volumes_objectID = objects_data.insert({&object, {&object, obj_id}}).first->second.volumes_objectID;
- // unsigned int volume_count = 0;
- // for (ModelVolume *volume : object.volumes) {
- // if (volume == nullptr) continue;
- // volumes_objectID.insert({volume, (++volume_count << 16 | obj_id)});
- // }
- //
- // _add_model_file_to_archive(filename.str(), archive, model, objects_data);
- //
- // mz_zip_writer_finalize_archive(&archive);
- // lock.close();
- // boost::filesystem::rename(filepath_tmp, filepath, ec);
- // return true;
- // }
- //
- // //BBS: add plate data related logic
- // bool _BBS_3MF_Exporter::_save_model_to_file(const std::string& filename,
- // Model& model,
- // PlateDataPtrs& plate_data_list,
- // std::vector<Preset*>& project_presets,
- // const DynamicPrintConfig* config,
- // const std::vector<ThumbnailData*>& thumbnail_data,
- // const std::vector<ThumbnailData*>& top_thumbnail_data,
- // const std::vector<ThumbnailData*>& pick_thumbnail_data,
- // Export3mfProgressFn proFn,
- // const std::vector<ThumbnailData*>& calibration_data,
- // //const std::vector<PlateBBoxData*>& id_bboxes, //Susi_not_impl
- // //BBLProject* project, //Susi_not_impl
- // int export_plate_idx)
- // {
- // PackingTemporaryData temp_data;
- //
- // mz_zip_archive archive;
- // mz_zip_zero_struct(&archive);
- //
- // bool cb_cancel = false;
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ <<
- // boost::format(",before open zip writer, m_skip_static %1%, m_save_gcode %2%, m_use_loaded_id %3%")%m_skip_static %m_save_gcode %m_use_loaded_id;
- // if (proFn) {
- // proFn(EXPORT_STAGE_OPEN_3MF, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // if (!open_zip_writer(&archive, filename)) {
- // add_error("Unable to open the file"+filename);
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to open the file\n");
- // return false;
- // }
- //
- // struct close_lock
- // {
- // mz_zip_archive & archive;
- // std::string const * filename;
- // ~close_lock() {
- // close_zip_writer(&archive);
- // if (filename) {
- // boost::system::error_code ec;
- // boost::filesystem::remove(*filename, ec);
- // }
- // }
- // } lock{ archive, &filename};
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add _add_content_types_file_to_archive\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_CONTENT_TYPES, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // // Adds content types file ("[Content_Types].xml";).
- // // The content of this file is the same for each OrcaSlicer 3mf.
- // if (!_add_content_types_file_to_archive(archive)) {
- // return false;
- // }
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(",before add thumbnails, count %1%") % thumbnail_data.size();
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",top&&pick thumbnails, count %1%")%top_thumbnail_data.size();
- //
- // //BBS: add thumbnail for each plate
- // if (!m_skip_static) {
- // std::vector<bool> thumbnail_status(plate_data_list.size(), false);
- // std::vector<bool> top_thumbnail_status(plate_data_list.size(), false);
- // std::vector<bool> pick_thumbnail_status(plate_data_list.size(), false);
- //
- // if ((thumbnail_data.size() > 0)&&(thumbnail_data.size() > plate_data_list.size())) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", thumbnail_data size %1% > plate count %2%")
- // % thumbnail_data.size() %plate_data_list.size();
- // return false;
- // }
- // if ((top_thumbnail_data.size() > 0)&&(top_thumbnail_data.size() > plate_data_list.size())) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_data size %1% > plate count %2%")
- // % top_thumbnail_data.size() %plate_data_list.size();
- // return false;
- // }
- // if ((pick_thumbnail_data.size() > 0)&&(pick_thumbnail_data.size() > plate_data_list.size())) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", pick_thumbnail_data size %1% > plate count %2%")
- // % pick_thumbnail_data.size() %plate_data_list.size();
- // return false;
- // }
- // if (top_thumbnail_data.size() != pick_thumbnail_data.size()) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_data size %1% != pick_thumbnail_data size %2%")
- // % top_thumbnail_data.size() %pick_thumbnail_data.size();
- // return false;
- // }
- //
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_THUMBNAILS, 0, plate_data_list.size(), cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // for (unsigned int index = 0; index < thumbnail_data.size(); index++)
- // {
- // if (thumbnail_data[index]->is_valid())
- // {
- // if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data[index], "Metadata/plate", index, true)) {
- // return false;
- // }
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add thumbnail %1%'s data into 3mf")%(index+1);
- // thumbnail_status[index] = true;
- // }
- // }
- //
- // // Adds the file Metadata/top_i.png and Metadata/pick_i.png
- // for (unsigned int index = 0; index < top_thumbnail_data.size(); index++)
- // {
- // if (top_thumbnail_data[index]->is_valid())
- // {
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add top thumbnail %1%'s data into 3mf")%(index+1);
- // if (!_add_thumbnail_file_to_archive(archive, *top_thumbnail_data[index], "Metadata/top", index)) {
- // return false;
- // }
- // top_thumbnail_status[index] = true;
- // }
- //
- // if (pick_thumbnail_data[index]->is_valid())
- // {
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add pick thumbnail %1%'s data into 3mf")%(index+1);
- // if (!_add_thumbnail_file_to_archive(archive, *pick_thumbnail_data[index], "Metadata/pick", index)) {
- // return false;
- // }
- // pick_thumbnail_status[index] = true;
- // }
- // }
- //
- // for (int i = 0; i < plate_data_list.size(); i++) {
- // PlateData *plate_data = plate_data_list[i];
- //
- // if (!thumbnail_status[i] && !plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){
- // std::string dst_in_3mf = (boost::format("Metadata/plate_%1%.png") % (i + 1)).str();
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add thumbnail %1% from file %2%") % (i+1) %plate_data->thumbnail_file;
- //
- // if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->thumbnail_file)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add thumbnail %1% from file %2% failed\n") % (i+1) %plate_data->thumbnail_file;
- // return false;
- // }
- // }
- //
- // if (!top_thumbnail_status[i] && !plate_data->top_file.empty() && (boost::filesystem::exists(plate_data->top_file))){
- // std::string dst_in_3mf = (boost::format("Metadata/top_%1%.png") % (i + 1)).str();
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add top thumbnail %1% from file %2%") % (i+1) %plate_data->top_file;
- // if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->top_file)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add top thumbnail %1% failed") % (i+1);
- // return false;
- // }
- // top_thumbnail_status[i] = true;
- // }
- //
- // if (!pick_thumbnail_status[i] && !plate_data->pick_file.empty() && (boost::filesystem::exists(plate_data->pick_file))){
- // std::string dst_in_3mf = (boost::format("Metadata/pick_%1%.png") % (i + 1)).str();
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add pick thumbnail %1% from file %2%") % (i+1) %plate_data->pick_file;
- // if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->pick_file)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add pick thumbnail %1% failed") % (i+1);
- // return false;
- // }
- // pick_thumbnail_status[i] = true;
- // }
- // }
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_THUMBNAILS, plate_data_list.size(), plate_data_list.size(), cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- // }
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before add calibration thumbnails, count %1%\n")%calibration_data.size();
- // //BBS add calibration thumbnail for each plate
- // if (!m_skip_static && calibration_data.size() > 0) {
- // // Adds the file Metadata/calibration_p[X].png.
- // for (unsigned int index = 0; index < calibration_data.size(); index++)
- // {
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_THUMBNAILS, index, calibration_data.size(), cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // if (calibration_data[index]->is_valid())
- // {
- // if (!_add_calibration_file_to_archive(archive, *calibration_data[index], index)) {
- // close_zip_writer(&archive);
- // return false;
- // }
- // }
- // }
- // }
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before add calibration boundingbox, count %1%\n")%id_bboxes.size();
- // //if (!m_skip_static && id_bboxes.size() > 0) {
- // // // Adds the file Metadata/calibration_p[X].png.
- // // for (unsigned int index = 0; index < id_bboxes.size(); index++)
- // // {
- // // // BBS: save bounding box to json
- // // if (id_bboxes[index]->is_valid()) {
- // // if (!_add_bbox_file_to_archive(archive, *id_bboxes[index], index)) {
- // // close_zip_writer(&archive);
- // // return false;
- // // }
- // // }
- // // }
- // //} //s
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add models\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_MODELS, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // // Adds model file ("3D/3dmodel.model").
- // // This is the one and only file that contains all the geometry (vertices and triangles) of all ModelVolumes.
- // ObjectToObjectDataMap objects_data;
- // //if (!m_skip_model)
- // {
- // if (!_add_model_file_to_archive(filename, archive, model, objects_data, proFn, project)) { return false; }
- //
- // // Adds layer height profile file ("Metadata/Slic3r_PE_layer_heights_profile.txt").
- // // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
- // // The index differes from the index of an object ID of an object instance of a 3MF file!
- // if (!_add_layer_height_profile_file_to_archive(archive, model)) {
- // close_zip_writer(&archive);
- // return false;
- // }
- //
- // // BBS progress point
- // /*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_LAYER_RANGE\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_LAYER_RANGE, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }*/
- //
- // // Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt").
- // // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
- // // The index differes from the index of an object ID of an object instance of a 3MF file!
- // if (!_add_layer_config_ranges_file_to_archive(archive, model)) {
- // close_zip_writer(&archive);
- // return false;
- // }
- //
- // // BBS progress point
- // /*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_SUPPORT\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_SUPPORT, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // // Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
- // // All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
- // // The index differes from the index of an object ID of an object instance of a 3MF file!
- // if (!_add_sla_support_points_file_to_archive(archive, model)) {
- // return false;
- // }
- //
- // if (!_add_sla_drain_holes_file_to_archive(archive, model)) {
- // return false;
- // }*/
- //
- // // BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", before add custom gcodes\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_CUSTOM_GCODE, 0, 1, cb_cancel);
- // if (cb_cancel) return false;
- // }
- //
- // // Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml").
- // // All custom gcode per height of whole Model are stored here
- // if (!_add_custom_gcode_per_print_z_file_to_archive(archive, model, config)) { return false; }
- //
- // // BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", before add project_settings\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_PRINT_CONFIG, 0, 1, cb_cancel);
- // if (cb_cancel) return false;
- // }
- //
- // // Adds slic3r print config file ("Metadata/Slic3r_PE.config").
- // // This file contains the content of FullPrintConfing / SLAFullPrintConfig.
- // if (config != nullptr) {
- // // BBS: change to json format
- // // if (!_add_print_config_file_to_archive(archive, *config)) {
- // if (!_add_project_config_file_to_archive(archive, *config, model)) { return false; }
- // }
- //
- // // BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", before add project embedded settings\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_CONFIG_FILE, 0, 1, cb_cancel);
- // if (cb_cancel) return false;
- // }
- //
- // // BBS: add project config
- // if (project_presets.size() > 0) {
- // // BBS: add project embedded preset files
- // _add_project_embedded_presets_to_archive(archive, model, project_presets);
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", finished add project embedded settings, size %1%\n")%project_presets.size();
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_PROJECT_CONFIG, 0, 1, cb_cancel);
- // if (cb_cancel) return false;
- // }
- // }
- // }
- //
- // // add plate_N.gcode.md5 to file
- // if (!m_skip_static && m_save_gcode) {
- // for (int i = 0; i < plate_data_list.size(); i++) {
- // PlateData *plate_data = plate_data_list[i];
- // if (!plate_data->gcode_file.empty() && plate_data->is_sliced_valid && boost::filesystem::exists(plate_data->gcode_file)) {
- // unsigned char digest[16];
- // MD5_CTX ctx;
- // MD5_Init(&ctx);
- // auto src_gcode_file = plate_data->gcode_file;
- // boost::filesystem::ifstream ifs(src_gcode_file, std::ios::binary);
- // std::string buf(64 * 1024, 0);
- // const std::size_t & size = boost::filesystem::file_size(src_gcode_file);
- // std::size_t left_size = size;
- // while (ifs) {
- // ifs.read(buf.data(), buf.size());
- // int read_bytes = ifs.gcount();
- // MD5_Update(&ctx, (unsigned char *) buf.data(), read_bytes);
- // }
- // MD5_Final(digest, &ctx);
- // char md5_str[33];
- // for (int j = 0; j < 16; j++) { sprintf(&md5_str[j * 2], "%02X", (unsigned int) digest[j]); }
- // plate_data->gcode_file_md5 = std::string(md5_str);
- // std::string target_file = (boost::format("Metadata/plate_%1%.gcode.md5") % (plate_data->plate_index + 1)).str();
- // if (!mz_zip_writer_add_mem(&archive, target_file.c_str(), (const void *) plate_data->gcode_file_md5.c_str(), plate_data->gcode_file_md5.length(),
- // MZ_DEFAULT_COMPRESSION)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__
- // << boost::format(", store gcode md5 to 3mf's %1%, length %2%, failed\n") %target_file %plate_data->gcode_file_md5.length();
- // return false;
- // }
- // }
- // }
- // }
- //
- // // Adds gcode files ("Metadata/plate_1.gcode, plate_2.gcode, ...)
- // // Before _add_model_config_file_to_archive, because we modify plate_data
- // //if (!m_skip_static && !_add_gcode_file_to_archive(archive, model, plate_data_list, proFn)) {
- // if (!m_skip_static && m_save_gcode && !_add_gcode_file_to_archive(archive, model, plate_data_list, proFn)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_gcode_file_to_archive failed\n");
- // return false;
- // }
- //
- // // Adds slic3r model config file ("Metadata/Slic3r_PE_model.config").
- // // This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides).
- // // As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data
- // // is stored here as well.
- // if (!_add_model_config_file_to_archive(archive, model, plate_data_list, objects_data, export_plate_idx, m_save_gcode, m_use_loaded_id)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_model_config_file_to_archive failed\n");
- // return false;
- // }
- //
- // if (!_add_cut_information_file_to_archive(archive, model)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_cut_information_file_to_archive failed\n");
- // return false;
- // }
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add sliced info to 3mf\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_SLICE_INFO, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // // Adds sliced info of plate file ("Metadata/slice_info.config")
- // // This file contains all sliced info of all plates
- // if (!_add_slice_info_config_file_to_archive(archive, model, plate_data_list, objects_data, *config)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_slice_info_config_file_to_archive failed\n");
- // return false;
- // }
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add auxiliary dir to 3mf\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_AUXILIARIES, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // if (!m_skip_static && !_add_auxiliary_dir_to_archive(archive, model.get_auxiliary_file_temp_path(), temp_data)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", _add_auxiliary_dir_to_archive failed\n");
- // return false;
- // }
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", before add relation file to 3mf\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_RELATIONS, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // // Adds relationships file ("_rels/.rels").
- // // The content of this file is the same for each OrcaSlicer 3mf.
- // // The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA.
- // if (!_add_relationships_file_to_archive(archive, {}, {}, {}, temp_data, export_plate_idx)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", _add_relationships_file_to_archive failed\n");
- // return false;
- // }
- //
- // if (!mz_zip_writer_finalize_archive(&archive)) {
- // add_error("Unable to finalize the archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to finalize the archive\n");
- // return false;
- // }
- //
- // //BBS progress point
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", finished exporting 3mf\n");
- // if (proFn) {
- // proFn(EXPORT_STAGE_FINISH, 0, 1, cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // lock.filename = nullptr;
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_file_to_archive(mz_zip_archive& archive, const std::string& path_in_zip, const std::string& src_file_path)
- // {
- // static std::string const nocomp_exts[] = {".png", ".jpg", ".mp4", ".jpeg", ".zip", ".3mf"};
- // auto end = nocomp_exts + sizeof(nocomp_exts) / sizeof(nocomp_exts[0]);
- // bool nocomp = std::find_if(nocomp_exts, end, [&path_in_zip](auto & ext) { return boost::algorithm::ends_with(path_in_zip, ext); }) != end;
- //#if WRITE_ZIP_LANGUAGE_ENCODING
- // bool result = mz_zip_writer_add_file(&archive, path_in_zip.c_str(), encode_path(src_file_path.c_str()).c_str(), NULL, 0, nocomp ? MZ_NO_COMPRESSION : MZ_DEFAULT_LEVEL);
- //#else
- // std::string native_path = encode_path(path_in_zip.c_str());
- // std::string extra = ZipUnicodePathExtraField::encode(path_in_zip, native_path);
- // bool result = mz_zip_writer_add_file_ex(&archive, native_path.c_str(), encode_path(src_file_path.c_str()).c_str(), NULL, 0, nocomp ? MZ_ZIP_FLAG_ASCII_FILENAME : MZ_DEFAULT_COMPRESSION,
- // extra.c_str(), extra.length(), extra.c_str(), extra.length());
- //#endif
- // if (!result) {
- // add_error("Unable to add file " + src_file_path + " to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", Unable to add file %1% to archive %2%\n") % src_file_path % path_in_zip;
- // } else {
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add file %1% to archive %2%\n") % src_file_path % path_in_zip;
- // }
- // return result;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_content_types_file_to_archive(mz_zip_archive& archive)
- // {
- // std::stringstream stream;
- // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- // stream << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n";
- // stream << " <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n";
- // stream << " <Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\"/>\n";
- // stream << " <Default Extension=\"png\" ContentType=\"image/png\"/>\n";
- // stream << " <Default Extension=\"gcode\" ContentType=\"text/x.gcode\"/>\n";
- // stream << "</Types>";
- //
- // std::string out = stream.str();
- //
- // if (!mz_zip_writer_add_mem(&archive, CONTENT_TYPES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add content types file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add content types file to archive\n");
- // return false;
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index, bool generate_small_thumbnail)
- // {
- // bool res = false;
- //
- // size_t png_size = 0;
- // void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_COMPRESSION, 1);
- // if (png_data != nullptr) {
- // std::string thumbnail_name = (boost::format("%1%_%2%.png")%local_path % (index + 1)).str();
- // res = mz_zip_writer_add_mem(&archive, thumbnail_name.c_str(), (const void*)png_data, png_size, MZ_NO_COMPRESSION);
- // mz_free(png_data);
- // }
- //
- // if (!res) {
- // add_error("Unable to add thumbnail file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add thumbnail file to archive\n");
- // }
- //
- // if (generate_small_thumbnail && thumbnail_data.is_valid()) {
- // //generate small size of thumbnail
- // std::vector<unsigned char> small_pixels;
- // small_pixels.resize(PLATE_THUMBNAIL_SMALL_WIDTH * PLATE_THUMBNAIL_SMALL_HEIGHT * 4);
- // /* step width and step height */
- // int sw = thumbnail_data.width / PLATE_THUMBNAIL_SMALL_WIDTH;
- // int sh = thumbnail_data.height / PLATE_THUMBNAIL_SMALL_HEIGHT;
- // int clampped_width = sw * PLATE_THUMBNAIL_SMALL_WIDTH;
- // int clampped_height = sh * PLATE_THUMBNAIL_SMALL_HEIGHT;
- //
- // for (int i = 0; i < clampped_height; i += sh) {
- // for (int j = 0; j < clampped_width; j += sw) {
- // int r = 0, g = 0, b = 0, a = 0;
- // for (int m = 0; m < sh; m++) {
- // for (int n = 0; n < sw; n++) {
- // r += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 0];
- // g += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 1];
- // b += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 2];
- // a += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 3];
- // }
- // }
- // r = std::clamp(0, r / sw / sh, 255);
- // g = std::clamp(0, g / sw / sh, 255);
- // b = std::clamp(0, b / sw / sh, 255);
- // a = std::clamp(0, a / sw / sh, 255);
- // small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 0] = (unsigned char)r;
- // small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 1] = (unsigned char)g;
- // small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 2] = (unsigned char)b;
- // small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 3] = (unsigned char)a;
- // //memcpy((void*)&small_pixels[4*(i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh)], thumbnail_data.pixels.data() + 4*(i * thumbnail_data.width + j), 4);
- // }
- // }
- // size_t small_png_size = 0;
- // void* small_png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)small_pixels.data(), PLATE_THUMBNAIL_SMALL_WIDTH, PLATE_THUMBNAIL_SMALL_HEIGHT, 4, &small_png_size, MZ_DEFAULT_COMPRESSION, 1);
- // if (png_data != nullptr) {
- // std::string thumbnail_name = (boost::format("%1%_%2%_small.png") % local_path % (index + 1)).str();
- // res = mz_zip_writer_add_mem(&archive, thumbnail_name.c_str(), (const void*)small_png_data, small_png_size, MZ_NO_COMPRESSION);
- // mz_free(small_png_data);
- // }
- //
- // if (!res) {
- // add_error("Unable to add small thumbnail file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add small thumbnail file to archive\n");
- // }
- // }
- //
- // return res;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_calibration_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index)
- // {
- // bool res = false;
- //
- // /*size_t png_size = 0;
- // void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)thumbnail_data.pixels.data(), thumbnail_data.width, thumbnail_data.height, 4, &png_size, MZ_DEFAULT_COMPRESSION, 1);
- // if (png_data != nullptr) {
- // std::string thumbnail_name = (boost::format(PATTERN_FILE_FORMAT) % (index + 1)).str();
- // res = mz_zip_writer_add_mem(&archive, thumbnail_name.c_str(), (const void*)png_data, png_size, MZ_NO_COMPRESSION);
- // mz_free(png_data);
- // }
- //
- // if (!res) {
- // add_error("Unable to add thumbnail file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add thumbnail file to archive\n");
- // }*/
- //
- // return res;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_bbox_file_to_archive(mz_zip_archive& archive, /*const PlateBBoxData& id_bboxes, */int index)
- // {
- // bool res = false;
- // nlohmann::json j;
- // //id_bboxes.to_json(j);
- // std::string out = j.dump();
- //
- // std::string json_file_name = (boost::format(PATTERN_CONFIG_FILE_FORMAT) % (index + 1)).str();
- // if (!mz_zip_writer_add_mem(&archive, json_file_name.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add json file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add json file to archive\n");
- // return false;
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_relationships_file_to_archive(
- // mz_zip_archive &archive, std::string const &from, std::vector<std::string> const &targets, std::vector<std::string> const &types, PackingTemporaryData data, int export_plate_idx) const
- // {
- // std::stringstream stream;
- // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- // stream << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
- // if (from.empty()) {
- // stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\"/>\n";
- //
- // if (export_plate_idx < 0) {
- // //use cover image if have
- // if (data._3mf_thumbnail.empty()) {
- // stream << " <Relationship Target=\"/Metadata/plate_1.png"
- // << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
- // } else {
- // stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
- // << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
- // }
- //
- // if (data._3mf_printer_thumbnail_middle.empty()) {
- // stream << " <Relationship Target=\"/Metadata/plate_1.png"
- // << "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
- // } else {
- // stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
- // << "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
- // }
- //
- // if (data._3mf_printer_thumbnail_small.empty()) {
- // stream << "<Relationship Target=\"/Metadata/plate_1_small.png"
- // << "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
- // } else {
- // stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
- // << "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
- // }
- // }
- // else {
- // //always use plate thumbnails
- // std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
- // stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
- // << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
- //
- // thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
- // stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
- // << "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
- //
- // thumbnail_file_str = (boost::format("Metadata/plate_%1%_small.png") % (export_plate_idx + 1)).str();
- // stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
- // << "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
- // }
- // }
- // else if (targets.empty()) {
- // return false;
- // }
- // else {
- // int i = 0;
- // for (auto & path : targets) {
- // for (auto & type : types)
- // stream << " <Relationship Target=\"/" << xml_escape(path) << "\" Id=\"rel-" << std::to_string(++i) << "\" Type=\"" << type << "\"/>\n";
- // }
- // }
- // stream << "</Relationships>";
- //
- // std::string out = stream.str();
- //
- // if (!mz_zip_writer_add_mem(&archive, from.empty() ? RELATIONSHIPS_FILE.c_str() : from.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add relationships file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add relationships file to archive\n");
- // return false;
- // }
- //
- // return true;
- // }
- //
- //
- // static void reset_stream(std::stringstream &stream)
- // {
- // stream.str("");
- // stream.clear();
- // // https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
- // // Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double).
- // // It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact.
- // // The default value of std::stream precision is 6 digits only!
- // stream << std::setprecision(std::numeric_limits<float>::max_digits10);
- // }
- //
- // /*
- // * BBS: Production Extension (SplitModel)
- // * save sub model if objects_data is not empty
- // * not collect build items in sub model
- // */
- // bool _BBS_3MF_Exporter::_add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, ObjectToObjectDataMap& objects_data, Export3mfProgressFn proFn, /*BBLProject* project*/) const
- // {
- // bool sub_model = !objects_data.empty();
- // bool write_object = sub_model || !m_split_model;
- //
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", filename %1%, m_split_model %2%, sub_model %3%")%filename % m_split_model % sub_model;
- //
- //#if WRITE_ZIP_LANGUAGE_ENCODING
- // auto & zip_filename = filename;
- //#else
- // std::string zip_filename = encode_path(filename.c_str());
- // std::string extra = sub_model ? ZipUnicodePathExtraField::encode(filename, zip_filename) : "";
- //#endif
- // mz_zip_writer_staged_context context;
- // if (!mz_zip_writer_add_staged_open(&archive, &context, sub_model ? zip_filename.c_str() : MODEL_FILE.c_str(),
- // m_zip64 ?
- // // Maximum expected and allowed 3MF file size is 16GiB.
- // // This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records.
- // (uint64_t(1) << 30) * 16 :
- // // Maximum expected 3MF file size is 4GB-1. This is a workaround for interoperability with Windows 10 3D model fixing API, see
- // // GH issue #6193.
- // (uint64_t(1) << 32) - 1,
- //#if WRITE_ZIP_LANGUAGE_ENCODING
- // nullptr, nullptr, 0, MZ_DEFAULT_LEVEL, nullptr, 0, nullptr, 0)) {
- //#else
- // nullptr, nullptr, 0, MZ_DEFAULT_COMPRESSION, extra.c_str(), extra.length(), extra.c_str(), extra.length())) {
- //#endif
- // add_error("Unable to add model file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add model file to archive\n");
- // return false;
- // }
- //
- //
- // {
- // std::stringstream stream;
- // reset_stream(stream);
- // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- // stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:slic3rpe=\"http://schemas.slic3r.org/3mf/2017/06\"";
- // if (m_production_ext)
- // stream << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\"";
- // stream << ">\n";
- //
- // std::string origin;
- // std::string name;
- // std::string user_name;
- // std::string user_id;
- // std::string design_cover;
- // std::string license;
- // std::string description;
- // std::string copyright;
- // std::string rating;
- // std::string model_id;
- // std::string region_code;
- // //if (model.design_info) {
- // // user_name = model.design_info->Designer;
- // // user_id = model.design_info->DesignerUserId;
- // // BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer = " << user_name;
- // // BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_user_id = " << user_id;
- // //} //Susi_not_impl
- //
- // //if (project) {
- // // model_id = project->project_model_id;
- // // region_code = project->project_country_code;
- // //} //Susi_not_impl
- //
- // //if (model.model_info) {
- // // design_cover = model.model_info->cover_file;
- // // license = model.model_info->license;
- // // description = model.model_info->description;
- // // copyright = model.model_info->copyright;
- // // name = model.model_info->model_name;
- // // origin = model.model_info->origin;
- // // BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_cover = " << design_cover;
- // //} //Susi_not_impl
- // // remember to use metadata_item_map to store metadata info
- // std::map<std::string, std::string> metadata_item_map;
- // if (!sub_model) {
- // // update metadat_items
- // //if (model.model_info && model.model_info.get()) {
- // // metadata_item_map = model.model_info.get()->metadata_items;
- // //} //Susi_not_impl
- //
- // metadata_item_map[BBL_MODEL_NAME_TAG] = xml_escape(name);
- // metadata_item_map[BBL_ORIGIN_TAG] = xml_escape(origin);
- // metadata_item_map[BBL_DESIGNER_TAG] = xml_escape(user_name);
- // metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id;
- // metadata_item_map[BBL_DESIGNER_COVER_FILE_TAG] = xml_escape(design_cover);
- // metadata_item_map[BBL_DESCRIPTION_TAG] = xml_escape(description);
- // metadata_item_map[BBL_COPYRIGHT_NORMATIVE_TAG] = xml_escape(copyright);
- // metadata_item_map[BBL_LICENSE_TAG] = xml_escape(license);
- //
- // /* save model info */
- // if (!model_id.empty()) {
- // metadata_item_map[BBL_MODEL_ID_TAG] = model_id;
- // metadata_item_map[BBL_REGION_TAG] = region_code;
- // }
- //
- // std::string date = Slic3r::Utils::utc_timestamp(Slic3r::Utils::get_current_time_utc());
- // // keep only the date part of the string
- // date = date.substr(0, 10);
- // metadata_item_map[BBL_CREATION_DATE_TAG] = date;
- // metadata_item_map[BBL_MODIFICATION_TAG] = date;
- // //SoftFever: write BambuStudio tag to keep it compatible
- // metadata_item_map[BBL_APPLICATION_TAG] = (boost::format("%1%-%2%") % "BambuStudio" % SoftFever_VERSION).str();
- // }
- // metadata_item_map[BBS_3MF_VERSION] = std::to_string(VERSION_BBS_3MF);
- //
- // // store metadata info
- // for (auto item : metadata_item_map) {
- // BOOST_LOG_TRIVIAL(info) << "bbs_3mf: save key= " << item.first << ", value = " << item.second;
- // stream << " <" << METADATA_TAG << " name=\"" << item.first << "\">"
- // << xml_escape(item.second) << "</" << METADATA_TAG << ">\n";
- // }
- //
- // stream << " <" << RESOURCES_TAG << ">\n";
- // std::string buf = stream.str();
- // if (! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) {
- // add_error("Unable to add model file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add model file to archive\n");
- // return false;
- // }
- // }
- //
- // // Instance transformations, indexed by the 3MF object ID (which is a linear serialization of all instances of all ModelObjects).
- // BuildItemsList build_items;
- //
- // // The object_id here is a one based identifier of the first instance of a ModelObject in the 3MF file, where
- // // all the object instances of all ModelObjects are stored and indexed in a 1 based linear fashion.
- // // Therefore the list of object_ids here may not be continuous.
- // unsigned int object_id = 1;
- // unsigned int object_index = 0;
- //
- // bool cb_cancel = false;
- // std::vector<std::string> object_paths;
- // // if (!m_skip_model) {
- // for (ModelObject* obj : model.objects) {
- // if (sub_model && obj != objects_data.begin()->second.object) continue;
- //
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_MODELS, object_index++, model.objects.size(), cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // if (obj == nullptr)
- // continue;
- //
- // // Index of an object in the 3MF file corresponding to the 1st instance of a ModelObject.
- // ObjectToObjectDataMap::iterator object_it = objects_data.begin();
- //
- // if (!sub_model) {
- // // For backup, use backup id as object id
- // int backup_id = const_cast<Model&>(model).get_object_backup_id(*obj);
- // if (m_from_backup_save) object_id = backup_id;
- // object_it = objects_data.insert({obj, {obj, backup_id} }).first;
- // auto & object_data = object_it->second;
- //
- // if (m_split_model) {
- // auto filename = boost::format("3D/Objects/%s_%d.model") % obj->name % backup_id;
- // object_data.sub_path = "/" + filename.str();
- // object_paths.push_back(filename.str());
- // }
- //
- // auto &volumes_objectID = object_data.volumes_objectID;
- // unsigned int volume_id = object_id, volume_count = 0;
- // for (ModelVolume *volume : obj->volumes) {
- // if (volume == nullptr)
- // continue;
- // volume_count++;
- // if (m_share_mesh) {
- // auto iter = m_shared_meshes.find(volume->mesh_ptr().get());
- // if (iter != m_shared_meshes.end())
- // {
- // const ModelVolume* shared_volume = iter->second.second;
- // if ((shared_volume->supported_facets.equals(volume->supported_facets))
- // && (shared_volume->seam_facets.equals(volume->seam_facets))
- // && (shared_volume->mmu_segmentation_facets.equals(volume->mmu_segmentation_facets)))
- // {
- // auto data = iter->second.first;
- // const_cast<_BBS_3MF_Exporter *>(this)->m_volume_paths.insert({volume, {data->sub_path, data->volumes_objectID.find(iter->second.second)->second}});
- // volumes_objectID.insert({volume, 0});
- // object_data.share_mesh = true;
- // continue;
- // }
- // }
- // const_cast<_BBS_3MF_Exporter *>(this)->m_shared_meshes.insert({volume->mesh_ptr().get(), {&object_data, volume}});
- // }
- // if (m_from_backup_save)
- // volume_id = (volume_count << 16 | backup_id);
- // volumes_objectID.insert({volume, volume_id});
- // volume_id++;
- // }
- //
- // if (!m_from_backup_save) object_id = volume_id;
- // object_data.object_id = object_id;
- // }
- //
- // if (m_skip_model) continue;
- //
- // if (write_object) {
- // // Store geometry of all ModelVolumes contained in a single ModelObject into a single 3MF indexed triangle set object.
- // // object_it->second.volumes_objectID will contain the offsets of the ModelVolumes in that single indexed triangle set.
- // // object_id will be increased to point to the 1st instance of the next ModelObject.
- // if (!_add_object_to_model_stream(context, object_it->second)) {
- // add_error("Unable to add object to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add object to archive\n");
- // return false;
- // }
- // }
- //
- // if (sub_model) break;
- //
- // unsigned int count = 0;
- // for (const ModelInstance* instance : obj->instances) {
- // Transform3d t = instance->get_matrix();
- // // instance_id is just a 1 indexed index in build_items.
- // //assert(m_skip_static || curr_id == build_items.size() + 1);
- // build_items.emplace_back("", object_it->second.object_id, t, instance->printable);
- // count++;
- // }
- //
- // if (!m_from_backup_save) object_id++;
- // }
- // // }
- //
- // {
- // std::stringstream stream;
- // reset_stream(stream);
- //
- // if (!m_skip_model && !sub_model) {
- // for (auto object : model.objects) {
- // auto &data = objects_data[object];
- // _add_object_components_to_stream(stream, data);
- // }
- // }
- //
- // stream << " </" << RESOURCES_TAG << ">\n";
- //
- // // Store the transformations of all the ModelInstances of all ModelObjects, indexed in a linear fashion.
- // if (!_add_build_to_model_stream(stream, build_items)) {
- // add_error("Unable to add build to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add build to archive\n");
- // return false;
- // }
- //
- // stream << "</" << MODEL_TAG << ">\n";
- //
- // std::string buf = stream.str();
- //
- // if ((! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) ||
- // ! mz_zip_writer_add_staged_finish(&context)) {
- // add_error("Unable to add model file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add model file to archive\n");
- // return false;
- // }
- // }
- //
- // if (m_skip_model || write_object) return true;
- //
- // // write model rels
- // _add_relationships_file_to_archive(archive, MODEL_RELS_FILE, object_paths, {"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel"});
- //
- // if (!m_from_backup_save) {
- // boost::mutex mutex;
- // tbb::parallel_for(tbb::blocked_range<size_t>(0, objects_data.size(), 1), [this, &mutex, &model, objects = model.objects, &objects_data, &object_paths, main = &archive, project](const tbb::blocked_range<size_t>& range) {
- // for (size_t i = range.begin(); i < range.end(); ++i) {
- // auto iter = objects_data.find(objects[i]);
- // ObjectToObjectDataMap objects_data2;
- // objects_data2.insert(*iter);
- // auto & object = *iter->second.object;
- // mz_zip_archive archive;
- // mz_zip_zero_struct(&archive);
- // mz_zip_writer_init_heap(&archive, 0, 1024 * 1024);
- // CNumericLocalesSetter locales_setter;
- // _add_model_file_to_archive(object_paths[i], archive, model, objects_data2, nullptr, project);
- // iter->second = objects_data2.begin()->second;
- // void *ppBuf; size_t pSize;
- // mz_zip_writer_finalize_heap_archive(&archive, &ppBuf, &pSize);
- // mz_zip_writer_end(&archive);
- // mz_zip_zero_struct(&archive);
- // mz_zip_reader_init_mem(&archive, ppBuf, pSize, 0);
- // {
- // boost::unique_lock l(mutex);
- // mz_zip_writer_add_from_zip_reader(main, &archive, 0);
- // }
- // mz_zip_reader_end(&archive);
- // }
- // });
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_object_to_model_stream(mz_zip_writer_staged_context &context, ObjectData const &object_data) const
- // {
- // // backup: make _add_mesh_to_object_stream() reusable
- // auto flush = [this, &context](std::string & buf, bool force = false) {
- // if ((force && !buf.empty()) || buf.size() >= 65536 * 16) {
- // if (!mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) {
- // add_error("Error during writing or compression");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Error during writing or compression\n");
- // return false;
- // }
- // buf.clear();
- // }
- // return true;
- // };
- // if (!_add_mesh_to_object_stream(flush, object_data)) {
- // add_error("Unable to add mesh to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add mesh to archive\n");
- // return false;
- // }
- //
- // // Move all components to main model
- // //_add_object_components_to_stream(stream, object_data);
- //
- // return true;
- // }
- //
- // void _BBS_3MF_Exporter::_add_object_components_to_stream(std::stringstream &stream, ObjectData const &object_data) const
- // {
- // auto & object = *object_data.object;
- //
- // stream << " <" << OBJECT_TAG << " id=\"" << object_data.object_id;
- // if (m_production_ext)
- // stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t)object_data.backup_id}
- // << (object_data.share_mesh ? OBJECT_UUID_SUFFIX2 : OBJECT_UUID_SUFFIX);
- // stream << "\" type=\"model\">\n";
- //
- // stream << " <" << COMPONENTS_TAG << ">\n";
- //
- // for (unsigned int index = 0; index < object.volumes.size(); index ++) {
- // ModelVolume *volume = object.volumes[index];
- // unsigned int volume_id = object_data.volumes_objectID.find(volume)->second;
- // auto * ppath = &object_data.sub_path;
- // auto iter = m_volume_paths.find(volume);
- // if (iter != m_volume_paths.end()) {
- // ppath = &iter->second.first;
- // volume_id = iter->second.second;
- // }
- // //add the transform of the volume
- // if (ppath->empty())
- // stream << " <" << COMPONENT_TAG << " objectid=\"" << volume_id;
- // else
- // stream << " <" << COMPONENT_TAG << " p:path=\"" << xml_escape(*ppath) << "\" objectid=\"" << volume_id; // << "\"/>\n";
- // if (m_production_ext)
- // stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) (index + (object_data.backup_id << 16))} << COMPONENT_UUID_SUFFIX;
- // const Transform3d &transf = volume->get_matrix();
- // stream << "\" " << TRANSFORM_ATTR << "=\"";
- // for (unsigned c = 0; c < 4; ++c) {
- // for (unsigned r = 0; r < 3; ++r) {
- // stream << transf(r, c);
- // if (r != 2 || c != 3)
- // stream << " ";
- // }
- // }
- // stream << "\"/>\n";
- // }
- //
- // stream << " </" << COMPONENTS_TAG << ">\n";
- //
- // stream << " </" << OBJECT_TAG << ">\n";
- // }
- //
- //#if EXPORT_3MF_USE_SPIRIT_KARMA_FP
- // template <typename Num>
- // struct coordinate_policy_fixed : boost::spirit::karma::real_policies<Num>
- // {
- // static int floatfield(Num n) { return fmtflags::fixed; }
- // // Number of decimal digits to maintain float accuracy when storing into a text file and parsing back.
- // static unsigned precision(Num /* n */) { return std::numeric_limits<Num>::max_digits10 + 1; }
- // // No trailing zeros, thus for fmtflags::fixed usually much less than max_digits10 decimal numbers will be produced.
- // static bool trailing_zeros(Num /* n */) { return false; }
- // };
- // template <typename Num>
- // struct coordinate_policy_scientific : coordinate_policy_fixed<Num>
- // {
- // static int floatfield(Num n) { return fmtflags::scientific; }
- // };
- // // Define a new generator type based on the new coordinate policy.
- // using coordinate_type_fixed = boost::spirit::karma::real_generator<float, coordinate_policy_fixed<float>>;
- // using coordinate_type_scientific = boost::spirit::karma::real_generator<float, coordinate_policy_scientific<float>>;
- //#endif // EXPORT_3MF_USE_SPIRIT_KARMA_FP
- //
- // //BBS: change volume to seperate objects
- // bool _BBS_3MF_Exporter::_add_mesh_to_object_stream(std::function<bool(std::string &, bool)> const &flush, ObjectData const &object_data) const
- // {
- // std::string output_buffer;
- //
- //#if 0
- // auto flush = [this, &output_buffer, &context](bool force = false) {
- // if ((force && ! output_buffer.empty()) || output_buffer.size() >= 65536 * 16) {
- // if (! mz_zip_writer_add_staged_data(&context, output_buffer.data(), output_buffer.size())) {
- // add_error("Error during writing or compression");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Error during writing or compression\n");
- // return false;
- // }
- // output_buffer.clear();
- // }
- // return true;
- // };
- //#endif
- //
- // /*output_buffer += " <";
- // output_buffer += MESH_TAG;
- // output_buffer += ">\n <";
- // output_buffer += VERTICES_TAG;
- // output_buffer += ">\n";*/
- //
- // auto format_coordinate = [](float f, char *buf) -> char* {
- // assert(is_decimal_separator_point());
- //#if EXPORT_3MF_USE_SPIRIT_KARMA_FP
- // // Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
- // // https://github.com/boostorg/spirit/pull/586
- // // where the exported string is one digit shorter than it should be to guarantee lossless round trip.
- // // The code is left here for the ocasion boost guys improve.
- // coordinate_type_fixed const coordinate_fixed = coordinate_type_fixed();
- // coordinate_type_scientific const coordinate_scientific = coordinate_type_scientific();
- // // Format "f" in a fixed format.
- // char *ptr = buf;
- // boost::spirit::karma::generate(ptr, coordinate_fixed, f);
- // // Format "f" in a scientific format.
- // char *ptr2 = ptr;
- // boost::spirit::karma::generate(ptr2, coordinate_scientific, f);
- // // Return end of the shorter string.
- // auto len2 = ptr2 - ptr;
- // if (ptr - buf > len2) {
- // // Move the shorter scientific form to the front.
- // memcpy(buf, ptr, len2);
- // ptr = buf + len2;
- // }
- // // Return pointer to the end.
- // return ptr;
- //#else
- // // Round-trippable float, shortest possible.
- // return buf + sprintf(buf, "%.9g", f);
- //#endif
- // };
- //
- // auto const & object = *object_data.object;
- //
- // char buf[256];
- // unsigned int vertices_count = 0;
- // //unsigned int triangles_count = 0;
- // for (unsigned int index = 0; index < object.volumes.size(); index++) {
- // ModelVolume *volume = object.volumes[index];
- // if (volume == nullptr)
- // continue;
- //
- // int volume_id = object_data.volumes_objectID.find(volume)->second;
- // if (m_share_mesh && volume_id == 0)
- // continue;
- //
- // //if (!volume->mesh().stats().repaired())
- // // throw Slic3r::FileIOError("store_3mf() requires repair()");
- //
- // const indexed_triangle_set &its = volume->mesh().its;
- // if (its.vertices.empty()) {
- // add_error("Found invalid mesh");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Found invalid mesh\n");
- // return false;
- // }
- //
- // std::string type = (volume->type() == ModelVolumeType::MODEL_PART)?"model":"other";
- //
- // output_buffer += " <";
- // output_buffer += OBJECT_TAG;
- // output_buffer += " id=\"";
- // output_buffer += std::to_string(volume_id);
- // if (m_production_ext) {
- // std::stringstream stream;
- // reset_stream(stream);
- // stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) (index + (object_data.backup_id << 16))} << SUB_OBJECT_UUID_SUFFIX;
- // //output_buffer += "\" ";
- // //output_buffer += PUUID_ATTR;
- // //output_buffer += "=\"";
- // //output_buffer += std::to_string(hex_wrap<boost::uint32_t>{(boost::uint32_t)backup_id});
- // //output_buffer += OBJECT_UUID_SUFFIX;
- // output_buffer += stream.str();
- // }
- // output_buffer += "\" type=\"";
- // output_buffer += type;
- // output_buffer += "\">\n";
- // output_buffer += " <";
- // output_buffer += MESH_TAG;
- // output_buffer += ">\n <";
- // output_buffer += VERTICES_TAG;
- // output_buffer += ">\n";
- //
- // vertices_count += (int)its.vertices.size();
- //
- // for (size_t i = 0; i < its.vertices.size(); ++i) {
- // //don't save the volume's matrix into vertex data
- // //add the shared mesh logic
- // //Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
- // Vec3f v = its.vertices[i];
- // char* ptr = buf;
- // boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << VERTEX_TAG << " x=\"");
- // ptr = format_coordinate(v.x(), ptr);
- // boost::spirit::karma::generate(ptr, "\" y=\"");
- // ptr = format_coordinate(v.y(), ptr);
- // boost::spirit::karma::generate(ptr, "\" z=\"");
- // ptr = format_coordinate(v.z(), ptr);
- // boost::spirit::karma::generate(ptr, "\"/>\n");
- // *ptr = '\0';
- // output_buffer += buf;
- // if (!flush(output_buffer, false))
- // return false;
- // }
- // //}
- //
- // output_buffer += " </";
- // output_buffer += VERTICES_TAG;
- // output_buffer += ">\n <";
- // output_buffer += TRIANGLES_TAG;
- // output_buffer += ">\n";
- //
- // //for (ModelVolume* volume : object.volumes) {
- // // if (volume == nullptr)
- // // continue;
- //
- // //BBS: as we stored matrix seperately, not multiplied into vertex
- // //we don't need to consider this left hand case specially
- // //bool is_left_handed = volume->is_left_handed();
- // bool is_left_handed = false;
- // //VolumeToOffsetsMap::iterator volume_it = volumes_objectID.find(volume);
- // //assert(volume_it != volumes_objectID.end());
- //
- // //const indexed_triangle_set &its = volume->mesh().its;
- //
- // // updates triangle offsets
- // //unsigned int first_triangle_id = triangles_count;
- // //triangles_count += (int)its.indices.size();
- // //unsigned int last_triangle_id = triangles_count - 1;
- //
- // for (int i = 0; i < int(its.indices.size()); ++ i) {
- // {
- // const Vec3i &idx = its.indices[i];
- // char *ptr = buf;
- // boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << TRIANGLE_TAG <<
- // " v1=\"" << boost::spirit::int_ <<
- // "\" v2=\"" << boost::spirit::int_ <<
- // "\" v3=\"" << boost::spirit::int_ << "\"",
- // idx[is_left_handed ? 2 : 0],
- // idx[1],
- // idx[is_left_handed ? 0 : 2]);
- // *ptr = '\0';
- // output_buffer += buf;
- // }
- //
- // std::string custom_supports_data_string = volume->supported_facets.get_triangle_as_string(i);
- // if (! custom_supports_data_string.empty()) {
- // output_buffer += " ";
- // output_buffer += CUSTOM_SUPPORTS_ATTR;
- // output_buffer += "=\"";
- // output_buffer += custom_supports_data_string;
- // output_buffer += "\"";
- // }
- //
- // std::string custom_seam_data_string = volume->seam_facets.get_triangle_as_string(i);
- // if (! custom_seam_data_string.empty()) {
- // output_buffer += " ";
- // output_buffer += CUSTOM_SEAM_ATTR;
- // output_buffer += "=\"";
- // output_buffer += custom_seam_data_string;
- // output_buffer += "\"";
- // }
- //
- // std::string mmu_painting_data_string = volume->mmu_segmentation_facets.get_triangle_as_string(i);
- // if (! mmu_painting_data_string.empty()) {
- // output_buffer += " ";
- // output_buffer += MMU_SEGMENTATION_ATTR;
- // output_buffer += "=\"";
- // output_buffer += mmu_painting_data_string;
- // output_buffer += "\"";
- // }
- //
- // // BBS
- // if (i < its.properties.size()) {
- // std::string prop_str = its.properties[i].to_string();
- // if (!prop_str.empty()) {
- // output_buffer += " ";
- // output_buffer += FACE_PROPERTY_ATTR;
- // output_buffer += "=\"";
- // output_buffer += prop_str;
- // output_buffer += "\"";
- // }
- // }
- //
- // output_buffer += "/>\n";
- //
- // if (! flush(output_buffer, false))
- // return false;
- // }
- // output_buffer += " </";
- // output_buffer += TRIANGLES_TAG;
- // output_buffer += ">\n </";
- // output_buffer += MESH_TAG;
- // output_buffer += ">\n";
- // output_buffer += " </";
- // output_buffer += OBJECT_TAG;
- // output_buffer += ">\n";
- // }
- //
- // // Force flush.
- // return flush(output_buffer, true);
- // }
- //
- // void _BBS_3MF_Exporter::add_transformation(std::stringstream &stream, const Transform3d &tr)
- // {
- // for (unsigned c = 0; c < 4; ++c) {
- // for (unsigned r = 0; r < 3; ++r) {
- // stream << tr(r, c);
- // if (r != 2 || c != 3) stream << " ";
- // }
- // }
- // }
- //
- // bool _BBS_3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const
- // {
- // // This happens for empty projects
- // if (build_items.size() == 0) {
- // stream << " <" << BUILD_TAG << "/>\n";
- // return true;
- // }
- //
- // stream << " <" << BUILD_TAG;
- // if (m_production_ext)
- // stream << " " << PUUID_ATTR << "=\"" << BUILD_UUID << "\"";
- // stream << ">\n";
- //
- // for (const BuildItem& item : build_items) {
- // stream << " <" << ITEM_TAG << " " << OBJECTID_ATTR << "=\"" << item.id;
- // if (m_production_ext)
- // stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{item.id} << BUILD_UUID_SUFFIX;
- // if (!item.path.empty())
- // stream << "\" " << PPATH_ATTR << "=\"" << xml_escape(item.path);
- // stream << "\" " << TRANSFORM_ATTR << "=\"";
- // add_transformation(stream, item.transform);
- // stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\"/>\n";
- // }
- //
- // stream << " </" << BUILD_TAG << ">\n";
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model)
- // {
- // std::string out = "";
- // pt::ptree tree;
- //
- // unsigned int object_cnt = 0;
- // for (const ModelObject* object : model.objects) {
- // object_cnt++;
- // if (!object->is_cut())
- // continue;
- // pt::ptree& obj_tree = tree.add("objects.object", "");
- //
- // obj_tree.put("<xmlattr>.id", object_cnt);
- //
- // // Store info for cut_id
- // pt::ptree& cut_id_tree = obj_tree.add("cut_id", "");
- //
- // // store cut_id atributes
- // cut_id_tree.put("<xmlattr>.id", object->cut_id.id().id);
- // cut_id_tree.put("<xmlattr>.check_sum", object->cut_id.check_sum());
- // cut_id_tree.put("<xmlattr>.connectors_cnt", object->cut_id.connectors_cnt());
- //
- // int volume_idx = -1;
- // for (const ModelVolume* volume : object->volumes) {
- // ++volume_idx;
- // if (volume->is_cut_connector()) {
- // pt::ptree& connectors_tree = obj_tree.add("connectors.connector", "");
- // connectors_tree.put("<xmlattr>.volume_id", volume_idx);
- // connectors_tree.put("<xmlattr>.type", int(volume->cut_info.connector_type));
- // connectors_tree.put("<xmlattr>.r_tolerance", volume->cut_info.radius_tolerance);
- // connectors_tree.put("<xmlattr>.h_tolerance", volume->cut_info.height_tolerance);
- // }
- // }
- // }
- //
- // if (!tree.empty()) {
- // std::ostringstream oss;
- // pt::write_xml(oss, tree);
- // out = oss.str();
- //
- // // Post processing("beautification") of the output string for a better preview
- // boost::replace_all(out, "><object", ">\n <object");
- // boost::replace_all(out, "><cut_id", ">\n <cut_id");
- // boost::replace_all(out, "></cut_id>", ">\n </cut_id>");
- // boost::replace_all(out, "><connectors", ">\n <connectors");
- // boost::replace_all(out, "></connectors>", ">\n </connectors>");
- // boost::replace_all(out, "><connector", ">\n <connector");
- // boost::replace_all(out, "></connector>", ">\n </connector>");
- // boost::replace_all(out, "></object>", ">\n </object>");
- // // OR just
- // boost::replace_all(out, "><", ">\n<");
- // }
- //
- // if (!out.empty()) {
- // if (!mz_zip_writer_add_mem(&archive, CUT_INFORMATION_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add cut information file to archive");
- // return false;
- // }
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model)
- // {
- // assert(is_decimal_separator_point());
- // std::string out = "";
- // char buffer[1024];
- //
- // unsigned int count = 0;
- // for (const ModelObject* object : model.objects) {
- // ++count;
- // const std::vector<double>& layer_height_profile = object->layer_height_profile.get();
- // if (layer_height_profile.size() >= 4 && layer_height_profile.size() % 2 == 0) {
- // snprintf(buffer, 1024, "object_id=%d|", count);
- // out += buffer;
- //
- // // Store the layer height profile as a single semicolon separated list.
- // for (size_t i = 0; i < layer_height_profile.size(); ++i) {
- // snprintf(buffer, 1024, (i == 0) ? "%f" : ";%f", layer_height_profile[i]);
- // out += buffer;
- // }
- //
- // out += "\n";
- // }
- // }
- //
- // if (!out.empty()) {
- // if (!mz_zip_writer_add_mem(&archive, BBS_LAYER_HEIGHTS_PROFILE_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add layer heights profile file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add layer heights profile file to archive\n");
- // return false;
- // }
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
- // {
- // std::string out = "";
- // pt::ptree tree;
- //
- // unsigned int object_cnt = 0;
- // for (const ModelObject* object : model.objects) {
- // object_cnt++;
- // const t_layer_config_ranges& ranges = object->layer_config_ranges;
- // if (!ranges.empty())
- // {
- // pt::ptree& obj_tree = tree.add("objects.object","");
- //
- // obj_tree.put("<xmlattr>.id", object_cnt);
- //
- // // Store the layer config ranges.
- // for (const auto& range : ranges) {
- // pt::ptree& range_tree = obj_tree.add("range", "");
- //
- // // store minX and maxZ
- // range_tree.put("<xmlattr>.min_z", range.first.first);
- // range_tree.put("<xmlattr>.max_z", range.first.second);
- //
- // // store range configuration
- // const ModelConfig& config = range.second;
- // for (const std::string& opt_key : config.keys()) {
- // pt::ptree& opt_tree = range_tree.add("option", config.opt_serialize(opt_key));
- // opt_tree.put("<xmlattr>.opt_key", opt_key);
- // }
- // }
- // }
- // }
- //
- // if (!tree.empty()) {
- // std::ostringstream oss;
- // pt::write_xml(oss, tree);
- // out = oss.str();
- //
- // // Post processing("beautification") of the output string for a better preview
- // boost::replace_all(out, "><object", ">\n <object");
- // boost::replace_all(out, "><range", ">\n <range");
- // boost::replace_all(out, "><option", ">\n <option");
- // boost::replace_all(out, "></range>", ">\n </range>");
- // boost::replace_all(out, "></object>", ">\n </object>");
- // // OR just
- // boost::replace_all(out, "><", ">\n<");
- // }
- //
- // if (!out.empty()) {
- // if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add layer heights profile file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add layer heights profile file to archive\n");
- // return false;
- // }
- // }
- //
- // return true;
- // }
- //
- // /*
- // bool _BBS_3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
- // {
- // assert(is_decimal_separator_point());
- // std::string out = "";
- // char buffer[1024];
- //
- // unsigned int count = 0;
- // for (const ModelObject* object : model.objects) {
- // ++count;
- // const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
- // if (!sla_support_points.empty()) {
- // sprintf(buffer, "object_id=%d|", count);
- // out += buffer;
- //
- // // Store the layer height profile as a single space separated list.
- // for (size_t i = 0; i < sla_support_points.size(); ++i) {
- // sprintf(buffer, (i==0 ? "%f %f %f %f %f" : " %f %f %f %f %f"), sla_support_points[i].pos(0), sla_support_points[i].pos(1), sla_support_points[i].pos(2), sla_support_points[i].head_front_radius, (float)sla_support_points[i].is_new_island);
- // out += buffer;
- // }
- // out += "\n";
- // }
- // }
- //
- // if (!out.empty()) {
- // // Adds version header at the beginning:
- // //out = std::string("support_points_format_version=") + std::to_string(support_points_format_version) + std::string("\n") + out;
- //
- // if (!mz_zip_writer_add_mem(&archive, SLA_SUPPORT_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add sla support points file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add sla support points file to archive\n");
- // return false;
- // }
- // }
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model)
- // {
- // assert(is_decimal_separator_point());
- // const char *const fmt = "object_id=%d|";
- // std::string out;
- //
- // unsigned int count = 0;
- // for (const ModelObject* object : model.objects) {
- // ++count;
- // sla::DrainHoles drain_holes = object->sla_drain_holes;
- //
- // // The holes were placed 1mm above the mesh in the first implementation.
- // // This was a bad idea and the reference point was changed in 2.3 so
- // // to be on the mesh exactly. The elevated position is still saved
- // // in 3MFs for compatibility reasons.
- // for (sla::DrainHole& hole : drain_holes) {
- // hole.pos -= hole.normal.normalized();
- // hole.height += 1.f;
- // }
- //
- // if (!drain_holes.empty()) {
- // out += string_printf(fmt, count);
- //
- // // Store the layer height profile as a single space separated list.
- // for (size_t i = 0; i < drain_holes.size(); ++i)
- // out += string_printf((i == 0 ? "%f %f %f %f %f %f %f %f" : " %f %f %f %f %f %f %f %f"),
- // drain_holes[i].pos(0),
- // drain_holes[i].pos(1),
- // drain_holes[i].pos(2),
- // drain_holes[i].normal(0),
- // drain_holes[i].normal(1),
- // drain_holes[i].normal(2),
- // drain_holes[i].radius,
- // drain_holes[i].height);
- //
- // out += "\n";
- // }
- // }
- //
- // if (!out.empty()) {
- // // Adds version header at the beginning:
- // //out = std::string("drain_holes_format_version=") + std::to_string(drain_holes_format_version) + std::string("\n") + out;
- //
- // if (!mz_zip_writer_add_mem(&archive, SLA_DRAIN_HOLES_FILE.c_str(), static_cast<const void*>(out.data()), out.length(), mz_uint(MZ_DEFAULT_COMPRESSION))) {
- // add_error("Unable to add sla support points file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add sla support points file to archive\n");
- // return false;
- // }
- // }
- // return true;
- // }*/
- //
- // bool _BBS_3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config)
- // {
- // assert(is_decimal_separator_point());
- // char buffer[1024];
- // snprintf(buffer, 1024, "; %s\n\n", header_slic3r_generated().c_str());
- // std::string out = buffer;
- //
- // for (const std::string &key : config.keys())
- // if (key != "compatible_printers")
- // out += "; " + key + " = " + config.opt_serialize(key) + "\n";
- //
- // if (!out.empty()) {
- // if (!mz_zip_writer_add_mem(&archive, BBS_PRINT_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add print config file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add print config file to archive\n");
- // return false;
- // }
- // }
- //
- // return true;
- // }
- //
- // //BBS: add project config file logic for new json format
- // bool _BBS_3MF_Exporter::_add_project_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, Model& model)
- // {
- // const std::string& temp_path = model.get_backup_path();
- // std::string temp_file = temp_path + std::string("/") + "_temp_1.config";
- // config.save_to_json(temp_file, std::string("project_settings"), std::string("project"), std::string(SoftFever_VERSION));
- // return _add_file_to_archive(archive, BBS_PROJECT_CONFIG_FILE, temp_file);
- // }
- //
- // //BBS: add project embedded preset files
- // bool _BBS_3MF_Exporter::_add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector<Preset*> project_presets)
- // {
- // char buffer[1024];
- // snprintf(buffer, 1024, "; %s\n\n", header_slic3r_generated().c_str());
- // std::string out = buffer;
- // int print_count = 0, filament_count = 0, printer_count = 0;
- // const std::string& temp_path = model.get_backup_path();
- //
- // for (int i = 0; i < project_presets.size(); i++)
- // {
- // Preset* preset = project_presets[i];
- //
- // if (preset) {
- // preset->file = temp_path + std::string("/") + "_temp_1.config";
- // DynamicPrintConfig& config = preset->config;
- // //config.save(preset->file);
- // config.save_to_json(preset->file, preset->name, std::string("project"), preset->version.to_string());
- //
- // std::string dest_file;
- // if (preset->type == Preset::TYPE_PRINT) {
- // dest_file = (boost::format(EMBEDDED_PRINT_FILE_FORMAT) % (print_count + 1)).str();
- // print_count++;
- // }
- // else if (preset->type == Preset::TYPE_FILAMENT) {
- // dest_file = (boost::format(EMBEDDED_FILAMENT_FILE_FORMAT) % (filament_count + 1)).str();
- // filament_count++;
- // }
- // else if (preset->type == Preset::TYPE_PRINTER) {
- // dest_file = (boost::format(EMBEDDED_PRINTER_FILE_FORMAT) % (printer_count + 1)).str();
- // printer_count++;
- // }
- // else
- // continue;
- //
- // _add_file_to_archive(archive, dest_file, preset->file);
- // }
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode, bool use_loaded_id)
- // {
- // std::stringstream stream;
- // // Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
- // // when loaded as accurately as possible.
- // stream << std::setprecision(std::numeric_limits<double>::max_digits10);
- // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- // stream << "<" << CONFIG_TAG << ">\n";
- //
- // if (!m_skip_model)
- // for (const ObjectToObjectDataMap::value_type& obj_metadata : objects_data) {
- // auto object_data = obj_metadata.second;
- // const ModelObject *obj = object_data.object;
- // if (obj != nullptr) {
- // // Output of instances count added because of github #3435, currently not used by PrusaSlicer
- // //stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
- // stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << object_data.object_id << "\">\n";
- //
- // // stores object's name
- // if (!obj->name.empty())
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
- //
- // //BBS: store object's module name
- // if (!obj->module_name.empty())
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"module\" " << VALUE_ATTR << "=\"" << xml_escape(obj->module_name) << "\"/>\n";
- //
- // // stores object's config data
- // for (const std::string& key : obj->config.keys()) {
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.opt_serialize(key) << "\"/>\n";
- // }
- //
- // for (const ModelVolume* volume : obj_metadata.second.object->volumes) {
- // if (volume != nullptr) {
- // const VolumeToObjectIDMap& objectIDs = obj_metadata.second.volumes_objectID;
- // VolumeToObjectIDMap::const_iterator it = objectIDs.find(volume);
- // if (it != objectIDs.end()) {
- // // stores volume's offsets
- // stream << " <" << PART_TAG << " ";
- // //stream << FIRST_TRIANGLE_ID_ATTR << "=\"" << it->second.first_triangle_id << "\" ";
- // //stream << LAST_TRIANGLE_ID_ATTR << "=\"" << it->second.last_triangle_id << "\" ";
- // int volume_id = it->second;
- // if (m_share_mesh && volume_id == 0)
- // volume_id = m_volume_paths.find(volume)->second.second;
- // stream << ID_ATTR << "=\"" << volume_id << "\" ";
- //
- // stream << SUBTYPE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\">\n";
- // //stream << " <" << PART_TAG << " " << ID_ATTR << "=\"" << it->second << "\" " << SUBTYPE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\">\n";
- //
- // // stores volume's name
- // if (!volume->name.empty())
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
- // //stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
- //
- // // stores volume's modifier field (legacy, to support old slicers)
- // /*if (volume->is_modifier())
- // stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << PART_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
- // // stores volume's type (overrides the modifier field above)
- // stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << PART_TYPE << "\" " << KEY_ATTR << "=\"" << PART_TYPE_KEY << "\" " <<
- // VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";*/
- //
- // // stores volume's local matrix
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
- // Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix();
- // for (int r = 0; r < 4; ++r) {
- // for (int c = 0; c < 4; ++c) {
- // stream << matrix(r, c);
- // if (r != 3 || c != 3)
- // stream << " ";
- // }
- // }
- // stream << "\"/>\n";
- //
- // // stores volume's source data
- // {
- // std::string input_file = xml_escape(m_fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string());
- // //std::string prefix = std::string(" <") + METADATA_TAG + " " + KEY_ATTR + "=\"";
- // std::string prefix = std::string(" <") + METADATA_TAG + " " + KEY_ATTR + "=\"";
- // if (! volume->source.input_file.empty()) {
- // stream << prefix << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << input_file << "\"/>\n";
- // stream << prefix << SOURCE_OBJECT_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.object_idx << "\"/>\n";
- // stream << prefix << SOURCE_VOLUME_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.volume_idx << "\"/>\n";
- // stream << prefix << SOURCE_OFFSET_X_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(0) << "\"/>\n";
- // stream << prefix << SOURCE_OFFSET_Y_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(1) << "\"/>\n";
- // stream << prefix << SOURCE_OFFSET_Z_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(2) << "\"/>\n";
- // }
- // assert(! volume->source.is_converted_from_inches || ! volume->source.is_converted_from_meters);
- // if (volume->source.is_converted_from_inches)
- // stream << prefix << SOURCE_IN_INCHES << "\" " << VALUE_ATTR << "=\"1\"/>\n";
- // else if (volume->source.is_converted_from_meters)
- // stream << prefix << SOURCE_IN_METERS << "\" " << VALUE_ATTR << "=\"1\"/>\n";
- // }
- //
- // // stores volume's config data
- // for (const std::string& key : volume->config.keys()) {
- // stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
- // }
- //
- // if (const std::optional<EmbossShape> &es = volume->emboss_shape;
- // es.has_value())
- // to_xml(stream, *es, *volume, archive);
- //
- // if (const std::optional<TextConfiguration> &tc = volume->text_configuration;
- // tc.has_value())
- // TextConfigurationSerialization::to_xml(stream, *tc);
- //
- // // stores mesh's statistics
- // const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors;
- // stream << " <" << MESH_STAT_TAG << " ";
- // stream << MESH_STAT_EDGES_FIXED << "=\"" << stats.edges_fixed << "\" ";
- // stream << MESH_STAT_DEGENERATED_FACETS << "=\"" << stats.degenerate_facets << "\" ";
- // stream << MESH_STAT_FACETS_REMOVED << "=\"" << stats.facets_removed << "\" ";
- // stream << MESH_STAT_FACETS_RESERVED << "=\"" << stats.facets_reversed << "\" ";
- // stream << MESH_STAT_BACKWARDS_EDGES << "=\"" << stats.backwards_edges << "\"/>\n";
- //
- // stream << " </" << PART_TAG << ">\n";
- // }
- // }
- // }
- //
- // stream << " </" << OBJECT_TAG << ">\n";
- // }
- // }
- //
- // //BBS: store plate related logic
- // std::vector<std::string> gcode_paths;
- // for (unsigned int i = 0; i < (unsigned int)plate_data_list.size(); ++i)
- // {
- // PlateData* plate_data = plate_data_list[i];
- // int instance_size = plate_data->objects_and_instances.size();
- //
- // if (plate_data != nullptr) {
- // stream << " <" << PLATE_TAG << ">\n";
- // //plate index
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PLATERID_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->plate_index + 1 << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PLATER_NAME_ATTR << "\" " << VALUE_ATTR << "=\"" << xml_escape(plate_data->plate_name.c_str()) << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LOCK_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->locked<< "\"/>\n";
- // ConfigOption* bed_type_opt = plate_data->config.option("curr_bed_type");
- // t_config_enum_names bed_type_names = ConfigOptionEnum<BedType>::get_enum_names();
- // if (bed_type_opt != nullptr && bed_type_names.size() > bed_type_opt->getInt())
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << BED_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << bed_type_names[bed_type_opt->getInt()] << "\"/>\n";
- //
- // ConfigOption* print_sequence_opt = plate_data->config.option("print_sequence");
- // t_config_enum_names print_sequence_names = ConfigOptionEnum<PrintSequence>::get_enum_names();
- // if (print_sequence_opt != nullptr && print_sequence_names.size() > print_sequence_opt->getInt())
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PRINT_SEQUENCE_ATTR << "\" " << VALUE_ATTR << "=\"" << print_sequence_names[print_sequence_opt->getInt()] << "\"/>\n";
- //
- // ConfigOptionInts *first_layer_print_sequence_opt = plate_data->config.option<ConfigOptionInts>("first_layer_print_sequence");
- // if (first_layer_print_sequence_opt != nullptr) {
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << FIRST_LAYER_PRINT_SEQUENCE_ATTR << "\" " << VALUE_ATTR << "=\"";
- // const std::vector<int>& values = first_layer_print_sequence_opt->values;
- // for (int i = 0; i < values.size(); ++i) {
- // stream << values[i];
- // if (i != (values.size() - 1))
- // stream << " ";
- // }
- // stream << "\"/>\n";
- // }
- //
- // ConfigOption* spiral_mode_opt = plate_data->config.option("spiral_mode");
- // if (spiral_mode_opt)
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SPIRAL_VASE_MODE << "\" " << VALUE_ATTR << "=\"" << spiral_mode_opt->getBool() << "\"/>\n";
- //
- // if (save_gcode)
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n";
- // if (!plate_data->gcode_file.empty()) {
- // gcode_paths.push_back(plate_data->gcode_file);
- // }
- // if (plate_data->plate_thumbnail.is_valid()) {
- // std::string thumbnail_file_in_3mf = (boost::format(THUMBNAIL_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n";
- // }
- // else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){
- // std::string thumbnail_file_in_3mf = (boost::format(THUMBNAIL_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n";
- // }
- //
- // if (!plate_data->top_file.empty()) {
- // std::string top_file_in_3mf = (boost::format(TOP_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TOP_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << top_file_in_3mf << "\"/>\n";
- // }
- //
- // if (!plate_data->pick_file.empty()) {
- // std::string pick_file_in_3mf = (boost::format(PICK_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PICK_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pick_file_in_3mf << "\"/>\n";
- // }
- //
- // /*if (!plate_data->pattern_file.empty()) {
- // std::string pattern_file_in_3mf = (boost::format(PATTERN_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_file_in_3mf << "\"/>\n";
- // }*/
- // if (!plate_data->pattern_bbox_file.empty()) {
- // std::string pattern_bbox_file_in_3mf = (boost::format(PATTERN_CONFIG_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_BBOX_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_bbox_file_in_3mf << "\"/>\n";
- // }
- //
- // if (!m_skip_model && instance_size > 0)
- // {
- // for (unsigned int j = 0; j < instance_size; ++j)
- // {
- // stream << " <" << INSTANCE_TAG << ">\n";
- // int obj_id = plate_data->objects_and_instances[j].first;
- // int inst_id = plate_data->objects_and_instances[j].second;
- // int identify_id = 0;
- // ModelObject* obj = NULL;
- // ModelInstance* inst = NULL;
- // if (obj_id >= model.objects.size()) {
- // BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_id;
- // }
- // else
- // obj = model.objects[obj_id];
- //
- // if (obj && (inst_id >= obj->instances.size())) {
- // BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_id;
- // }
- // else if (obj){
- // inst = obj->instances[inst_id];
- // if (use_loaded_id && (inst->loaded_id > 0))
- // identify_id = inst->loaded_id;
- // else
- // identify_id = inst->id().id;
- // }
- // obj_id = objects_data.find(obj)->second.object_id;
- //
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OBJECT_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << obj_id << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << INSTANCEID_ATTR << "\" " << VALUE_ATTR << "=\"" << inst_id << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << IDENTIFYID_ATTR << "\" " << VALUE_ATTR << "=\"" << identify_id << "\"/>\n";
- // stream << " </" << INSTANCE_TAG << ">\n";
- // }
- // }
- // stream << " </" << PLATE_TAG << ">\n";
- // }
- // }
- //
- // // write model rels
- // if (save_gcode)
- // _add_relationships_file_to_archive(archive, BBS_MODEL_CONFIG_RELS_FILE, gcode_paths, {"http://schemas.bambulab.com/package/2021/gcode"}, Slic3r::PackingTemporaryData(), export_plate_idx);
- //
- // if (!m_skip_model) {
- // //BBS: store assemble related info
- // stream << " <" << ASSEMBLE_TAG << ">\n";
- // for (const ObjectToObjectDataMap::value_type& obj_metadata : objects_data) {
- // auto object_data = obj_metadata.second;
- // const ModelObject* obj = object_data.object;
- // if (obj != nullptr) {
- // for (int instance_idx = 0; instance_idx < obj->instances.size(); ++instance_idx) {
- // if (obj->instances[instance_idx]->is_assemble_initialized()) {
- // stream << " <" << ASSEMBLE_ITEM_TAG << " " << OBJECT_ID_ATTR << "=\"" << object_data.object_id << "\" ";
- // stream << INSTANCEID_ATTR << "=\"" << instance_idx << "\" " << TRANSFORM_ATTR << "=\"";
- // for (unsigned c = 0; c < 4; ++c) {
- // for (unsigned r = 0; r < 3; ++r) {
- // const Transform3d assemble_trans = obj->instances[instance_idx]->get_assemble_transformation().get_matrix();
- // stream << assemble_trans(r, c);
- // if (r != 2 || c != 3)
- // stream << " ";
- // }
- // }
- //
- // stream << "\" ";
- //
- // stream << OFFSET_ATTR << "=\"";
- // const Vec3d ofs2ass = obj->instances[instance_idx]->get_offset_to_assembly();
- // stream << ofs2ass(0) << " " << ofs2ass(1) << " " << ofs2ass(2);
- // stream << "\" />\n";
- // }
- // }
- // }
- // }
- // stream << " </" << ASSEMBLE_TAG << ">\n";
- // }
- //
- // stream << "</" << CONFIG_TAG << ">\n";
- //
- // std::string out = stream.str();
- // if (!mz_zip_writer_add_mem(&archive, BBS_MODEL_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add model config file to archive\n");
- // add_error("Unable to add model config file to archive");
- // return false;
- // }
- //
- // return true;
- // }
- //
- // bool _BBS_3MF_Exporter::_add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config)
- // {
- // std::stringstream stream;
- // // Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
- // // when loaded as accurately as possible.
- // stream << std::setprecision(std::numeric_limits<double>::max_digits10);
- // stream << std::setiosflags(std::ios::fixed) << std::setprecision(2);
- // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- // stream << "<" << CONFIG_TAG << ">\n";
- //
- // // save slice header for debug
- // stream << " <" << SLICE_HEADER_TAG << ">\n";
- // stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "X-BBL-Client-Type" << "\" " << VALUE_ATTR << "=\"" << "slicer" << "\"/>\n";
- // stream << " <" << SLICE_HEADER_ITEM_TAG << " " << KEY_ATTR << "=\"" << "X-BBL-Client-Version" << "\" " << VALUE_ATTR << "=\"" << convert_to_full_version(SoftFever_VERSION) << "\"/>\n";
- // stream << " </" << SLICE_HEADER_TAG << ">\n";
- //
- // for (unsigned int i = 0; i < (unsigned int)plate_data_list.size(); ++i)
- // {
- // PlateData* plate_data = plate_data_list[i];
- // //int instance_size = plate_data->objects_and_instances.size();
- //
- // if (plate_data != nullptr && plate_data->is_sliced_valid) {
- // stream << " <" << PLATE_TAG << ">\n";
- // //plate index
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PLATE_IDX_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->plate_index + 1 << "\"/>\n";
- //
- // int timelapse_type = int(config.opt_enum<TimelapseType>("timelapse_type"));
- // for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) {
- // if (it->msg == NOT_GENERATE_TIMELAPSE) {
- // timelapse_type = -1;
- // break;
- // }
- // }
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PRINTER_MODEL_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->printer_model_id << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NOZZLE_DIAMETERS_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->nozzle_diameters << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << timelapse_type << "\"/>\n";
- // //stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_ERROR_CODE_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->timelapse_warning_code << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_PREDICTION_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_prediction_str() << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_WEIGHT_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_weight_str() << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SUPPORT_USED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_support_used << "\"/>\n";
- // stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LABEL_OBJECT_ENABLED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_label_object_enabled << "\"/>\n";
- //
- // for (auto it = plate_data->objects_and_instances.begin(); it != plate_data->objects_and_instances.end(); it++)
- // {
- // int obj_id = it->first;
- // int inst_id = it->second;
- // int identify_id = 0;
- // ModelObject* obj = NULL;
- // ModelInstance* inst = NULL;
- // if (obj_id >= model.objects.size()) {
- // BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_id;
- // continue;
- // }
- // obj = model.objects[obj_id];
- //
- // if (obj && (inst_id >= obj->instances.size())) {
- // BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_id;
- // continue;
- // }
- // inst = obj->instances[inst_id];
- // if (m_use_loaded_id && (inst->loaded_id > 0))
- // identify_id = inst->loaded_id;
- // else
- // identify_id = inst->id().id;
- // bool skipped = std::find(plate_data->skipped_objects.begin(), plate_data->skipped_objects.end(), identify_id) !=
- // plate_data->skipped_objects.end();
- // stream << " <" << OBJECT_TAG << " " << IDENTIFYID_ATTR << "=\"" << std::to_string(identify_id) << "\" " << NAME_ATTR << "=\"" << xml_escape(obj->name)
- // << "\" " << SKIPPED_ATTR << "=\"" << (skipped ? "true" : "false")
- // << "\" />\n";
- // }
- //
- // for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++)
- // {
- // stream << " <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" "
- // << FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
- // << FILAMENT_COLOR_TAG << "=\"" << it->color << "\" "
- // << FILAMENT_USED_M_TAG << "=\"" << it->used_m << "\" "
- // << FILAMENT_USED_G_TAG << "=\"" << it->used_g << "\" />\n";
- // }
- //
- // for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) {
- // stream << " <" << SLICE_WARNING_TAG << " msg=\"" << it->msg << "\" level=\"" << std::to_string(it->level) << "\" error_code =\"" << it->error_code << "\" />\n";
- // }
- // stream << " </" << PLATE_TAG << ">\n";
- // }
- // }
- // stream << "</" << CONFIG_TAG << ">\n";
- //
- // std::string out = stream.str();
- //
- // if (!mz_zip_writer_add_mem(&archive, SLICE_INFO_CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add model config file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", store slice-info to 3mf, length %1%, failed\n") % out.length();
- // return false;
- // }
- //
- // return true;
- // }
- //bool _BBS_3MF_Exporter::_add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn)
- //{
- // bool result = true;
- // bool cb_cancel = false;
- //
- // PlateDataPtrs plate_data_list2;
- // for (unsigned int i = 0; i < (unsigned int)plate_data_list.size(); ++i)
- // {
- // if (proFn) {
- // proFn(EXPORT_STAGE_ADD_GCODE, i, plate_data_list.size(), cb_cancel);
- // if (cb_cancel)
- // return false;
- // }
- //
- // PlateData* plate_data = plate_data_list[i];
- // if (!plate_data->gcode_file.empty() && plate_data->is_sliced_valid && boost::filesystem::exists(plate_data->gcode_file)) {
- // plate_data_list2.push_back(plate_data);
- // }
- // }
- //
- // boost::mutex mutex;
- // tbb::parallel_for(tbb::blocked_range<size_t>(0, plate_data_list2.size(), 1), [this, &plate_data_list2, &root_archive = archive, &mutex, &result](const tbb::blocked_range<size_t>& range) {
- // for (int i = range.begin(); i < range.end(); ++i) {
- // PlateData* plate_data = plate_data_list2[i];
- // auto src_gcode_file = plate_data->gcode_file;
- // std::string gcode_in_3mf = (boost::format(GCODE_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
- //
- // plate_data->gcode_file = gcode_in_3mf;
- // mz_zip_archive archive;
- // mz_zip_writer_staged_context context;
- // mz_zip_zero_struct(&archive);
- // mz_zip_writer_init_heap(&archive, 0, 1024 * 1024);
- // {
- // mz_zip_writer_add_staged_open(&archive, &context, gcode_in_3mf.c_str(), m_zip64 ? (uint64_t(1) << 30) * 16 : (uint64_t(1) << 32) - 1, nullptr, nullptr, 0,
- // MZ_DEFAULT_COMPRESSION, nullptr, 0, nullptr, 0);
- // boost::filesystem::path src_gcode_path(src_gcode_file);
- // if (!boost::filesystem::exists(src_gcode_path)) {
- // BOOST_LOG_TRIVIAL(error) << "Gcode is missing, filename = " << src_gcode_file;
- // result = false;
- // }
- // boost::filesystem::ifstream ifs(src_gcode_file, std::ios::binary);
- // std::string buf(64 * 1024, 0);
- // while (ifs) {
- // ifs.read(buf.data(), buf.size());
- // mz_zip_writer_add_staged_data(&context, buf.data(), ifs.gcount());
- // }
- // mz_zip_writer_add_staged_finish(&context);
- // }
- // void *ppBuf; size_t pSize;
- // mz_zip_writer_finalize_heap_archive(&archive, &ppBuf, &pSize);
- // mz_zip_writer_end(&archive);
- // mz_zip_zero_struct(&archive);
- // mz_zip_reader_init_mem(&archive, ppBuf, pSize, 0);
- // {
- // boost::unique_lock l(mutex);
- // mz_zip_writer_add_from_zip_reader(&root_archive, &archive, 0);
- // }
- // mz_zip_reader_end(&archive);
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", store %1% to 3mf %2%\n") % src_gcode_file % gcode_in_3mf;
- // }
- // });
- // return result;
- //}
- //
- //bool _BBS_3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config)
- //{
- // //BBS: add plate tree related logic
- // std::string out = "";
- // bool has_custom_gcode = false;
- // pt::ptree tree;
- // pt::ptree& main_tree = tree.add("custom_gcodes_per_layer", "");
- // for (auto custom_gcodes : model.plates_custom_gcodes) {
- // has_custom_gcode = true;
- // pt::ptree& plate_tree = main_tree.add("plate", "");
- // pt::ptree& plate_idx_tree = plate_tree.add("plate_info", "");
- // plate_idx_tree.put("<xmlattr>.id", custom_gcodes.first + 1);
- //
- // // store data of custom_gcode_per_print_z
- // for (const CustomGCode::Item& code : custom_gcodes.second.gcodes) {
- // pt::ptree& code_tree = plate_tree.add("layer", "");
- // code_tree.put("<xmlattr>.top_z", code.print_z);
- // code_tree.put("<xmlattr>.type", static_cast<int>(code.type));
- // code_tree.put("<xmlattr>.extruder", code.extruder);
- // code_tree.put("<xmlattr>.color", code.color);
- // code_tree.put("<xmlattr>.extra", code.extra);
- //
- // //BBS
- // std::string gcode = //code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") :
- // code.type == CustomGCode::PausePrint ? config->opt_string("machine_pause_gcode") :
- // code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") :
- // code.type == CustomGCode::ToolChange ? "tool_change" : code.extra;
- // code_tree.put("<xmlattr>.gcode", gcode);
- // }
- //
- // pt::ptree& mode_tree = plate_tree.add("mode", "");
- // // store mode of a custom_gcode_per_print_z
- // mode_tree.put("<xmlattr>.value", custom_gcodes.second.mode == CustomGCode::Mode::SingleExtruder ? CustomGCode::SingleExtruderMode :
- // custom_gcodes.second.mode == CustomGCode::Mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode :
- // CustomGCode::MultiExtruderMode);
- //
- // }
- // if (has_custom_gcode) {
- // std::ostringstream oss;
- // boost::property_tree::write_xml(oss, tree);
- // out = oss.str();
- //
- // // Post processing("beautification") of the output string
- // boost::replace_all(out, "><", ">\n<");
- // }
- //
- // if (!out.empty()) {
- // if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
- // add_error("Unable to add custom Gcodes per print_z file to archive");
- // BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add custom Gcodes per print_z file to archive\n");
- // return false;
- // }
- // }
- //
- // return true;
- //}
- //
- //bool _BBS_3MF_Exporter::_add_auxiliary_dir_to_archive(mz_zip_archive &archive, const std::string &aux_dir, PackingTemporaryData &data)
- //{
- // bool result = true;
- //
- // if (aux_dir.empty()) {
- // //no accessory directories
- // return result;
- // }
- //
- // boost::filesystem::path dir = boost::filesystem::path(aux_dir);
- // if (!boost::filesystem::exists(dir))
- // {
- // //no accessory directories
- // return result;
- // }
- //
- // static std::string const nocomp_exts[] = {".png", ".jpg", ".mp4", ".jpeg"};
- // std::deque<boost::filesystem::path> directories({dir});
- // int root_dir_len = dir.string().length() + 1;
- // //boost file access
- // while (!directories.empty()) {
- // boost::filesystem::directory_iterator iterator(directories.front());
- // directories.pop_front();
- // for (auto &dir_entry : iterator)
- // {
- // std::string src_file;
- // std::string dst_in_3mf;
- // if (boost::filesystem::is_directory(dir_entry.path()))
- // {
- // directories.push_back(dir_entry.path());
- // continue;
- // }
- // if (boost::filesystem::is_regular_file(dir_entry.path()) && !m_skip_auxiliary)
- // {
- // src_file = dir_entry.path().string();
- // dst_in_3mf = dir_entry.path().string();
- // dst_in_3mf.replace(0, root_dir_len, AUXILIARY_DIR);
- // std::replace(dst_in_3mf.begin(), dst_in_3mf.end(), '\\', '/');
- // if (_3MF_COVER_FILE.compare(1, _3MF_COVER_FILE.length() - 1, dst_in_3mf) == 0) {
- // data._3mf_thumbnail = dst_in_3mf;
- // } else if (m_thumbnail_small.compare(1, m_thumbnail_small.length() - 1, dst_in_3mf) == 0) {
- // data._3mf_printer_thumbnail_small = dst_in_3mf;
- // if (m_thumbnail_middle == m_thumbnail_small) data._3mf_printer_thumbnail_middle = dst_in_3mf;
- // } else if (m_thumbnail_middle.compare(1, m_thumbnail_middle.length() - 1, dst_in_3mf) == 0) {
- // data._3mf_printer_thumbnail_middle = dst_in_3mf;
- // }
- // result &= _add_file_to_archive(archive, dst_in_3mf, src_file);
- // }
- // }
- // }
- //
- // return result;
- //}
- //
- //// Perform conversions based on the config values available.
- ////FIXME provide a version of PrusaSlicer that stored the project file (3MF).
- //static void handle_legacy_project_loaded(unsigned int version_project_file, DynamicPrintConfig& config)
- //{
- // if (! config.has("brim_object_gap")) {
- // if (auto *opt_elephant_foot = config.option<ConfigOptionFloat>("elefant_foot_compensation", false); opt_elephant_foot) {
- // // Conversion from older PrusaSlicer which applied brim separation equal to elephant foot compensation.
- // auto *opt_brim_separation = config.option<ConfigOptionFloat>("brim_object_gap", true);
- // opt_brim_separation->value = opt_elephant_foot->value;
- // }
- // }
- //}
- //
- //// backup backgroud thread to dispatch tasks and coperate with ui thread
- //class _BBS_Backup_Manager
- //{
- //public:
- // static _BBS_Backup_Manager& get() {
- // static _BBS_Backup_Manager m;
- // return m;
- // }
- //
- // void set_post_callback(std::function<void(int)> c) {
- // boost::lock_guard lock(m_mutex);
- // m_post_callback = c;
- // }
- //
- // void run_ui_tasks() {
- // std::deque<Task> tasks;
- // {
- // boost::lock_guard lock(m_mutex);
- // std::swap(tasks, m_ui_tasks);
- // }
- // for (auto& t : tasks)
- // {
- // process_ui_task(t);
- // }
- // }
- //
- // void push_object_gaurd(ModelObject& object) {
- // m_gaurd_objects.push_back(std::make_pair(&object, 0));
- // }
- //
- // void pop_object_gaurd() {
- // auto object = m_gaurd_objects.back();
- // m_gaurd_objects.pop_back();
- // if (object.second)
- // add_object_mesh(*object.first);
- // }
- //
- // void add_object_mesh(ModelObject& object) {
- // for (auto& g : m_gaurd_objects) {
- // if (g.first == &object) {
- // ++g.second;
- // return;
- // }
- // }
- // // clone object
- // auto model = object.get_model();
- // auto o = m_temp_model.add_object(object);
- // int backup_id = model->get_object_backup_id(object);
- // push_task({ AddObject, (size_t) backup_id, object.get_model()->get_backup_path(), o, 1 });
- // }
- //
- // void remove_object_mesh(ModelObject& object) {
- // push_task({ RemoveObject, object.id().id, object.get_model()->get_backup_path() });
- // }
- //
- // void backup_soon() {
- // boost::lock_guard lock(m_mutex);
- // m_other_changes_backup = true;
- // m_tasks.push_back({ Backup, 0, std::string(), nullptr, ++m_task_seq });
- // m_cond.notify_all();
- // }
- //
- // void remove_backup(Model& model, bool removeAll) {
- // BOOST_LOG_TRIVIAL(info)
- // << "remove_backup " << model.get_backup_path() << ", " << removeAll;
- // std::deque<Task> canceled_tasks;
- // boost::unique_lock lock(m_mutex);
- // if (removeAll && model.is_need_backup()) {
- // // running task may not be canceled
- // for (auto & t : m_ui_tasks)
- // canceled_tasks.push_back(t);
- // for (auto & t : m_tasks)
- // canceled_tasks.push_back(t);
- // m_ui_tasks.clear();
- // m_tasks.clear();
- // }
- // m_tasks.push_back({ RemoveBackup, model.id().id, model.get_backup_path(), nullptr, removeAll });
- // ++m_task_seq;
- // if (model.is_need_backup()) {
- // m_other_changes = false;
- // m_other_changes_backup = false;
- // }
- // m_cond.notify_all();
- // lock.unlock();
- // for (auto& t : canceled_tasks) {
- // process_ui_task(t, true);
- // }
- // }
- //
- // void set_interval(long n) {
- // boost::lock_guard lock(m_mutex);
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and last interval is: " << m_interval;
- // m_next_backup -= boost::posix_time::seconds(m_interval);
- // m_interval = n;
- // m_next_backup += boost::posix_time::seconds(m_interval);
- // m_cond.notify_all();
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " exit, and new interval is: " << m_interval;
- // }
- //
- // void put_other_changes()
- // {
- // BOOST_LOG_TRIVIAL(info) << "put_other_changes";
- // m_other_changes = true;
- // m_other_changes_backup = true;
- // }
- //
- // void clear_other_changes(bool backup)
- // {
- // if (backup)
- // m_other_changes_backup = false;
- // else
- // m_other_changes = false;
- // }
- //
- // bool has_other_changes(bool backup)
- // {
- // return backup ? m_other_changes_backup : m_other_changes;
- // }
- //
- //private:
- // enum TaskType {
- // None,
- // Backup, // this task is working as response in ui thread
- // AddObject,
- // RemoveObject,
- // RemoveBackup,
- // Exit
- // };
- // struct Task {
- // TaskType type;
- // size_t id = 0;
- // std::string path;
- // ModelObject* object = nullptr;
- // union {
- // size_t delay = 0; // delay sequence, only last task is delayed
- // size_t sequence;
- // bool removeAll;
- // };
- // friend bool operator==(Task const& l, Task const& r) {
- // return l.type == r.type && l.id == r.id;
- // }
- // std::string to_string() const {
- // constexpr char const *type_names[] = {"None",
- // "Backup",
- // "AddObject",
- // "RemoveObject",
- // "RemoveBackup",
- // "Exit"};
- // std::ostringstream os;
- // os << "{ type:" << type_names[type] << ", id:" << id
- // << ", path:" << path
- // << ", object:" << (object ? object->id().id : 0) << ", extra:" << delay << "}";
- // return os.str();
- // }
- // };
- //
- // struct timer {
- // timer(char const * msg) : msg(msg), start(boost::posix_time::microsec_clock::universal_time()) { }
- // ~timer() {
- //#ifdef __WIN32__
- // auto end = boost::posix_time::microsec_clock::universal_time();
- // int duration = (int)(end - start).total_milliseconds();
- // char buf[20];
- // OutputDebugStringA(msg);
- // OutputDebugStringA(": ");
- // OutputDebugStringA(itoa(duration, buf, 10));
- // OutputDebugStringA("\n");
- //#endif
- // }
- // char const* msg;
- // boost::posix_time::ptime start;
- // };
- //private:
- // _BBS_Backup_Manager() {
- // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " inital and interval = " << m_interval;
- // m_next_backup = boost::get_system_time() + boost::posix_time::seconds(m_interval);
- // boost::unique_lock lock(m_mutex);
- // m_thread = std::move(boost::thread(boost::ref(*this)));
- // }
- //
- // ~_BBS_Backup_Manager() {
- // push_task({Exit});
- // m_thread.join();
- // }
- //
- // void push_task(Task const & t) {
- // boost::unique_lock lock(m_mutex);
- // if (t.delay && !m_tasks.empty() && m_tasks.back() == t) {
- // auto t2 = m_tasks.back();
- // m_tasks.back() = t;
- // m_tasks.back().delay = t2.delay + 1;
- // m_cond.notify_all();
- // lock.unlock();
- // process_ui_task(t2);
- // }
- // else {
- // m_tasks.push_back(t);
- // ++m_task_seq;
- // m_cond.notify_all();
- // }
- // }
- //
- // void process_ui_task(Task& t, bool canceled = false) {
- // BOOST_LOG_TRIVIAL(info) << "process_ui_task" << t.to_string() << " and interval = " << m_interval;
- // switch (t.type) {
- // case Backup: {
- // if (canceled)
- // break;
- // std::function<void(int)> callback;
- // boost::unique_lock lock(m_mutex);
- // if (m_task_seq != t.sequence) {
- // if (find(m_tasks.begin(), m_tasks.end(), Task{ Backup }) == m_tasks.end()) {
- // t.sequence = ++m_task_seq; // may has pending tasks, retry later
- // m_tasks.push_back(t);
- // m_cond.notify_all();
- // }
- // break;
- // }
- // callback = m_post_callback;
- // lock.unlock();
- // {
- // timer t("backup cost");
- // try {
- // if (callback) callback(1);
- // } catch (...) {}
- // }
- // m_other_changes_backup = false;
- // break;
- // }
- // case AddObject:
- // m_temp_model.delete_object(t.object);
- // break;
- // case RemoveBackup:
- // if (t.removeAll) {
- // try {
- // boost::filesystem::remove(t.path + "/lock.txt");
- // boost::filesystem::remove_all(t.path);
- // BOOST_LOG_TRIVIAL(info) << "process_ui_task: remove all of backup path " << t.path;
- // } catch (std::exception &ex) {
- // BOOST_LOG_TRIVIAL(error) << "process_ui_task: failed to remove backup path" << t.path << ": " << ex.what();
- // }
- // }
- // break;
- // }
- // }
- //
- // void process_task(Task& t) {
- // BOOST_LOG_TRIVIAL(info) << "process_task" << t.to_string() << " and interval = " << m_interval;
- // switch (t.type) {
- // case Backup:
- // // do it in response
- // break;
- // case AddObject: {
- // {
- // CNumericLocalesSetter locales_setter;
- // _BBS_3MF_Exporter e;
- // e.save_object_mesh(t.path, *t.object, (int) t.id);
- // // response to delete cloned object
- // }
- // break;
- // }
- // case RemoveObject: {
- // boost::system::error_code ec;
- // boost::filesystem::remove(t.path + "/mesh_" + boost::lexical_cast<std::string>(t.id) + ".xml", ec);
- // t.type = None;
- // break;
- // }
- // case RemoveBackup: {
- // try {
- // boost::system::error_code ec;
- // boost::filesystem::remove(t.path + "/.3mf", ec);
- // // We Saved with SplitModel now, so we can safe delete these sub models.
- // boost::filesystem::remove_all(t.path + "/3D/Objects");
- // boost::filesystem::create_directory(t.path + "/3D/Objects");
- // }
- // catch (...) {}
- // }
- // }
- // }
- //
- //public:
- // void operator()() {
- // boost::unique_lock lock(m_mutex);
- // while (true)
- // {
- // while (m_tasks.empty()) {
- // if (m_interval > 0)
- // m_cond.timed_wait(lock, m_next_backup);
- // else
- // m_cond.wait(lock);
- // if (m_interval > 0 && boost::get_system_time() > m_next_backup) {
- // m_tasks.push_back({ Backup, 0, std::string(), nullptr, ++m_task_seq });
- // m_next_backup += boost::posix_time::seconds(m_interval);
- // // Maybe wakeup from power sleep
- // if (m_next_backup < boost::get_system_time())
- // m_next_backup = boost::get_system_time() + boost::posix_time::seconds(m_interval);
- // }
- // }
- // Task t = m_tasks.front();
- // if (t.type == Exit) break;
- // if (t.object && t.delay) {
- // if (!delay_task(t, lock))
- // continue;
- // }
- // m_tasks.pop_front();
- // auto callback = m_post_callback;
- // lock.unlock();
- // process_task(t);
- // lock.lock();
- // if (t.type > None) {
- // m_ui_tasks.push_back(t);
- // if (m_ui_tasks.size() == 1 && callback)
- // callback(0);
- // }
- // }
- // }
- //
- // bool delay_task(Task& t, boost::unique_lock<boost::mutex> & lock) {
- // // delay last task for 3 seconds after last modify
- // auto now = boost::get_system_time();
- // auto delay_expire = now + boost::posix_time::seconds(10); // must not delay over this time
- // auto wait = now + boost::posix_time::seconds(3);
- // while (true) {
- // m_cond.timed_wait(lock, wait);
- // // Only delay when it's the only-one task
- // if (m_tasks.size() != 1 || m_tasks.front().delay == t.delay)
- // break;
- // t.delay = m_tasks.front().delay;
- // now = boost::get_system_time();
- // if (now >= delay_expire)
- // break;
- // wait = now + boost::posix_time::seconds(3);
- // if (wait > delay_expire)
- // wait = delay_expire;
- // };
- // // task maybe canceled
- // if (m_tasks.empty())
- // return false;
- // t = m_tasks.front();
- // return true;
- // }
- //
- //private:
- // boost::mutex m_mutex;
- // boost::condition_variable m_cond;
- // std::deque<Task> m_tasks;
- // std::deque<Task> m_ui_tasks;
- // size_t m_task_seq = 0;
- // // param 0: should call run_ui_tasks
- // // param 1: should backup current project
- // std::function<void(int)> m_post_callback;
- // long m_interval = 1 * 60;
- // boost::system_time m_next_backup;
- // Model m_temp_model; // visit only in main thread
- // bool m_other_changes = false; // visit only in main thread
- // bool m_other_changes_backup = false; // visit only in main thread
- // std::vector<std::pair<ModelObject*, size_t>> m_gaurd_objects;
- // boost::thread m_thread;
- //};
- //
- //
- ////BBS: add plate data list related logic
- bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector<Preset*>* project_presets,
- bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn, LoadStrategy strategy, /*BBLProject *project,*/ int plate_id)
- {
- if (path == nullptr || config == nullptr || model == nullptr)
- return false;
- // All import should use "C" locales for number formatting.
- CNumericLocalesSetter locales_setter;
- _BBS_3MF_Importer importer;
- bool res = importer.load_model_from_file(path, *model, *plate_data_list, *project_presets, *config, *config_substitutions, strategy, *is_bbl_3mf, *file_version, proFn, /*project,*/ plate_id);
- importer.log_errors();
- //BBS: remove legacy project logic currently
- //handle_legacy_project_loaded(importer.version(), *config);
- return res;
- }
- //
- //std::string bbs_3mf_get_thumbnail(const char *path)
- //{
- // _BBS_3MF_Importer importer;
- // std::string data;
- // bool res = importer.get_thumbnail(path, data);
- // if (!res) importer.log_errors();
- // return data;
- //}
- //
- //bool load_gcode_3mf_from_stream(std::istream &data, DynamicPrintConfig *config, Model *model, PlateDataPtrs *plate_data_list, Semver *file_version)
- //{
- // CNumericLocalesSetter locales_setter;
- // _BBS_3MF_Importer importer;
- // bool res = importer.load_gcode_3mf_from_stream(data, *model, *plate_data_list, *config, *file_version);
- // importer.log_errors();
- // return res;
- //}
- //
- //bool store_bbs_3mf(StoreParams& store_params)
- //{
- // // All export should use "C" locales for number formatting.
- // CNumericLocalesSetter locales_setter;
- //
- // if (store_params.path == nullptr || store_params.model == nullptr)
- // return false;
- //
- // _BBS_3MF_Exporter exporter;
- // bool res = exporter.save_model_to_file(store_params);
- // if (!res)
- // exporter.log_errors();
- //
- // return res;
- //}
- //
- ////BBS: release plate data list
- //void release_PlateData_list(PlateDataPtrs& plate_data_list)
- //{
- // //clear
- // for (unsigned int i = 0; i < plate_data_list.size(); i++)
- // {
- // delete plate_data_list[i];
- // }
- // plate_data_list.clear();
- //
- // return;
- //}
- //
- //// backup interface
- //
- //void save_object_mesh(ModelObject& object)
- //{
- // if (!object.get_model() || !object.get_model()->is_need_backup())
- // return;
- // if (object.volumes.empty() || object.instances.empty())
- // return;
- // _BBS_Backup_Manager::get().add_object_mesh(object);
- //}
- //
- //void delete_object_mesh(ModelObject& object)
- //{
- // // not really remove
- // // _BBS_Backup_Manager::get().remove_object_mesh(object);
- //}
- //
- //void backup_soon()
- //{
- // _BBS_Backup_Manager::get().backup_soon();
- //}
- //
- //void remove_backup(Model& model, bool removeAll)
- //{
- // _BBS_Backup_Manager::get().remove_backup(model, removeAll);
- //}
- //
- //void set_backup_interval(long interval)
- //{
- // _BBS_Backup_Manager::get().set_interval(interval);
- //}
- //
- //void set_backup_callback(std::function<void(int)> callback)
- //{
- // _BBS_Backup_Manager::get().set_post_callback(callback);
- //}
- //
- //void run_backup_ui_tasks()
- //{
- // _BBS_Backup_Manager::get().run_ui_tasks();
- //}
- //
- //bool has_restore_data(std::string & path, std::string& origin)
- //{
- // if (path.empty()) {
- // origin = "<lock>";
- // return false;
- // }
- // if (boost::filesystem::exists(path + "/lock.txt")) {
- // std::string pid;
- // load_string_file(path + "/lock.txt", pid);
- // try {
- // if (get_process_name(boost::lexical_cast<int>(pid)) ==
- // get_process_name(0)) {
- // origin = "<lock>";
- // return false;
- // }
- // }
- // catch (...) {
- // return false;
- // }
- // }
- // std::string file3mf = path + "/.3mf";
- // if (!boost::filesystem::exists(file3mf))
- // return false;
- // try {
- // if (boost::filesystem::exists(path + "/origin.txt"))
- // load_string_file(path + "/origin.txt", origin);
- // }
- // catch (...) {
- // }
- // path = file3mf;
- // return true;
- //}
- //
- //void put_other_changes()
- //{
- // _BBS_Backup_Manager::get().put_other_changes();
- //}
- //
- //void clear_other_changes(bool backup)
- //{
- // _BBS_Backup_Manager::get().clear_other_changes(backup);
- //}
- //
- //bool has_other_changes(bool backup)
- //{
- // return _BBS_Backup_Manager::get().has_other_changes(backup);
- //}
- //
- //SaveObjectGaurd::SaveObjectGaurd(ModelObject& object)
- //{
- // _BBS_Backup_Manager::get().push_object_gaurd(object);
- //}
- //
- //SaveObjectGaurd::~SaveObjectGaurd()
- //{
- // _BBS_Backup_Manager::get().pop_object_gaurd();
- //}
- //
- //namespace{
- //
- //// Conversion with bidirectional map
- //// F .. first, S .. second
- //template<typename F, typename S>
- //F bimap_cvt(const boost::bimap<F, S> &bmap, S s, const F & def_value) {
- // const auto &map = bmap.right;
- // auto found_item = map.find(s);
- //
- // // only for back and forward compatibility
- // assert(found_item != map.end());
- // if (found_item == map.end())
- // return def_value;
- //
- // return found_item->second;
- //}
- //
- //template<typename F, typename S>
- //S bimap_cvt(const boost::bimap<F, S> &bmap, F f, const S &def_value)
- //{
- // const auto &map = bmap.left;
- // auto found_item = map.find(f);
- //
- // // only for back and forward compatibility
- // assert(found_item != map.end());
- // if (found_item == map.end())
- // return def_value;
- //
- // return found_item->second;
- //}
- //
- //} // namespace
- /// <summary>
- /// TextConfiguration serialization //Susi_not_impl
- /// </summary>
- //const TextConfigurationSerialization::TypeToName TextConfigurationSerialization::type_to_name =
- // boost::assign::list_of<TypeToName::relation>
- // (EmbossStyle::Type::file_path, "file_name")
- // (EmbossStyle::Type::wx_win_font_descr, "wxFontDescriptor_Windows")
- // (EmbossStyle::Type::wx_lin_font_descr, "wxFontDescriptor_Linux")
- // (EmbossStyle::Type::wx_mac_font_descr, "wxFontDescriptor_MacOsX");
- //
- //const TextConfigurationSerialization::HorizontalAlignToName TextConfigurationSerialization::horizontal_align_to_name =
- // boost::assign::list_of<HorizontalAlignToName::relation>
- // (FontProp::HorizontalAlign::left, "left")
- // (FontProp::HorizontalAlign::center, "center")
- // (FontProp::HorizontalAlign::right, "right");
- //
- //const TextConfigurationSerialization::VerticalAlignToName TextConfigurationSerialization::vertical_align_to_name =
- // boost::assign::list_of<VerticalAlignToName::relation>
- // (FontProp::VerticalAlign::top, "top")
- // (FontProp::VerticalAlign::center, "middle")
- // (FontProp::VerticalAlign::bottom, "bottom");
- //
- //void TextConfigurationSerialization::to_xml(std::stringstream &stream, const TextConfiguration &tc)
- //{
- // stream << " <" << TEXT_TAG << " ";
- //
- // stream << TEXT_DATA_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(tc.text) << "\" ";
- // // font item
- // const EmbossStyle &style = tc.style;
- // stream << STYLE_NAME_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(style.name) << "\" ";
- // stream << FONT_DESCRIPTOR_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(style.path) << "\" ";
- // constexpr std::string_view dafault_type{"undefined"};
- // std::string_view style_type = bimap_cvt(type_to_name, style.type, dafault_type);
- // stream << FONT_DESCRIPTOR_TYPE_ATTR << "=\"" << style_type << "\" ";
- //
- // // font property
- // const FontProp &fp = tc.style.prop;
- // if (fp.char_gap.has_value())
- // stream << CHAR_GAP_ATTR << "=\"" << *fp.char_gap << "\" ";
- // if (fp.line_gap.has_value())
- // stream << LINE_GAP_ATTR << "=\"" << *fp.line_gap << "\" ";
- //
- // stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" ";
- // if (fp.boldness.has_value())
- // stream << BOLDNESS_ATTR << "=\"" << *fp.boldness << "\" ";
- // if (fp.skew.has_value())
- // stream << SKEW_ATTR << "=\"" << *fp.skew << "\" ";
- // if (fp.per_glyph)
- // stream << PER_GLYPH_ATTR << "=\"" << 1 << "\" ";
- // stream << HORIZONTAL_ALIGN_ATTR << "=\"" << bimap_cvt(horizontal_align_to_name, fp.align.first, dafault_type) << "\" ";
- // stream << VERTICAL_ALIGN_ATTR << "=\"" << bimap_cvt(vertical_align_to_name, fp.align.second, dafault_type) << "\" ";
- // if (fp.collection_number.has_value())
- // stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
- // // font descriptor
- // if (fp.family.has_value())
- // stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
- // if (fp.face_name.has_value())
- // stream << FONT_FACE_NAME_ATTR << "=\"" << *fp.face_name << "\" ";
- // if (fp.style.has_value())
- // stream << FONT_STYLE_ATTR << "=\"" << *fp.style << "\" ";
- // if (fp.weight.has_value())
- // stream << FONT_WEIGHT_ATTR << "=\"" << *fp.weight << "\" ";
- //
- // stream << "/>\n"; // end TEXT_TAG
- //}
- //namespace {
- //
- //FontProp::HorizontalAlign read_horizontal_align(const char **attributes, unsigned int num_attributes, const TextConfigurationSerialization::HorizontalAlignToName& horizontal_align_to_name){
- // std::string horizontal_align_str = bbs_get_attribute_value_string(attributes, num_attributes, HORIZONTAL_ALIGN_ATTR);
- //
- // // Back compatibility
- // // PS 2.6.0 do not have align
- // if (horizontal_align_str.empty())
- // return FontProp::HorizontalAlign::center;
- //
- // // Back compatibility
- // // PS 2.6.1 store indices(0|1|2) instead of text for align
- // if (horizontal_align_str.length() == 1) {
- // int horizontal_align_int = 0;
- // if(boost::spirit::qi::parse(horizontal_align_str.c_str(), horizontal_align_str.c_str() + 1, boost::spirit::qi::int_, horizontal_align_int))
- // return static_cast<FontProp::HorizontalAlign>(horizontal_align_int);
- // }
- //
- // return bimap_cvt(horizontal_align_to_name, std::string_view(horizontal_align_str), FontProp::HorizontalAlign::center);
- //}
- //
- //
- //FontProp::VerticalAlign read_vertical_align(const char **attributes, unsigned int num_attributes, const TextConfigurationSerialization::VerticalAlignToName& vertical_align_to_name){
- // std::string vertical_align_str = bbs_get_attribute_value_string(attributes, num_attributes, VERTICAL_ALIGN_ATTR);
- //
- // // Back compatibility
- // // PS 2.6.0 do not have align
- // if (vertical_align_str.empty())
- // return FontProp::VerticalAlign::center;
- //
- // // Back compatibility
- // // PS 2.6.1 store indices(0|1|2) instead of text for align
- // if (vertical_align_str.length() == 1) {
- // int vertical_align_int = 0;
- // if(boost::spirit::qi::parse(vertical_align_str.c_str(), vertical_align_str.c_str() + 1, boost::spirit::qi::int_, vertical_align_int))
- // return static_cast<FontProp::VerticalAlign>(vertical_align_int);
- // }
- //
- // return bimap_cvt(vertical_align_to_name, std::string_view(vertical_align_str), FontProp::VerticalAlign::center);
- //}
- //
- //} // namespace
- //
- //std::optional<TextConfiguration> TextConfigurationSerialization::read(const char **attributes, unsigned int num_attributes)
- //{
- // FontProp fp;
- // int char_gap = bbs_get_attribute_value_int(attributes, num_attributes, CHAR_GAP_ATTR);
- // if (char_gap != 0) fp.char_gap = char_gap;
- // int line_gap = bbs_get_attribute_value_int(attributes, num_attributes, LINE_GAP_ATTR);
- // if (line_gap != 0) fp.line_gap = line_gap;
- // float boldness = bbs_get_attribute_value_float(attributes, num_attributes, BOLDNESS_ATTR);
- // if (std::fabs(boldness) > std::numeric_limits<float>::epsilon())
- // fp.boldness = boldness;
- // float skew = bbs_get_attribute_value_float(attributes, num_attributes, SKEW_ATTR);
- // if (std::fabs(skew) > std::numeric_limits<float>::epsilon())
- // fp.skew = skew;
- // int per_glyph = bbs_get_attribute_value_int(attributes, num_attributes, PER_GLYPH_ATTR);
- // if (per_glyph == 1) fp.per_glyph = true;
- //
- // fp.align = FontProp::Align(
- // read_horizontal_align(attributes, num_attributes, horizontal_align_to_name),
- // read_vertical_align(attributes, num_attributes, vertical_align_to_name));
- //
- // int collection_number = bbs_get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
- // if (collection_number > 0) fp.collection_number = static_cast<unsigned int>(collection_number);
- //
- // fp.size_in_mm = bbs_get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
- //
- // std::string family = bbs_get_attribute_value_string(attributes, num_attributes, FONT_FAMILY_ATTR);
- // if (!family.empty()) fp.family = family;
- // std::string face_name = bbs_get_attribute_value_string(attributes, num_attributes, FONT_FACE_NAME_ATTR);
- // if (!face_name.empty()) fp.face_name = face_name;
- // std::string style = bbs_get_attribute_value_string(attributes, num_attributes, FONT_STYLE_ATTR);
- // if (!style.empty()) fp.style = style;
- // std::string weight = bbs_get_attribute_value_string(attributes, num_attributes, FONT_WEIGHT_ATTR);
- // if (!weight.empty()) fp.weight = weight;
- //
- // std::string style_name = bbs_get_attribute_value_string(attributes, num_attributes, STYLE_NAME_ATTR);
- // std::string font_descriptor = bbs_get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR);
- // std::string type_str = bbs_get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_TYPE_ATTR);
- // EmbossStyle::Type type = bimap_cvt(type_to_name, std::string_view{type_str}, EmbossStyle::Type::undefined);
- //
- // std::string text = bbs_get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR);
- // EmbossStyle es{style_name, std::move(font_descriptor), type, std::move(fp)};
- // return TextConfiguration{std::move(es), std::move(text)};
- //}
- //
- //EmbossShape TextConfigurationSerialization::read_old(const char **attributes, unsigned int num_attributes)
- //{
- // EmbossShape es;
- // std::string fix_tr_mat_str = bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
- // if (!fix_tr_mat_str.empty())
- // es.fix_3mf_tr = bbs_get_transform_from_3mf_specs_string(fix_tr_mat_str);
- //
- //
- // if (bbs_get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR) == 1)
- // es.projection.use_surface = true;
- //
- // es.projection.depth = bbs_get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
- //
- // int use_surface = bbs_get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
- // if (use_surface == 1)
- // es.projection.use_surface = true;
- //
- // return es;
- //}
- //
- //namespace {
- //Transform3d create_fix(const std::optional<Transform3d> &prev, const ModelVolume &volume)
- //{
- // // IMPROVE: check if volume was modified (translated, rotated OR scaled)
- // // when no change do not calculate transformation only store original fix matrix
- //
- // // Create transformation used after load actual stored volume
- // // Orca: do not bake volume transformation into meshes
- // // const Transform3d &actual_trmat = volume.get_matrix();
- // const Transform3d& actual_trmat = Transform3d::Identity();
- //
- // const auto &vertices = volume.mesh().its.vertices;
- // Vec3d min = actual_trmat * vertices.front().cast<double>();
- // Vec3d max = min;
- // for (const Vec3f &v : vertices) {
- // Vec3d vd = actual_trmat * v.cast<double>();
- // for (size_t i = 0; i < 3; ++i) {
- // if (min[i] > vd[i])
- // min[i] = vd[i];
- // if (max[i] < vd[i])
- // max[i] = vd[i];
- // }
- // }
- // Vec3d center = (max + min) / 2;
- // Transform3d post_trmat = Transform3d::Identity();
- // post_trmat.translate(center);
- //
- // Transform3d fix_trmat = actual_trmat.inverse() * post_trmat;
- // if (!prev.has_value())
- // return fix_trmat;
- //
- // // check whether fix somehow differ previous
- // if (fix_trmat.isApprox(Transform3d::Identity(), 1e-5))
- // return *prev;
- //
- // return *prev * fix_trmat;
- //}
- //
- //bool to_xml(std::stringstream &stream, /*const EmbossShape::SvgFile &svg, */const ModelVolume &volume, mz_zip_archive &archive){
- // if (svg.path_in_3mf.empty())
- // return true; // EmbossedText OR unwanted store .svg file into .3mf (protection of copyRight)
- //
- // if (!svg.path.empty())
- // stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path) << "\" ";
- // stream << SVG_FILE_PATH_IN_3MF_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path_in_3mf) << "\" ";
- //
- // std::shared_ptr<std::string> file_data = svg.file_data;
- // assert(file_data != nullptr);
- // if (file_data == nullptr && !svg.path.empty())
- // file_data = read_from_disk(svg.path);
- // if (file_data == nullptr) {
- // BOOST_LOG_TRIVIAL(warning) << "Can't write svg file no filedata";
- // return false;
- // }
- // const std::string &file_data_str = *file_data;
- //
- // return mz_zip_writer_add_mem(&archive, svg.path_in_3mf.c_str(),
- // (const void *) file_data_str.c_str(), file_data_str.size(), MZ_DEFAULT_COMPRESSION);
- //}
- //
- //} // namespace
- //
- //void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive)
- //{
- // stream << " <" << SHAPE_TAG << " ";
- // if (es.svg_file.has_value())
- // if(!to_xml(stream, *es.svg_file, volume, archive))
- // BOOST_LOG_TRIVIAL(warning) << "Can't write svg file defiden embossed shape into 3mf";
- //
- // stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" ";
- //
- // if (!es.final_shape.is_healed)
- // stream << UNHEALED_ATTR << "=\"" << 1 << "\" ";
- //
- // // projection
- // const EmbossProjection &p = es.projection;
- // stream << DEPTH_ATTR << "=\"" << p.depth << "\" ";
- // if (p.use_surface)
- // stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
- //
- // // FIX of baked transformation
- // Transform3d fix = create_fix(es.fix_3mf_tr, volume);
- // stream << TRANSFORM_ATTR << "=\"";
- // _BBS_3MF_Exporter::add_transformation(stream, fix);
- // stream << "\" ";
- //
- // stream << "/>\n"; // end SHAPE_TAG
- //}
- //
- //std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes) {
- // double scale = bbs_get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
- // int unhealed = bbs_get_attribute_value_int(attributes, num_attributes, UNHEALED_ATTR);
- // bool is_healed = unhealed != 1;
- //
- // EmbossProjection projection;
- // projection.depth = bbs_get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
- // if (is_approx(projection.depth, 0.))
- // projection.depth = 10.;
- //
- // int use_surface = bbs_get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
- // if (use_surface == 1)
- // projection.use_surface = true;
- //
- // std::optional<Transform3d> fix_tr_mat;
- // std::string fix_tr_mat_str = bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
- // if (!fix_tr_mat_str.empty()) {
- // fix_tr_mat = bbs_get_transform_from_3mf_specs_string(fix_tr_mat_str);
- // }
- //
- // std::string file_path = bbs_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR);
- // std::string file_path_3mf = bbs_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_IN_3MF_ATTR);
- //
- // // MayBe: store also shapes to not store svg
- // // But be carefull curve will be lost -> scale will not change sampling
- // // shapes could be loaded from SVG
- // ExPolygonsWithIds shapes;
- // // final shape could be calculated from shapes
- // HealedExPolygons final_shape;
- // final_shape.is_healed = is_healed;
- //
- // EmbossShape::SvgFile svg{file_path, file_path_3mf};
- // return EmbossShape{std::move(shapes), std::move(final_shape), scale, std::move(projection), std::move(fix_tr_mat), std::move(svg)};
- //}
- } // namespace Slic3r
|