PrintObject.cpp 253 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469
  1. ///|/ Copyright (c) Prusa Research 2016 - 2023 Lukáš Hejl @hejllukas, Pavel Mikuš @Godrak, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, David Kocík @kocikdav, Roman Beránek @zavorka
  2. ///|/ Copyright (c) 2021 Justin Schuh @jschuh
  3. ///|/ Copyright (c) 2021 Ilya @xorza
  4. ///|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens
  5. ///|/ Copyright (c) Slic3r 2014 - 2016 Alessandro Ranellucci @alranel
  6. ///|/ Copyright (c) 2015 Maksim Derbasov @ntfshard
  7. ///|/
  8. ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
  9. ///|/
  10. #include "AABBTreeLines.hpp"
  11. #include "BridgeDetector.hpp"
  12. #include "ExPolygon.hpp"
  13. #include "Exception.hpp"
  14. #include "Flow.hpp"
  15. #include "GCode/ExtrusionProcessor.hpp"
  16. #include "KDTreeIndirect.hpp"
  17. #include "Line.hpp"
  18. #include "Point.hpp"
  19. #include "Polygon.hpp"
  20. #include "Polyline.hpp"
  21. #include "Print.hpp"
  22. #include "BoundingBox.hpp"
  23. #include "ClipperUtils.hpp"
  24. #include "ElephantFootCompensation.hpp"
  25. #include "Geometry.hpp"
  26. #include "I18N.hpp"
  27. #include "Layer.hpp"
  28. #include "MutablePolygon.hpp"
  29. #include "PrintBase.hpp"
  30. #include "PrintConfig.hpp"
  31. #include "Support/SupportMaterial.hpp"
  32. #include "Support/TreeSupport.hpp"
  33. #include "Surface.hpp"
  34. #include "Slicing.hpp"
  35. #include "SurfaceCollection.hpp"
  36. #include "Tesselate.hpp"
  37. #include "Thread.hpp"
  38. #include "TriangleMeshSlicer.hpp"
  39. #include "Utils.hpp"
  40. #include "Fill/FillAdaptive.hpp"
  41. #include "Fill/FillLightning.hpp"
  42. #include "Format/STL.hpp"
  43. #include "Support/SupportMaterial.hpp"
  44. #include "SupportSpotsGenerator.hpp"
  45. #include "TriangleSelectorWrapper.hpp"
  46. #include "format.hpp"
  47. #include "libslic3r.h"
  48. #include <algorithm>
  49. #include <atomic>
  50. #include <cmath>
  51. #include <cstddef>
  52. #include <cstdint>
  53. #include <float.h>
  54. #include <functional>
  55. #include <limits>
  56. #include <map>
  57. #include <oneapi/tbb/blocked_range.h>
  58. #include <oneapi/tbb/concurrent_vector.h>
  59. #include <oneapi/tbb/parallel_for.h>
  60. #include <string>
  61. #include <string_view>
  62. #include <tuple>
  63. #include <unordered_map>
  64. #include <unordered_set>
  65. #include <utility>
  66. #include <boost/log/trivial.hpp>
  67. #include <tbb/parallel_for.h>
  68. #include <vector>
  69. using namespace std::literals;
  70. // #define PRINT_OBJECT_TIMING
  71. #ifdef PRINT_OBJECT_TIMING
  72. // time limit for one ClipperLib operation (union / diff / offset), in ms
  73. #define PRINT_OBJECT_TIME_LIMIT_DEFAULT 50
  74. #include <boost/current_function.hpp>
  75. #include "Timer.hpp"
  76. #define PRINT_OBJECT_TIME_LIMIT_SECONDS(limit) Timing::TimeLimitAlarm time_limit_alarm(uint64_t(limit) * 1000000000l, BOOST_CURRENT_FUNCTION)
  77. #define PRINT_OBJECT_TIME_LIMIT_MILLIS(limit) Timing::TimeLimitAlarm time_limit_alarm(uint64_t(limit) * 1000000l, BOOST_CURRENT_FUNCTION)
  78. #else
  79. #define PRINT_OBJECT_TIME_LIMIT_SECONDS(limit) do {} while(false)
  80. #define PRINT_OBJECT_TIME_LIMIT_MILLIS(limit) do {} while(false)
  81. #endif // PRINT_OBJECT_TIMING
  82. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  83. #define SLIC3R_DEBUG
  84. #endif
  85. // #define SLIC3R_DEBUG
  86. // Make assert active if SLIC3R_DEBUG
  87. #ifdef SLIC3R_DEBUG
  88. #undef NDEBUG
  89. #define DEBUG
  90. #define _DEBUG
  91. #include "SVG.hpp"
  92. #undef assert
  93. #include <cassert>
  94. #endif
  95. #include "SVG.hpp"
  96. namespace Slic3r {
  97. // Constructor is called from the main thread, therefore all Model / ModelObject / ModelIntance data are valid.
  98. PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances) :
  99. PrintObjectBaseWithState(print, model_object),
  100. m_trafo(trafo)
  101. {
  102. // Compute centering offet to be applied to our meshes so that we work with smaller coordinates
  103. // requiring less bits to represent Clipper coordinates.
  104. // Snug bounding box of a rotated and scaled object by the 1st instantion, without the instance translation applied.
  105. // All the instances share the transformation matrix with the exception of translation in XY and rotation by Z,
  106. // therefore a bounding box from 1st instance of a ModelObject is good enough for calculating the object center,
  107. // snug height and an approximate bounding box in XY.
  108. BoundingBoxf3 bbox = model_object->raw_bounding_box();
  109. Vec3d bbox_center = bbox.center();
  110. // We may need to rotate the bbox / bbox_center from the original instance to the current instance.
  111. double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_matrix(), instances.front().model_instance->get_matrix());
  112. if (std::abs(z_diff) > EPSILON) {
  113. auto z_rot = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ());
  114. bbox = bbox.transformed(Transform3d(z_rot));
  115. bbox_center = (z_rot * bbox_center).eval();
  116. }
  117. // Center of the transformed mesh (without translation).
  118. m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
  119. // Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
  120. m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
  121. m_size.z() = coord_t(model_object->max_z() * (1. / SCALING_FACTOR));
  122. this->set_instances(std::move(instances));
  123. //create config hierarchy
  124. m_config.parent = &print->config();
  125. }
  126. PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances&& instances)
  127. {
  128. for (PrintInstance& i : instances)
  129. // Add the center offset, which will be subtracted from the mesh when slicing.
  130. i.shift += m_center_offset;
  131. // Invalidate and set copies.
  132. PrintBase::ApplyStatus status = PrintBase::APPLY_STATUS_UNCHANGED;
  133. bool equal_length = instances.size() == m_instances.size();
  134. bool equal = equal_length && std::equal(instances.begin(), instances.end(), m_instances.begin(),
  135. [](const PrintInstance& lhs, const PrintInstance& rhs) { return lhs.model_instance == rhs.model_instance && lhs.shift == rhs.shift; });
  136. if (! equal) {
  137. status = PrintBase::APPLY_STATUS_CHANGED;
  138. if (m_print->invalidate_steps({ psSkirtBrim, psGCodeExport }) ||
  139. (! equal_length && m_print->invalidate_step(psWipeTower)))
  140. status = PrintBase::APPLY_STATUS_INVALIDATED;
  141. m_instances = std::move(instances);
  142. for (PrintInstance &i : m_instances)
  143. i.print_object = this;
  144. }
  145. return status;
  146. }
  147. std::vector<std::reference_wrapper<const PrintRegion>> PrintObject::all_regions() const
  148. {
  149. std::vector<std::reference_wrapper<const PrintRegion>> out;
  150. out.reserve(m_shared_regions->all_regions.size());
  151. for (const std::unique_ptr<Slic3r::PrintRegion> &region : m_shared_regions->all_regions)
  152. out.emplace_back(*region.get());
  153. return out;
  154. }
  155. // 1) Merges typed region slices into stInternal type.
  156. // 2) Increases an "extra perimeters" counter at region slices where needed.
  157. // 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
  158. void PrintObject::make_perimeters()
  159. {
  160. // prerequisites
  161. this->slice();
  162. if (! this->set_started(posPerimeters))
  163. return;
  164. m_print->set_status(objectstep_2_percent[PrintObjectStep::posPerimeters], _u8L("Generating perimeters"));
  165. m_print->secondary_status_counter_add_max(m_layers.size());
  166. BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
  167. // Revert the typed slices into untyped slices.
  168. if (m_typed_slices) {
  169. for (Layer *layer : m_layers) {
  170. layer->clear_fills();
  171. layer->restore_untyped_slices();
  172. m_print->throw_if_canceled();
  173. }
  174. m_typed_slices = false;
  175. }
  176. // compare each layer to the one below, and mark those slices needing
  177. // one additional inner perimeter, like the top of domed objects-
  178. // this algorithm makes sure that at least one perimeter is overlapping
  179. // but we don't generate any extra perimeter if fill density is zero, as they would be floating
  180. // inside the object - infill_only_where_needed should be the method of choice for printing
  181. // hollow objects
  182. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  183. const PrintRegion &region = this->printing_region(region_id);
  184. if (!region.config().extra_perimeters || region.config().perimeters == 0 ||
  185. region.config().fill_density == 0 || this->layer_count() < 2) {
  186. continue;
  187. }
  188. // use an antomic idx instead of the range, to avoid a thread being very late because it's on the difficult layers.
  189. BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start";
  190. Slic3r::parallel_for(size_t(0), m_layers.size() - 1,
  191. [this, &region, region_id](const size_t layer_idx) {
  192. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  193. m_print->throw_if_canceled();
  194. LayerRegion &layerm = *m_layers[layer_idx]->get_region(region_id);
  195. const LayerRegion &upper_layerm = *m_layers[layer_idx+1]->get_region(region_id);
  196. const Polygons upper_layerm_polygons = to_polygons(upper_layerm.slices().surfaces);
  197. // Filter upper layer polygons in intersection_ppl by their bounding boxes?
  198. // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
  199. const double total_loop_length = total_length(upper_layerm_polygons);
  200. const coord_t perimeter_spacing = layerm.flow(frPerimeter).scaled_spacing();
  201. const Flow ext_perimeter_flow = layerm.flow(frExternalPerimeter);
  202. const coord_t ext_perimeter_width = ext_perimeter_flow.scaled_width();
  203. const coord_t ext_perimeter_spacing = ext_perimeter_flow.scaled_spacing();
  204. // slice_mutable is not const because slice.extra_perimeters is being incremented.
  205. for (Surface &slice_mutable : layerm.m_slices.surfaces) {
  206. const Surface &slice = slice_mutable;
  207. for (;;) {
  208. // compute the total thickness of perimeters
  209. const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
  210. + (region.config().perimeters-1 + slice.extra_perimeters) * perimeter_spacing;
  211. // define a critical area where we don't want the upper slice to fall into
  212. // (it should either lay over our perimeters or outside this area)
  213. const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5);
  214. const Polygons critical_area = diff(
  215. offset(slice.expolygon, float(- perimeters_thickness)),
  216. offset(slice.expolygon, float(- perimeters_thickness - critical_area_depth))
  217. );
  218. // check whether a portion of the upper slices falls inside the critical area
  219. const Polylines intersection = intersection_pl(to_polylines(upper_layerm_polygons), critical_area);
  220. // only add an additional loop if at least 30% of the slice loop would benefit from it
  221. if (total_length(intersection) <= total_loop_length*0.3)
  222. break;
  223. /*
  224. if (0) {
  225. require "Slic3r/SVG.pm";
  226. Slic3r::SVG::output(
  227. "extra.svg",
  228. no_arrows => 1,
  229. expolygons => union_ex($critical_area),
  230. polylines => [ map $_->split_at_first_point, map $_->p, @{$upper_layerm->slices} ],
  231. );
  232. }
  233. */
  234. ++ slice_mutable.extra_perimeters;
  235. }
  236. #ifdef DEBUG
  237. if (slice.extra_perimeters > 0)
  238. printf(" adding %d more perimeter(s) at layer %zu\n", slice.extra_perimeters, layer_idx);
  239. #endif
  240. }
  241. }
  242. );
  243. m_print->throw_if_canceled();
  244. BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end";
  245. }
  246. BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
  247. Slic3r::parallel_for(size_t(0), m_layers.size(),
  248. [this](const size_t layer_idx) {
  249. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  250. m_print->throw_if_canceled();
  251. // updating progress
  252. int32_t nb_layers_done = m_print->secondary_status_counter_increment();
  253. m_print->set_status( int((nb_layers_done * 100) / m_print->secondary_status_counter_get_max()), L("Generating perimeters: layer %s / %s"),
  254. { std::to_string(nb_layers_done), std::to_string(m_print->secondary_status_counter_get_max()) }, PrintBase::SlicingStatus::SECONDARY_STATE);
  255. // make perimeters
  256. m_layers[layer_idx]->make_perimeters();
  257. }
  258. );
  259. m_print->throw_if_canceled();
  260. BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
  261. if (print()->config().milling_diameter.size() > 0) {
  262. BOOST_LOG_TRIVIAL(debug) << "Generating milling post-process in parallel - start";
  263. Slic3r::parallel_for(size_t(0), m_layers.size(),
  264. [this](const size_t layer_idx) {
  265. m_print->throw_if_canceled();
  266. m_layers[layer_idx]->make_milling_post_process();
  267. }
  268. );
  269. m_print->throw_if_canceled();
  270. BOOST_LOG_TRIVIAL(debug) << "Generating milling post-process in parallel - end";
  271. }
  272. this->set_done(posPerimeters);
  273. }
  274. void PrintObject::prepare_infill()
  275. {
  276. if (!this->set_started(posPrepareInfill))
  277. return;
  278. m_print->set_status(objectstep_2_percent[PrintObjectStep::posPrepareInfill], L("Preparing infill"));
  279. if (m_print->objects().size() == 1) {
  280. m_print->set_status(0, "", PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE);
  281. } else {
  282. // detect (33%) -> 25 25
  283. // prepare layers (1%) -> 5 30
  284. // discover shells (40%) -> 30 60
  285. // process externals (12%) -> 15 75
  286. // Clean surfaces (1%) -> 5 80
  287. // Put bridges over sparse infill (12%) -> 15 95
  288. // Combine infill (1%) -> 5 100
  289. m_print->secondary_status_counter_add_max(100);
  290. }
  291. if (m_typed_slices) {
  292. // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
  293. // The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells()
  294. // with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe
  295. // to reset to the untyped slices before re-runnning detect_surfaces_type().
  296. for (Layer* layer : m_layers) {
  297. layer->restore_untyped_slices_no_extra_perimeters();
  298. m_print->throw_if_canceled();
  299. }
  300. }
  301. // This will assign a type (top/bottom/internal) to $layerm->slices.
  302. // Then the classifcation of $layerm->slices is transfered onto
  303. // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
  304. // by the cummulative area of the previous $layerm->fill_surfaces.
  305. if (m_print->objects().size() == 1) {
  306. m_print->set_status(0, L("Detect surfaces types"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  307. } else {
  308. int32_t advancement_count = m_print->secondary_status_counter_increment(25);
  309. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  310. {std::to_string(advancement_count),
  311. std::to_string(m_print->secondary_status_counter_get_max())},
  312. PrintBase::SlicingStatus::SECONDARY_STATE);
  313. }
  314. this->detect_surfaces_type();
  315. m_print->throw_if_canceled();
  316. // Decide what surfaces are to be filled.
  317. // Here the stTop / stBottomBridge / stBottom infill is turned to just stInternal if zero top / bottom infill layers are configured.
  318. // Also tiny stInternal surfaces are turned to stInternalSolid.
  319. BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..." << log_memory_info();
  320. if (m_print->objects().size() > 1) {
  321. int32_t advancement_count = m_print->secondary_status_counter_increment(5);
  322. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  323. {std::to_string(advancement_count),
  324. std::to_string(m_print->secondary_status_counter_get_max())},
  325. PrintBase::SlicingStatus::SECONDARY_STATE);
  326. }
  327. for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++layer_idx) {
  328. Layer *layer = m_layers[layer_idx];
  329. if (m_print->objects().size() == 1) {
  330. m_print->set_status(int(25 + (5 * layer_idx / m_layers.size())),
  331. L("Prepare fill surfaces: layer %s / %s"),
  332. {std::to_string(layer_idx), std::to_string(m_layers.size())},
  333. PrintBase::SlicingStatus::SECONDARY_STATE);
  334. }
  335. for (auto *region : layer->m_regions) {
  336. region->prepare_fill_surfaces();
  337. m_print->throw_if_canceled();
  338. }
  339. }
  340. // Add solid fills to ensure the shell vertical thickness.
  341. if (m_print->objects().size() == 1) {
  342. m_print->set_status(30, L("Discover shells"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  343. } else {
  344. int32_t advancement_count = m_print->secondary_status_counter_increment(30);
  345. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  346. {std::to_string(advancement_count),
  347. std::to_string(m_print->secondary_status_counter_get_max())},
  348. PrintBase::SlicingStatus::SECONDARY_STATE);
  349. }
  350. this->discover_vertical_shells();
  351. m_print->throw_if_canceled();
  352. // Debugging output.
  353. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  354. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  355. for (const Layer *layer : m_layers) {
  356. LayerRegion *layerm = layer->m_regions[region_id];
  357. layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-final");
  358. layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
  359. } // for each layer
  360. } // for each region
  361. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  362. // this will detect bridges and reverse bridges
  363. // and rearrange top/bottom/internal surfaces
  364. // It produces enlarged overlapping bridging areas.
  365. //
  366. // 1) stBottomBridge / stBottom infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
  367. // 2) stTop is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
  368. // 3) Clip the internal surfaces by the grown top/bottom surfaces.
  369. // 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
  370. //FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
  371. if (m_print->objects().size() == 1) {
  372. m_print->set_status( 60, L("Process external surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  373. } else {
  374. int32_t advancement_count = m_print->secondary_status_counter_increment(15);
  375. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  376. {std::to_string(advancement_count),
  377. std::to_string(m_print->secondary_status_counter_get_max())},
  378. PrintBase::SlicingStatus::SECONDARY_STATE);
  379. }
  380. this->process_external_surfaces();
  381. m_print->throw_if_canceled();
  382. // Debugging output.
  383. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  384. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  385. for (const Layer *layer : m_layers) {
  386. LayerRegion *layerm = layer->m_regions[region_id];
  387. layerm->export_region_slices_to_svg_debug("3_process_external_surfaces-final");
  388. layerm->export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-final");
  389. } // for each layer
  390. } // for each region
  391. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  392. // Detect, which fill surfaces are near external layers.
  393. // They will be split in internal and internal-solid surfaces.
  394. // The purpose is to add a configurable number of solid layers to support the TOP surfaces
  395. // and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces
  396. // to close these surfaces reliably.
  397. //FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
  398. //note: only if not "ensure vertical shell" (which doesn't exist anymore)
  399. this->discover_horizontal_shells();
  400. m_print->throw_if_canceled();
  401. //as there is some too thin solid surface, please deleted them and merge all of the surfacesthat are contigous.
  402. if (m_print->objects().size() == 1) {
  403. m_print->set_status( 75, L("Clean surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  404. } else {
  405. int32_t advancement_count = m_print->secondary_status_counter_increment(5);
  406. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  407. {std::to_string(advancement_count),
  408. std::to_string(m_print->secondary_status_counter_get_max())},
  409. PrintBase::SlicingStatus::SECONDARY_STATE);
  410. }
  411. this->clean_surfaces();
  412. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  413. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  414. for (const Layer *layer : m_layers) {
  415. LayerRegion *layerm = layer->m_regions[region_id];
  416. layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final");
  417. layerm->export_region_fill_surfaces_to_svg_debug("7_discover_horizontal_shells-final");
  418. } // for each layer
  419. } // for each region
  420. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  421. // Only active if config->infill_only_where_needed. This step trims the sparse infill,
  422. // so it acts as an internal support. It maintains all other infill types intact.
  423. // Here the internal surfaces and perimeters have to be supported by the sparse infill.
  424. //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
  425. // Likely the sparse infill will not be anchored correctly, so it will not work as intended.
  426. // Also one wishes the perimeters to be supported by a full infill.
  427. //m_print->set_status( 70, L("Clip surfaces"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  428. //this->clip_fill_surfaces(); // infill_only_where_needed
  429. m_print->throw_if_canceled();
  430. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  431. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  432. for (const Layer *layer : m_layers) {
  433. LayerRegion *layerm = layer->m_regions[region_id];
  434. layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final");
  435. layerm->export_region_fill_surfaces_to_svg_debug("8_clip_surfaces-final");
  436. } // for each layer
  437. } // for each region
  438. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  439. // the following step needs to be done before combination because it may need
  440. // to remove only half of the combined infill
  441. if (m_print->objects().size() == 1) {
  442. m_print->set_status( 80, L("Put bridges over sparse infill"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  443. } else {
  444. int32_t advancement_count = m_print->secondary_status_counter_increment(15);
  445. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  446. {std::to_string(advancement_count),
  447. std::to_string(m_print->secondary_status_counter_get_max())},
  448. PrintBase::SlicingStatus::SECONDARY_STATE);
  449. }
  450. this->bridge_over_infill();
  451. m_print->throw_if_canceled();
  452. this->replaceSurfaceType(stPosInternal | stDensSolid,
  453. stPosInternal | stDensSolid | stModOverBridge,
  454. stPosInternal | stDensSolid | stModBridge);
  455. m_print->throw_if_canceled();
  456. this->replaceSurfaceType(stPosTop | stDensSolid,
  457. stPosTop | stDensSolid | stModOverBridge,
  458. stPosInternal | stDensSolid | stModBridge);
  459. m_print->throw_if_canceled();
  460. this->replaceSurfaceType(stPosInternal | stDensSolid,
  461. stPosInternal | stDensSolid | stModOverBridge,
  462. stPosBottom | stDensSolid | stModBridge);
  463. m_print->throw_if_canceled();
  464. this->replaceSurfaceType(stPosTop | stDensSolid,
  465. stPosTop | stDensSolid | stModOverBridge,
  466. stPosBottom | stDensSolid | stModBridge);
  467. m_print->throw_if_canceled();
  468. // combine fill surfaces to honor the "infill every N layers" option
  469. if (m_print->objects().size() == 1) {
  470. m_print->set_status( 95, L("Combine infill"), {}, PrintBase::SlicingStatus::SECONDARY_STATE);
  471. } else {
  472. int32_t advancement_count = m_print->secondary_status_counter_increment(5);
  473. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  474. {std::to_string(advancement_count),
  475. std::to_string(m_print->secondary_status_counter_get_max())},
  476. PrintBase::SlicingStatus::SECONDARY_STATE);
  477. }
  478. this->combine_infill();
  479. m_print->throw_if_canceled();
  480. // count the distance from the nearest top surface, to allow to use denser infill
  481. // if needed and if infill_dense_layers is positive.
  482. this->tag_under_bridge();
  483. m_print->throw_if_canceled();
  484. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  485. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  486. for (const Layer *layer : m_layers) {
  487. LayerRegion *layerm = layer->m_regions[region_id];
  488. layerm->export_region_slices_to_svg_debug("9_prepare_infill-final");
  489. layerm->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
  490. } // for each layer
  491. } // for each region
  492. for (const Layer *layer : m_layers) {
  493. layer->export_region_slices_to_svg_debug("9_prepare_infill-final");
  494. layer->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
  495. } // for each layer
  496. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  497. //compute m_max_sparse_spacing for fill_aligned_z
  498. _compute_max_sparse_spacing();
  499. if (m_print->objects().size() > 1) {
  500. int32_t advancement_count = m_print->secondary_status_counter_increment(0);
  501. m_print->set_status(advancement_count * 100 / m_print->secondary_status_counter_get_max(), L("Process objects: %s / %s"),
  502. {std::to_string(advancement_count),
  503. std::to_string(m_print->secondary_status_counter_get_max())},
  504. PrintBase::SlicingStatus::SECONDARY_STATE);
  505. }
  506. this->set_done(posPrepareInfill);
  507. }
  508. void PrintObject::_compute_max_sparse_spacing()
  509. {
  510. m_max_sparse_spacing = 0;
  511. std::atomic_int64_t max_sparse_spacing(0);
  512. Slic3r::parallel_for(size_t(0), m_layers.size(),
  513. [this, &max_sparse_spacing](const size_t layer_idx) {
  514. m_print->throw_if_canceled();
  515. const Layer *layer = m_layers[layer_idx];
  516. for (const LayerRegion *layerm : layer->regions()) {
  517. // check if region has sparse infill.
  518. for (const Surface &surface : layerm->fill_surfaces().surfaces) {
  519. if (surface.has_fill_sparse()) {
  520. coord_t spacing = layerm->region().flow(*this, frInfill, layer->height, layer->id()).scaled_spacing();
  521. // update atomic to max
  522. int64_t prev_value = max_sparse_spacing.load();
  523. while (prev_value < int64_t(spacing) &&
  524. !max_sparse_spacing.compare_exchange_weak(prev_value, int64_t(spacing))) {
  525. }
  526. }
  527. }
  528. }
  529. });
  530. m_max_sparse_spacing = max_sparse_spacing.load();
  531. }
  532. void PrintObject::clear_fills()
  533. {
  534. for (Layer *layer : m_layers)
  535. layer->clear_fills();
  536. }
  537. void PrintObject::infill()
  538. {
  539. // prerequisites
  540. this->prepare_infill();
  541. //m_print->set_status(0, _u8L("Infilling layer %s / %s"),
  542. // { std::to_string(0), std::to_string(m_layers.size()) }, PrintBase::SlicingStatus::SECONDARY_STATE);
  543. if (this->set_started(posInfill)) {
  544. // TRN Status for the Print calculation
  545. m_print->set_status(objectstep_2_percent[PrintObjectStep::posInfill], L("Infilling layers"));
  546. m_print->secondary_status_counter_add_max(m_layers.size());
  547. const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first;
  548. const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
  549. BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
  550. Slic3r::parallel_for(size_t(0), m_layers.size(),
  551. [this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree]
  552. (const size_t layer_idx) {
  553. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  554. // updating progress
  555. int32_t nb_layers_done = m_print->secondary_status_counter_increment();
  556. m_print->set_status(100 * nb_layers_done / m_print->secondary_status_counter_get_max(), L("Infilling layer %s / %s"),
  557. {std::to_string(nb_layers_done), std::to_string(m_print->secondary_status_counter_get_max())},
  558. PrintBase::SlicingStatus::SECONDARY_STATE);
  559. std::chrono::time_point<std::chrono::system_clock> start_make_fill = std::chrono::system_clock::now();
  560. m_print->throw_if_canceled();
  561. m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get(), this->m_lightning_generator.get());
  562. }
  563. );
  564. m_print->set_status(100, "", PrintBase::SlicingStatus::SECONDARY_STATE);
  565. m_print->throw_if_canceled();
  566. BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - end";
  567. /* we could free memory now, but this would make this step not idempotent
  568. ### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
  569. */
  570. this->set_done(posInfill);
  571. }
  572. }
  573. void PrintObject::ironing()
  574. {
  575. if (this->set_started(posIroning)) {
  576. m_print->set_status(objectstep_2_percent[PrintObjectStep::posIroning], L("Ironing"));
  577. m_print->secondary_status_counter_add_max(m_layers.size());
  578. BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - start";
  579. // Ironing starting with layer 0 to support ironing all surfaces.
  580. Slic3r::parallel_for(size_t(0), m_layers.size(),
  581. [this](const size_t layer_idx) {
  582. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  583. // updating progress
  584. int32_t nb_layers_done = m_print->secondary_status_counter_increment();
  585. m_print->set_status(100 * nb_layers_done / m_print->secondary_status_counter_get_max(), L("Ironing layer %s / %s"),
  586. {std::to_string(nb_layers_done), std::to_string(m_print->secondary_status_counter_get_max())},
  587. PrintBase::SlicingStatus::SECONDARY_STATE);
  588. m_print->throw_if_canceled();
  589. m_layers[layer_idx]->make_ironing();
  590. }
  591. );
  592. m_print->throw_if_canceled();
  593. BOOST_LOG_TRIVIAL(debug) << "Ironing in parallel - end";
  594. this->set_done(posIroning);
  595. }
  596. }
  597. void PrintObject::generate_support_spots()
  598. {
  599. assert(this->default_region_config(this->print()->default_region_config()).get_computed_value("perimeter_acceleration") > -1);
  600. if (this->set_started(posSupportSpotsSearch)) {
  601. BOOST_LOG_TRIVIAL(debug) << "Searching support spots - start";
  602. m_print->set_status(objectstep_2_percent[PrintObjectStep::posSupportSpotsSearch], L("Searching support spots"));
  603. if (m_print->objects().size() > 1) {
  604. m_print->secondary_status_counter_add_max(1);
  605. m_print->set_status(0. / m_print->objects().size(), L("Object %s / %s"),
  606. {std::to_string(0), std::to_string(m_print->objects().size())},
  607. PrintBase::SlicingStatus::SECONDARY_STATE);
  608. } else {
  609. m_print->set_status(0, "", PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE);
  610. }
  611. if (!this->shared_regions()->generated_support_points.has_value()) {
  612. PrintTryCancel cancel_func = m_print->make_try_cancel();
  613. const PrintRegionConfig &region_config = this->default_region_config(this->print()->default_region_config());
  614. SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.get_values(),
  615. float(region_config.get_computed_value("perimeter_acceleration")),
  616. this->config().raft_layers.value,
  617. float(this->config().brim_width.value),
  618. float(this->config().brim_width_interior.value)};
  619. auto [supp_points, partial_objects] = SupportSpotsGenerator::full_search(this, cancel_func, params);
  620. Transform3d po_transform = this->trafo_centered();
  621. if (this->layer_count() > 0) {
  622. po_transform = Geometry::translation_transform(Vec3d{0, 0, this->layers().front()->bottom_z()}) * po_transform;
  623. }
  624. this->m_shared_regions->generated_support_points = {po_transform, supp_points, partial_objects};
  625. m_print->throw_if_canceled();
  626. }
  627. // updating progress
  628. if (m_print->objects().size() > 1) {
  629. int32_t nb_objects_done = m_print->secondary_status_counter_increment();
  630. m_print->set_status(100 * (nb_objects_done + 1) / m_print->secondary_status_counter_get_max(),
  631. L("Object %s / %s"),
  632. {std::to_string(nb_objects_done + 1), std::to_string(m_print->secondary_status_counter_get_max())},
  633. PrintBase::SlicingStatus::SECONDARY_STATE);
  634. }
  635. BOOST_LOG_TRIVIAL(debug) << "Searching support spots - end";
  636. this->set_done(posSupportSpotsSearch);
  637. }
  638. }
  639. void PrintObject::generate_support_material()
  640. {
  641. if (this->set_started(posSupportMaterial)) {
  642. m_print->set_status(objectstep_2_percent[PrintObjectStep::posSupportMaterial], L("Generating support material"));
  643. if (m_print->objects().size() > 1) {
  644. m_print->secondary_status_counter_add_max(1);
  645. m_print->set_status(0. / m_print->objects().size(), L("Object %s / %s"),
  646. {std::to_string(0), std::to_string(m_print->objects().size())},
  647. PrintBase::SlicingStatus::SECONDARY_STATE);
  648. } else {
  649. m_print->set_status(0, "", PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE);
  650. }
  651. this->clear_support_layers();
  652. if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
  653. this->_generate_support_material();
  654. m_print->throw_if_canceled();
  655. } else {
  656. #if 0
  657. // Printing without supports. Empty layer means some objects or object parts are levitating,
  658. // therefore they cannot be printed without supports.
  659. for (const Layer *layer : m_layers)
  660. if (layer->empty())
  661. throw Slic3r::SlicingError("Levitating objects cannot be printed without supports.");
  662. #endif
  663. }
  664. this->set_done(posSupportMaterial);
  665. // updating progress
  666. if (m_print->objects().size() > 1) {
  667. int32_t nb_objects_done = m_print->secondary_status_counter_increment();
  668. m_print->set_status(100 * (nb_objects_done + 1) / m_print->secondary_status_counter_get_max(),
  669. L("Object %s / %s"),
  670. {std::to_string(nb_objects_done + 1), std::to_string(m_print->secondary_status_counter_get_max())},
  671. PrintBase::SlicingStatus::SECONDARY_STATE);
  672. }
  673. }
  674. }
  675. void PrintObject::simplify_extrusion_path()
  676. {
  677. if (this->set_started(posSimplifyPath)) {
  678. const PrintConfig& print_config = this->print()->config();
  679. const bool spiral_mode = print_config.spiral_vase;
  680. const bool enable_arc_fitting = print_config.arc_fitting != ArcFittingType::Disabled && !spiral_mode;
  681. m_print->secondary_status_counter_add_max(m_layers.size() + m_support_layers.size());
  682. BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of object in parallel - start";
  683. //BBS: infill and walls
  684. Slic3r::parallel_for(size_t(0), m_layers.size(),
  685. [this](const size_t layer_idx) {
  686. m_print->throw_if_canceled();
  687. m_layers[layer_idx]->simplify_extrusion_path();
  688. // updating progress
  689. int32_t nb_layers_done = m_print->secondary_status_counter_increment() + 1;
  690. m_print->set_status(int((nb_layers_done * 100) / m_print->secondary_status_counter_get_max()),
  691. L("Optimizing layer %s / %s"),
  692. {std::to_string(nb_layers_done), std::to_string(m_print->secondary_status_counter_get_max())},
  693. PrintBase::SlicingStatus::SECONDARY_STATE);
  694. }
  695. );
  696. //also simplify object skirt & brim
  697. if (enable_arc_fitting) {
  698. coordf_t scaled_resolution = scale_d(print_config.arc_fitting_resolution.get_abs_value(print_config.resolution.value));
  699. if (scaled_resolution == 0) scaled_resolution = enable_arc_fitting ? SCALED_EPSILON * 2 : SCALED_EPSILON;
  700. const ConfigOptionFloatOrPercent& arc_fitting_tolerance = print_config.arc_fitting_tolerance;
  701. GetPathsVisitor visitor;
  702. this->m_skirt.visit(visitor);
  703. this->m_brim.visit(visitor);
  704. tbb::parallel_for(
  705. tbb::blocked_range<size_t>(0, visitor.paths.size() + visitor.paths3D.size()),
  706. [this, &visitor, scaled_resolution, &arc_fitting_tolerance, &print_config](const tbb::blocked_range<size_t>& range) {
  707. size_t path_idx = range.begin();
  708. for (; path_idx < range.end() && path_idx < visitor.paths.size(); ++path_idx) {
  709. visitor.paths[path_idx]->simplify(scaled_resolution, print_config.arc_fitting, arc_fitting_tolerance.get_abs_value(visitor.paths[path_idx]->width()));
  710. }
  711. for (; path_idx < range.end() && path_idx - visitor.paths.size() < visitor.paths3D.size(); ++path_idx) {
  712. visitor.paths3D[path_idx - visitor.paths.size()]->simplify(scaled_resolution, print_config.arc_fitting,
  713. arc_fitting_tolerance.get_abs_value(visitor.paths3D[path_idx - visitor.paths.size()]->width()));
  714. }
  715. }
  716. );
  717. }
  718. m_print->throw_if_canceled();
  719. BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of object in parallel - end";
  720. //BBS: share same progress
  721. BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - start";
  722. Slic3r::parallel_for(size_t(0), m_support_layers.size(),
  723. [this](const size_t layer_idx) {
  724. m_print->throw_if_canceled();
  725. m_support_layers[layer_idx]->simplify_support_extrusion_path();
  726. // updating progress
  727. int32_t nb_layers_done = m_print->secondary_status_counter_increment() + 1;
  728. m_print->set_status(int((nb_layers_done * 100) / m_print->secondary_status_counter_get_max()),
  729. L("Optimizing layer %s / %s"),
  730. {std::to_string(nb_layers_done), std::to_string(m_print->secondary_status_counter_get_max())},
  731. PrintBase::SlicingStatus::SECONDARY_STATE);
  732. }
  733. );
  734. m_print->throw_if_canceled();
  735. BOOST_LOG_TRIVIAL(debug) << "Simplify extrusion path of support in parallel - end";
  736. this->set_done(posSimplifyPath);
  737. }
  738. }
  739. void PrintObject::estimate_curled_extrusions()
  740. {
  741. if (this->set_started(posEstimateCurledExtrusions)) {
  742. m_print->set_status(objectstep_2_percent[PrintObjectStep::posEstimateCurledExtrusions], L("Estimate curled extrusions"));
  743. if (m_print->objects().size() > 1) {
  744. m_print->secondary_status_counter_add_max(1);
  745. m_print->set_status(0. / m_print->objects().size(), L("Object %s / %s"),
  746. {std::to_string(0), std::to_string(m_print->objects().size())},
  747. PrintBase::SlicingStatus::SECONDARY_STATE);
  748. } else {
  749. m_print->set_status(0, "", PrintBase::SlicingStatus::DEFAULT | PrintBase::SlicingStatus::SECONDARY_STATE);
  750. }
  751. if (this->print()->config().avoid_crossing_curled_overhangs ||
  752. std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(),
  753. [](const PrintRegion *region) { return region->config().overhangs_dynamic_speed.is_enabled(); })) {
  754. BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - start";
  755. m_print->set_status(objectstep_2_percent[PrintObjectStep::posEstimateCurledExtrusions], _u8L("Estimating curled extrusions"));
  756. // Estimate curling of support material and add it to the malformaition lines of each layer
  757. float support_flow_width = support_material_flow(this, this->config().layer_height).width();
  758. SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.get_values(),
  759. float(this->print()->full_print_config().get_computed_value("perimeter_acceleration")),
  760. this->config().raft_layers.value,
  761. float(this->config().brim_width.value),
  762. float(this->config().brim_width_interior.value)};
  763. SupportSpotsGenerator::estimate_supports_malformations(this->edit_support_layers(), support_flow_width, params);
  764. SupportSpotsGenerator::estimate_malformations(this->layers(), params);
  765. m_print->throw_if_canceled();
  766. BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - end";
  767. }
  768. this->set_done(posEstimateCurledExtrusions);
  769. // updating progress
  770. if (m_print->objects().size() > 1) {
  771. int32_t nb_objects_done = m_print->secondary_status_counter_increment();
  772. m_print->set_status(100 * (nb_objects_done + 1) / m_print->secondary_status_counter_get_max(),
  773. L("Object %s / %s"),
  774. {std::to_string(nb_objects_done + 1), std::to_string(m_print->secondary_status_counter_get_max())},
  775. PrintBase::SlicingStatus::SECONDARY_STATE);
  776. }
  777. }
  778. }
  779. void PrintObject::calculate_overhanging_perimeters()
  780. {
  781. if (this->set_started(posCalculateOverhangingPerimeters)) {
  782. BOOST_LOG_TRIVIAL(debug) << "Calculating overhanging perimeters - start";
  783. m_print->set_status(objectstep_2_percent[PrintObjectStep::posCalculateOverhangingPerimeters], _u8L("Calculating overhanging perimeters"));
  784. std::set<uint16_t> extruders;
  785. std::unordered_set<const PrintRegion *> regions_with_dynamic_speeds;
  786. for (const PrintRegion *pr : this->print()->m_print_regions) {
  787. if (pr->config().overhangs_dynamic_speed.is_enabled()) {
  788. regions_with_dynamic_speeds.insert(pr);
  789. }
  790. extruders.clear();
  791. pr->collect_object_printing_extruders(*this->print(), extruders);
  792. auto cfg = this->print()->config();
  793. if (std::any_of(extruders.begin(), extruders.end(),
  794. [&cfg](unsigned int extruder_id) { return cfg.overhangs_dynamic_fan_speed.is_enabled(extruder_id); })) {
  795. regions_with_dynamic_speeds.insert(pr);
  796. }
  797. }
  798. if (!regions_with_dynamic_speeds.empty()) {
  799. std::unordered_map<size_t, AABBTreeLines::LinesDistancer<CurledLine>> curled_lines;
  800. std::unordered_map<size_t, AABBTreeLines::LinesDistancer<Linef>> unscaled_polygons_lines;
  801. for (const Layer *l : this->layers()) {
  802. curled_lines[l->id()] = AABBTreeLines::LinesDistancer<CurledLine>{l->curled_lines};
  803. unscaled_polygons_lines[l->id()] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(l->lslices())};
  804. }
  805. curled_lines[size_t(-1)] = {};
  806. unscaled_polygons_lines[size_t(-1)] = {};
  807. Slic3r::parallel_for(size_t(0), m_layers.size(),
  808. [this, &curled_lines, &unscaled_polygons_lines, &regions_with_dynamic_speeds]
  809. (const size_t layer_idx) {
  810. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  811. auto l = m_layers[layer_idx];
  812. // first layer: do not split
  813. if (l->id() > 0) {
  814. for (LayerRegion *layer_region : l->regions()) {
  815. if (regions_with_dynamic_speeds.find(layer_region->m_region) == regions_with_dynamic_speeds.end()) {
  816. continue;
  817. }
  818. size_t prev_layer_id = l->lower_layer ? l->lower_layer->id() : size_t(-1);
  819. const double nozzle_diameter_overhangs = layer_region->bridging_flow(frPerimeter).nozzle_diameter();
  820. double max_width = -1;
  821. if (layer_region->region().config().overhangs_width_speed.is_enabled()) {
  822. max_width = layer_region->region().config().overhangs_width_speed.get_abs_value(nozzle_diameter_overhangs);
  823. }
  824. if (layer_region->region().config().overhangs_width.is_enabled() && (max_width < 0 ||
  825. max_width > layer_region->region().config().overhangs_width.get_abs_value(nozzle_diameter_overhangs))) {
  826. max_width = layer_region->region().config().overhangs_width.get_abs_value(nozzle_diameter_overhangs);
  827. }
  828. if (max_width < 0) {
  829. max_width = nozzle_diameter_overhangs;
  830. }
  831. layer_region->m_perimeters =
  832. ExtrusionProcessor::calculate_and_split_overhanging_extrusions(&layer_region->m_perimeters,
  833. unscaled_polygons_lines[prev_layer_id],
  834. curled_lines[l->id()],
  835. max_width);
  836. }
  837. #ifdef _DEBUG
  838. {
  839. struct OverhangAssertVisitor : public ExtrusionVisitorRecursiveConst
  840. {
  841. virtual void default_use(const ExtrusionEntity &entity) override{};
  842. virtual void use(const ExtrusionPath &path) override {
  843. if (path.role().is_overhang())
  844. assert(path.attributes().overhang_attributes.has_value());
  845. }
  846. };
  847. OverhangAssertVisitor ov_visitor;
  848. for (auto &reg : l->regions()) {
  849. reg->perimeters().visit(ov_visitor);
  850. }
  851. }
  852. #endif
  853. }
  854. });
  855. m_print->throw_if_canceled();
  856. BOOST_LOG_TRIVIAL(debug) << "Calculating overhanging perimeters - end";
  857. }
  858. this->set_done(posCalculateOverhangingPerimeters);
  859. }
  860. }
  861. std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare_adaptive_infill_data(
  862. const std::vector<std::pair<const Surface *, float>> &surfaces_w_bottom_z) const
  863. {
  864. using namespace FillAdaptive;
  865. auto [adaptive_line_spacing, support_line_spacing] = adaptive_fill_line_spacing(*this);
  866. if ((adaptive_line_spacing == 0. && support_line_spacing == 0.) || this->layers().empty())
  867. return std::make_pair(OctreePtr(), OctreePtr());
  868. indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set();
  869. // Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
  870. auto to_octree = transform_to_octree().toRotationMatrix();
  871. its_transform(mesh, to_octree * this->trafo_centered(), true);
  872. // Triangulate internal bridging surfaces.
  873. std::vector<std::vector<Vec3d>> overhangs(std::max(surfaces_w_bottom_z.size(), size_t(1)));
  874. // ^ make sure vector is not empty, even with no briding surfaces we still want to build the adaptive trees later, some continue normally
  875. Slic3r::parallel_for(size_t(0), surfaces_w_bottom_z.size(),
  876. [this, &to_octree, &overhangs, &surfaces_w_bottom_z] (const size_t surface_idx) {
  877. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  878. std::vector<Vec3d> &out = overhangs[surface_idx];
  879. m_print->throw_if_canceled();
  880. append(out, triangulate_expolygon_3d(surfaces_w_bottom_z[surface_idx].first->expolygon,
  881. surfaces_w_bottom_z[surface_idx].second));
  882. for (Vec3d &p : out)
  883. p = (to_octree * p).eval();
  884. }
  885. );
  886. // and gather them.
  887. for (size_t i = 1; i < overhangs.size(); ++ i)
  888. append(overhangs.front(), std::move(overhangs[i]));
  889. return std::make_pair(
  890. adaptive_line_spacing ? build_octree(mesh, overhangs.front(), adaptive_line_spacing, false) : OctreePtr(),
  891. support_line_spacing ? build_octree(mesh, overhangs.front(), support_line_spacing, true) : OctreePtr());
  892. }
  893. FillLightning::GeneratorPtr PrintObject::prepare_lightning_infill_data()
  894. {
  895. bool has_lightning_infill = false;
  896. coordf_t lightning_density = 0.;
  897. size_t lightning_cnt = 0;
  898. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
  899. if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern.value == ipLightning) {
  900. has_lightning_infill = true;
  901. lightning_density += config.fill_density;
  902. ++lightning_cnt;
  903. }
  904. if (has_lightning_infill)
  905. lightning_density /= coordf_t(lightning_cnt);
  906. return has_lightning_infill ? FillLightning::build_generator(std::as_const(*this), lightning_density, [this]() -> void { this->throw_if_canceled(); }) : FillLightning::GeneratorPtr();
  907. }
  908. const PrintRegionConfig &PrintObject::default_region_config(const PrintRegionConfig &from_print) const {
  909. //TODO check if a regionconfig set in an object modifier go through
  910. if (this->m_shared_regions && num_printing_regions() > 0) {
  911. return printing_region(0).config();
  912. }
  913. return from_print;
  914. }
  915. bool PrintObject::has_brim() const {
  916. bool has_brim_volume = false;
  917. for (const ModelVolume *volume : this->model_object()->volumes) {
  918. if (volume->is_brim_patch()) {
  919. has_brim_volume = true;
  920. }
  921. }
  922. return has_brim_volume || ((this->config().brim_width.value > 0 && this->config().brim_width_interior.value > 0)
  923. && !this->has_raft());
  924. }
  925. Polygons PrintObject::get_brim_patch(ModelVolumeType brim_type, const PrintInstance *instance /*= nullptr*/) const {
  926. Polygons polys;
  927. for (const ModelVolume *v : this->model_object()->volumes) {
  928. assert(v);
  929. if (v->type() == brim_type) {
  930. if (instance == nullptr) {
  931. for (const PrintInstance &inst : this->instances()) {
  932. Polygons vol_outline;
  933. auto transl = Transform3d::Identity();
  934. assert(inst.model_instance);
  935. vol_outline = project_mesh(v->mesh().its,
  936. transl * inst.model_instance->get_matrix() * v->get_matrix(), [] {});
  937. append(polys, vol_outline);
  938. }
  939. } else {
  940. Polygons vol_outline;
  941. auto transl = Transform3d::Identity();
  942. assert(instance->model_instance);
  943. vol_outline = project_mesh(v->mesh().its,
  944. transl * instance->model_instance->get_matrix() * v->get_matrix(), [] {});
  945. append(polys, vol_outline);
  946. }
  947. }
  948. }
  949. coord_t scaled_brim_resolution = std::max(SCALED_EPSILON * 10, scale_t(this->print()->config().resolution.value));
  950. return ensure_valid(union_(polys), scaled_brim_resolution);
  951. }
  952. void PrintObject::clear_layers()
  953. {
  954. for (Layer *l : m_layers)
  955. delete l;
  956. m_layers.clear();
  957. }
  958. Layer* PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
  959. {
  960. m_layers.emplace_back(new Layer(id, this, height, print_z, slice_z));
  961. return m_layers.back();
  962. }
  963. void PrintObject::clear_support_layers()
  964. {
  965. for (Layer *l : m_support_layers)
  966. delete l;
  967. m_support_layers.clear();
  968. }
  969. void PrintObject::add_support_layer(int id, int interface_id, coordf_t height, coordf_t print_z)
  970. {
  971. m_support_layers.emplace_back(new SupportLayer(id, interface_id, this, height, print_z, -1));
  972. }
  973. SupportLayerPtrs::iterator PrintObject::insert_support_layer(SupportLayerPtrs::const_iterator pos, size_t id, size_t interface_id, coordf_t height, coordf_t print_z, coordf_t slice_z)
  974. {
  975. return m_support_layers.insert(pos, new SupportLayer(id, interface_id, this, height, print_z, slice_z));
  976. }
  977. // Called by Print::apply().
  978. // This method only accepts PrintObjectConfig and PrintRegionConfig option keys.
  979. bool PrintObject::invalidate_state_by_config_options(
  980. const ConfigOptionResolver &old_config, const ConfigOptionResolver &new_config, const std::vector<t_config_option_key> &opt_keys)
  981. {
  982. if (opt_keys.empty())
  983. return false;
  984. std::vector<PrintObjectStep> steps;
  985. bool invalidated = false;
  986. for (const t_config_option_key& opt_key : opt_keys) {
  987. if (
  988. opt_key == "arc_fitting"
  989. || opt_key == "external_perimeters_first"
  990. || opt_key == "external_perimeters_first_force"
  991. || opt_key == "external_perimeters_hole"
  992. || opt_key == "external_perimeters_nothole"
  993. || opt_key == "external_perimeter_extrusion_change_odd_layers"
  994. || opt_key == "external_perimeter_extrusion_spacing"
  995. || opt_key == "external_perimeter_extrusion_width"
  996. || opt_key == "external_perimeters_vase"
  997. || opt_key == "gap_fill_extension"
  998. || opt_key == "gap_fill_last"
  999. || opt_key == "gap_fill_max_width"
  1000. || opt_key == "gap_fill_min_area"
  1001. || opt_key == "gap_fill_min_length"
  1002. || opt_key == "gap_fill_min_width"
  1003. || opt_key == "min_width_top_surface"
  1004. || opt_key == "only_one_perimeter_first_layer"
  1005. || opt_key == "only_one_perimeter_top"
  1006. || opt_key == "only_one_perimeter_top_other_algo"
  1007. || opt_key == "overhangs_dynamic_speed"
  1008. || opt_key == "overhangs_reverse"
  1009. || opt_key == "overhangs_reverse_threshold"
  1010. || opt_key == "overhangs_speed_enforce"
  1011. || opt_key == "overhangs_width_speed"
  1012. || opt_key == "overhangs_width"
  1013. || opt_key == "perimeter_bonding"
  1014. || opt_key == "perimeter_direction"
  1015. || opt_key == "perimeter_extrusion_change_odd_layers"
  1016. || opt_key == "perimeter_extrusion_spacing"
  1017. || opt_key == "perimeter_extrusion_width"
  1018. || opt_key == "perimeter_loop"
  1019. || opt_key == "perimeter_loop_seam"
  1020. || opt_key == "perimeter_reverse"
  1021. || opt_key == "perimeter_round_corners"
  1022. || opt_key == "thin_perimeters"
  1023. || opt_key == "thin_perimeters_all"
  1024. || opt_key == "thin_walls_merge"
  1025. || opt_key == "thin_walls_min_width"
  1026. || opt_key == "thin_walls_overlap"
  1027. ) {
  1028. steps.emplace_back(posPerimeters);
  1029. } else if (
  1030. opt_key == "gap_fill_enabled"
  1031. || opt_key == "gap_fill_speed") {
  1032. // Return true if gap-fill speed has changed from zero value to non-zero or from non-zero value to zero.
  1033. auto is_gap_fill_changed_state_due_to_speed = [&opt_key, &old_config, &new_config]() -> bool {
  1034. if (opt_key == "gap_fill_speed") {
  1035. assert(old_config.option<ConfigOptionFloatOrPercent>(opt_key) && new_config.option<ConfigOptionFloatOrPercent>(opt_key));
  1036. const float old_gap_fill_speed = old_config.option(opt_key)->get_float();
  1037. const float new_gap_fill_speed = new_config.option(opt_key)->get_float();
  1038. return (old_gap_fill_speed > 0.f && new_gap_fill_speed == 0.f) ||
  1039. (old_gap_fill_speed == 0.f && new_gap_fill_speed > 0.f);
  1040. }
  1041. return false;
  1042. };
  1043. // Filtering of unprintable regions in multi-material segmentation depends on if gap-fill is enabled or not.
  1044. // So step posSlice is invalidated when gap-fill was enabled/disabled by option "gap_fill_enabled" or by
  1045. // changing "gap_fill_speed" to force recomputation of the multi-material segmentation.
  1046. if (this->is_mm_painted() && (opt_key == "gap_fill_enabled" || (opt_key == "gap_fill_speed" && is_gap_fill_changed_state_due_to_speed())))
  1047. steps.emplace_back(posSlice);
  1048. steps.emplace_back(posPerimeters);
  1049. } else if (
  1050. // || opt_key == "exact_last_layer_height"
  1051. opt_key == "bridge_type"
  1052. || opt_key == "clip_multipart_objects"
  1053. || opt_key == "curve_smoothing_angle_concave"
  1054. || opt_key == "curve_smoothing_angle_convex"
  1055. || opt_key == "curve_smoothing_cutoff_dist"
  1056. || opt_key == "curve_smoothing_precision"
  1057. || opt_key == "dont_support_bridges"
  1058. || opt_key == "elephant_foot_min_width" //sla ?
  1059. || opt_key == "first_layer_size_compensation"
  1060. || opt_key == "first_layer_size_compensation_layers"
  1061. || opt_key == "first_layer_size_compensation_no_collapse"
  1062. || opt_key == "first_layer_height"
  1063. || opt_key == "hole_size_compensation"
  1064. || opt_key == "hole_size_threshold"
  1065. || opt_key == "hole_to_polyhole"
  1066. || opt_key == "hole_to_polyhole_threshold"
  1067. || opt_key == "hole_to_polyhole_twisted"
  1068. || opt_key == "layer_height"
  1069. || opt_key == "min_bead_width"
  1070. || opt_key == "min_feature_size"
  1071. || opt_key == "mmu_segmented_region_max_width"
  1072. || opt_key == "model_precision"
  1073. || opt_key == "overhangs_max_slope"
  1074. || opt_key == "overhangs_bridge_threshold"
  1075. || opt_key == "overhangs_bridge_upper_layers"
  1076. || opt_key == "raft_contact_distance"
  1077. || opt_key == "raft_interface_layer_height"
  1078. || opt_key == "raft_layers"
  1079. || opt_key == "raft_layer_height"
  1080. || opt_key == "perimeter_generator"
  1081. || opt_key == "slice_closing_radius"
  1082. || opt_key == "slicing_mode"
  1083. || opt_key == "support_material_contact_distance_type"
  1084. || opt_key == "support_material_contact_distance"
  1085. || opt_key == "support_material_bottom_contact_distance"
  1086. || opt_key == "support_material_interface_layer_height"
  1087. || opt_key == "support_material_layer_height"
  1088. || opt_key == "wall_transition_length"
  1089. || opt_key == "wall_transition_filter_deviation"
  1090. || opt_key == "wall_transition_angle"
  1091. || opt_key == "wall_distribution_count"
  1092. || opt_key == "xy_inner_size_compensation"
  1093. || opt_key == "xy_size_compensation") {
  1094. steps.emplace_back(posSlice);
  1095. } else if (opt_key == "support_material") {
  1096. steps.emplace_back(posSupportMaterial);
  1097. if (m_config.support_material_contact_distance.value == 0. || m_config.support_material_bottom_contact_distance.value == 0.) {
  1098. // Enabling / disabling supports while soluble support interface is enabled.
  1099. // This changes the bridging logic (bridging enabled without supports, disabled with supports).
  1100. // Reset everything.
  1101. // See GH #1482 for details.
  1102. steps.emplace_back(posSlice);
  1103. }
  1104. } else if (
  1105. opt_key == "raft_expansion"
  1106. || opt_key == "raft_first_layer_density"
  1107. || opt_key == "raft_first_layer_expansion"
  1108. || opt_key == "support_material_auto"
  1109. || opt_key == "support_material_angle"
  1110. || opt_key == "support_material_angle_height"
  1111. || opt_key == "support_material_buildplate_only"
  1112. || opt_key == "support_material_enforce_layers"
  1113. || opt_key == "support_material_extruder"
  1114. || opt_key == "support_material_extrusion_width"
  1115. || opt_key == "support_material_interface_layers"
  1116. || opt_key == "support_material_bottom_interface_layers"
  1117. || opt_key == "support_material_bottom_interface_pattern"
  1118. || opt_key == "support_material_interface_angle"
  1119. || opt_key == "support_material_interface_angle_increment"
  1120. || opt_key == "support_material_interface_contact_loops"
  1121. || opt_key == "support_material_interface_extruder"
  1122. || opt_key == "support_material_interface_spacing"
  1123. || opt_key == "support_material_pattern"
  1124. || opt_key == "support_material_style"
  1125. || opt_key == "support_material_top_interface_pattern"
  1126. || opt_key == "support_material_xy_spacing"
  1127. || opt_key == "support_material_spacing"
  1128. || opt_key == "support_material_closing_radius"
  1129. || opt_key == "support_material_synchronize_layers"
  1130. || opt_key == "support_material_threshold"
  1131. || opt_key == "support_material_with_sheath") {
  1132. steps.emplace_back(posSupportMaterial);
  1133. } else if (opt_key == "bottom_solid_layers") {
  1134. steps.emplace_back(posPrepareInfill);
  1135. if (m_print->config().spiral_vase) {
  1136. // Changing the number of bottom layers when a spiral vase is enabled requires re-slicing the object again.
  1137. // Otherwise, holes in the bottom layers could be filled, as is reported in GH #5528.
  1138. steps.emplace_back(posSlice);
  1139. }
  1140. } else if (
  1141. opt_key == "bottom_solid_min_thickness"
  1142. || opt_key == "ensure_vertical_shell_thickness"
  1143. || opt_key == "interface_shells"
  1144. || opt_key == "infill_extruder"
  1145. || opt_key == "infill_extrusion_change_odd_layers"
  1146. || opt_key == "infill_extrusion_spacing"
  1147. || opt_key == "infill_extrusion_width"
  1148. || opt_key == "infill_every_layers"
  1149. || opt_key == "infill_dense"
  1150. || opt_key == "infill_dense_algo"
  1151. || opt_key == "infill_only_where_needed"
  1152. || opt_key == "ironing"
  1153. || opt_key == "ironing_type"
  1154. || opt_key == "over_bridge_flow_ratio"
  1155. || opt_key == "solid_infill_below_area"
  1156. || opt_key == "solid_infill_below_layer_area"
  1157. || opt_key == "solid_infill_below_width"
  1158. || opt_key == "solid_infill_extruder"
  1159. || opt_key == "solid_infill_every_layers"
  1160. || opt_key == "solid_over_perimeters"
  1161. || opt_key == "top_solid_layers"
  1162. || opt_key == "top_solid_min_thickness") {
  1163. steps.emplace_back(posPrepareInfill);
  1164. } else if (
  1165. opt_key == "bottom_fill_pattern"
  1166. || opt_key == "bridge_fill_pattern"
  1167. || opt_key == "bridge_overlap"
  1168. || opt_key == "bridge_overlap_min"
  1169. || opt_key == "enforce_full_fill_volume"
  1170. || opt_key == "fill_aligned_z"
  1171. || opt_key == "fill_angle"
  1172. || opt_key == "fill_angle_cross"
  1173. || opt_key == "fill_angle_follow_model"
  1174. || opt_key == "fill_angle_increment"
  1175. || opt_key == "fill_angle_template"
  1176. || opt_key == "fill_top_flow_ratio"
  1177. || opt_key == "fill_smooth_width"
  1178. || opt_key == "fill_smooth_distribution"
  1179. || opt_key == "first_layer_infill_extrusion_spacing"
  1180. || opt_key == "first_layer_infill_extrusion_width"
  1181. || opt_key == "infill_anchor"
  1182. || opt_key == "infill_anchor_max"
  1183. || opt_key == "infill_connection"
  1184. || opt_key == "infill_connection_bottom"
  1185. || opt_key == "infill_connection_bridge"
  1186. || opt_key == "infill_connection_solid"
  1187. || opt_key == "infill_connection_top"
  1188. || opt_key == "ironing_angle"
  1189. || opt_key == "ironing_flowrate"
  1190. || opt_key == "ironing_spacing"
  1191. || opt_key == "solid_fill_pattern"
  1192. || opt_key == "top_fill_pattern"
  1193. || opt_key == "top_infill_extrusion_spacing"
  1194. || opt_key == "top_infill_extrusion_width" ) {
  1195. steps.emplace_back(posInfill);
  1196. } else if (opt_key == "fill_pattern") {
  1197. steps.emplace_back(posInfill);
  1198. const auto *old_fill_pattern = old_config.option<ConfigOptionEnum<InfillPattern>>(opt_key);
  1199. const auto *new_fill_pattern = new_config.option<ConfigOptionEnum<InfillPattern>>(opt_key);
  1200. assert(old_fill_pattern && new_fill_pattern);
  1201. // We need to recalculate infill surfaces when infill_only_where_needed is enabled, and we are switching from
  1202. // the Lightning infill to another infill or vice versa.
  1203. //if (m_config.infill_only_where_needed && (new_fill_pattern->value == ipLightning || old_fill_pattern->value == ipLightning))
  1204. //steps.emplace_back(posPrepareInfill);
  1205. } else if (opt_key == "fill_density") {
  1206. // One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes),
  1207. // normal infill and 100% (solid) infill.
  1208. const auto *old_density = old_config.option<ConfigOptionPercent>(opt_key);
  1209. const auto *new_density = new_config.option<ConfigOptionPercent>(opt_key);
  1210. assert(old_density && new_density);
  1211. //FIXME Vojtech is not quite sure about the 100% here, maybe it is not needed.
  1212. if (is_approx(old_density->value, 0.) || is_approx(old_density->value, 100.) ||
  1213. is_approx(new_density->value, 0.) || is_approx(new_density->value, 100.)) {
  1214. steps.emplace_back(posPerimeters);
  1215. }
  1216. steps.emplace_back(posPrepareInfill);
  1217. } else if (
  1218. opt_key == "bridge_angle"
  1219. || opt_key == "bridged_infill_margin"
  1220. || opt_key == "extra_perimeters"
  1221. || opt_key == "extra_perimeters_odd_layers"
  1222. || opt_key == "extra_perimeters_on_overhangs"
  1223. || opt_key == "external_infill_margin"
  1224. || opt_key == "external_perimeter_overlap"
  1225. || opt_key == "gap_fill_overlap"
  1226. || opt_key == "infill_overlap"
  1227. || opt_key == "no_perimeter_unsupported_algo"
  1228. || opt_key == "perimeters"
  1229. || opt_key == "perimeters_hole"
  1230. || opt_key == "perimeter_overlap"
  1231. || opt_key == "solid_infill_extrusion_change_odd_layers"
  1232. || opt_key == "solid_infill_extrusion_spacing"
  1233. || opt_key == "solid_infill_extrusion_width"
  1234. || opt_key == "solid_infill_overlap"
  1235. || opt_key == "top_solid_infill_overlap") {
  1236. steps.emplace_back(posPerimeters);
  1237. steps.emplace_back(posPrepareInfill);
  1238. } else if (
  1239. opt_key == "external_perimeter_extrusion_width"
  1240. || opt_key == "external_perimeter_extrusion_spacing"
  1241. || opt_key == "perimeter_extruder"
  1242. || opt_key == "fuzzy_skin"
  1243. || opt_key == "fuzzy_skin_thickness"
  1244. || opt_key == "fuzzy_skin_point_dist"
  1245. || opt_key == "thin_walls") {
  1246. steps.emplace_back(posPerimeters);
  1247. steps.emplace_back(posSupportMaterial);
  1248. } else if (opt_key == "bridge_flow_ratio"
  1249. || opt_key == "extrusion_spacing"
  1250. || opt_key == "extrusion_width"
  1251. || opt_key == "first_layer_extrusion_spacing"
  1252. || opt_key == "first_layer_extrusion_width") {
  1253. //if (m_config.support_material_contact_distance > 0.) {
  1254. // Only invalidate due to bridging if bridging is enabled.
  1255. // If later "support_material_contact_distance" is modified, the complete PrintObject is invalidated anyway.
  1256. steps.emplace_back(posPerimeters);
  1257. steps.emplace_back(posInfill);
  1258. steps.emplace_back(posSupportMaterial);
  1259. //}
  1260. } else if (
  1261. opt_key == "avoid_crossing_top"
  1262. || opt_key == "bridge_acceleration"
  1263. || opt_key == "bridge_speed"
  1264. || opt_key == "brim_acceleration"
  1265. || opt_key == "brim_speed"
  1266. || opt_key == "external_perimeter_speed"
  1267. || opt_key == "default_acceleration"
  1268. || opt_key == "default_speed"
  1269. || opt_key == "external_perimeter_acceleration"
  1270. || opt_key == "external_perimeter_cut_corners"
  1271. || opt_key == "first_layer_acceleration"
  1272. || opt_key == "first_layer_acceleration_over_raft"
  1273. || opt_key == "first_layer_flow_ratio"
  1274. || opt_key == "first_layer_infill_speed"
  1275. || opt_key == "first_layer_min_speed"
  1276. || opt_key == "first_layer_speed"
  1277. || opt_key == "first_layer_speed_over_raft"
  1278. || opt_key == "gap_fill_acceleration"
  1279. || opt_key == "gap_fill_flow_match_perimeter"
  1280. || opt_key == "gap_fill_speed"
  1281. || opt_key == "infill_acceleration"
  1282. || opt_key == "infill_speed"
  1283. || opt_key == "internal_bridge_acceleration"
  1284. || opt_key == "internal_bridge_speed"
  1285. || opt_key == "ironing_acceleration"
  1286. || opt_key == "ironing_speed"
  1287. || opt_key == "milling_after_z"
  1288. || opt_key == "milling_extra_size"
  1289. || opt_key == "milling_post_process"
  1290. || opt_key == "milling_speed"
  1291. || opt_key == "object_gcode"
  1292. || opt_key == "overhangs_acceleration"
  1293. || opt_key == "overhangs_speed"
  1294. || opt_key == "perimeter_acceleration"
  1295. || opt_key == "perimeter_speed"
  1296. || opt_key == "print_extrusion_multiplier"
  1297. || opt_key == "print_first_layer_temperature"
  1298. || opt_key == "print_retract_length"
  1299. || opt_key == "print_retract_lift"
  1300. || opt_key == "print_temperature"
  1301. || opt_key == "region_gcode"
  1302. || opt_key == "seam_position"
  1303. //|| opt_key == "seam_preferred_direction"
  1304. //|| opt_key == "seam_preferred_direction_jitter"
  1305. || opt_key == "seam_angle_cost"
  1306. || opt_key == "seam_notch_all"
  1307. || opt_key == "seam_notch_angle"
  1308. || opt_key == "seam_notch_inner"
  1309. || opt_key == "seam_notch_outer"
  1310. || opt_key == "seam_travel_cost"
  1311. || opt_key == "seam_visibility"
  1312. || opt_key == "small_area_infill_flow_compensation"
  1313. || opt_key == "small_area_infill_flow_compensation_model"
  1314. || opt_key == "small_perimeter_speed"
  1315. || opt_key == "small_perimeter_min_length"
  1316. || opt_key == "small_perimeter_max_length"
  1317. || opt_key == "solid_infill_acceleration"
  1318. || opt_key == "solid_infill_speed"
  1319. || opt_key == "support_material_interface_speed"
  1320. || opt_key == "support_material_speed"
  1321. || opt_key == "thin_walls_acceleration"
  1322. || opt_key == "thin_walls_speed"
  1323. || opt_key == "top_solid_infill_acceleration"
  1324. || opt_key == "top_solid_infill_speed"
  1325. || opt_key == "travel_acceleration"
  1326. || opt_key == "travel_deceleration_use_target") {
  1327. invalidated |= m_print->invalidate_step(psGCodeExport);
  1328. } else if (
  1329. opt_key == "infill_first"
  1330. || opt_key == "wipe_into_infill"
  1331. || opt_key == "wipe_into_objects") {
  1332. invalidated |= m_print->invalidate_step(psWipeTower);
  1333. invalidated |= m_print->invalidate_step(psGCodeExport);
  1334. } else if (
  1335. opt_key == "brim_inside_holes"
  1336. || opt_key == "brim_ears"
  1337. || opt_key == "brim_ears_detection_length"
  1338. || opt_key == "brim_ears_max_angle"
  1339. || opt_key == "brim_ears_pattern"
  1340. || opt_key == "brim_per_object"
  1341. || opt_key == "brim_separation"
  1342. || opt_key == "brim_type") {
  1343. invalidated |= m_print->invalidate_step(psSkirtBrim);
  1344. // Brim is printed below supports, support invalidates brim and skirt.
  1345. steps.emplace_back(posSupportMaterial);
  1346. } else if (
  1347. opt_key == "brim_width"
  1348. || opt_key == "brim_width_interior") {
  1349. invalidated |= m_print->invalidate_step(psSkirtBrim);
  1350. // these two may change the ordering of first layer perimeters
  1351. steps.emplace_back(posPerimeters);
  1352. // Brim is printed below supports, support invalidates brim and skirt.
  1353. steps.emplace_back(posSupportMaterial);
  1354. } else {
  1355. // for legacy, if we can't handle this option let's invalidate all steps
  1356. this->invalidate_all_steps();
  1357. invalidated = true;
  1358. }
  1359. }
  1360. sort_remove_duplicates(steps);
  1361. for (PrintObjectStep step : steps)
  1362. invalidated |= this->invalidate_step(step);
  1363. return invalidated;
  1364. }
  1365. bool PrintObject::invalidate_step(PrintObjectStep step)
  1366. {
  1367. bool invalidated = Inherited::invalidate_step(step);
  1368. // propagate to dependent steps
  1369. if (step == posPerimeters) {
  1370. invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill, posIroning,
  1371. posSupportSpotsSearch, posEstimateCurledExtrusions, posCalculateOverhangingPerimeters, posSimplifyPath });
  1372. invalidated |= m_print->invalidate_steps({ psSkirtBrim });
  1373. } else if (step == posPrepareInfill) {
  1374. invalidated |= this->invalidate_steps({ posInfill, posIroning, posSupportSpotsSearch, posSimplifyPath });
  1375. } else if (step == posInfill) {
  1376. invalidated |= this->invalidate_steps({ posIroning, posSupportSpotsSearch, posSimplifyPath });
  1377. invalidated |= m_print->invalidate_steps({ psSkirtBrim });
  1378. } else if (step == posSlice) {
  1379. invalidated |= this->invalidate_steps({posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportSpotsSearch,
  1380. posSupportMaterial, posEstimateCurledExtrusions, posCalculateOverhangingPerimeters,
  1381. posSimplifyPath });
  1382. invalidated |= m_print->invalidate_steps({ psSkirtBrim });
  1383. m_slicing_params->valid = false;
  1384. } else if (step == posSupportMaterial) {
  1385. invalidated |= m_print->invalidate_steps({ psSkirtBrim, });
  1386. invalidated |= this->invalidate_steps({ posEstimateCurledExtrusions });
  1387. m_slicing_params->valid = false;
  1388. }
  1389. // invalidate alerts step always, since it depends on everything (except supports, but with supports enabled it is skipped anyway.)
  1390. invalidated |= m_print->invalidate_step(psAlertWhenSupportsNeeded);
  1391. // Wipe tower depends on the ordering of extruders, which in turn depends on everything.
  1392. // It also decides about what the wipe_into_infill / wipe_into_object features will do,
  1393. // and that too depends on many of the settings.
  1394. invalidated |= m_print->invalidate_step(psWipeTower);
  1395. // Invalidate G-code export in any case.
  1396. invalidated |= m_print->invalidate_step(psGCodeExport);
  1397. return invalidated;
  1398. }
  1399. bool PrintObject::invalidate_all_steps()
  1400. {
  1401. // First call the "invalidate" functions, which may cancel background processing.
  1402. bool result = Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
  1403. // Then reset some of the depending values.
  1404. m_slicing_params->valid = false;
  1405. return result;
  1406. }
  1407. // Called on main thread with stopped or paused background processing to let PrintObject release data for its milestones that were invalidated or canceled.
  1408. void PrintObject::cleanup()
  1409. {
  1410. if (this->query_reset_dirty_step_unguarded(posInfill))
  1411. this->clear_fills();
  1412. if (this->query_reset_dirty_step_unguarded(posSupportMaterial))
  1413. this->clear_support_layers();
  1414. }
  1415. //Fit to size helper
  1416. bool has_boundary_point(const MultiPoint& contour, const Point &point)
  1417. {
  1418. double dist = (contour.point_projection(point).first - point).cast<double>().norm();
  1419. return dist < SCALED_EPSILON;
  1420. }
  1421. bool has_boundary_point(const ExPolygon& expoly, const Point &point)
  1422. {
  1423. if (has_boundary_point(expoly.contour, point)) return true;
  1424. for (Polygons::const_iterator h = expoly.holes.begin(); h != expoly.holes.end(); ++h) {
  1425. if (has_boundary_point(*h,point)) return true;
  1426. }
  1427. return false;
  1428. }
  1429. // Function used by fit_to_size.
  1430. // It check if polygon_to_check can be decimated, using only point into allowedPoints and also cover polygon_to_cover
  1431. ExPolygon try_fit_to_size(ExPolygon polygon_to_check, const ExPolygons& allowedPoints) {
  1432. ExPolygon polygon_reduced = polygon_to_check;
  1433. size_t pos_check = 0;
  1434. bool has_del = false;
  1435. while ((polygon_reduced.contour.points.begin() + pos_check) != polygon_reduced.contour.points.end()) {
  1436. bool ok = false;
  1437. for (const ExPolygon &poly : allowedPoints) {
  1438. //return this->contains(point) || this->has_boundary_point(point);
  1439. if (poly.contains(*(polygon_reduced.contour.points.begin() + pos_check))
  1440. || has_boundary_point(poly, *(polygon_reduced.contour.points.begin() + pos_check))) {
  1441. ok = true;
  1442. has_del = true;
  1443. break;
  1444. }
  1445. }
  1446. if (ok) ++pos_check;
  1447. else polygon_reduced.contour.points.erase(polygon_reduced.contour.points.begin() + pos_check);
  1448. }
  1449. if (has_del) polygon_reduced.holes.clear();
  1450. return polygon_reduced;
  1451. }
  1452. ExPolygon try_fit_to_size2(ExPolygon polygon_to_check, const ExPolygon& allowedPoints) {
  1453. ExPolygon polygon_reduced = polygon_to_check;
  1454. size_t pos_check = 0;
  1455. while ((polygon_reduced.contour.points.begin() + pos_check) != polygon_reduced.contour.points.end()) {
  1456. //Point best_point = polygon_reduced.contour.points[pos_check].projection_onto(allowedPoints.contour);
  1457. Point best_point = allowedPoints.contour.point_projection(polygon_reduced.contour.points[pos_check]).first;
  1458. for (const Polygon& hole : allowedPoints.holes) {
  1459. Point hole_point = hole.point_projection(polygon_reduced.contour.points[pos_check]).first;
  1460. if ((hole_point - polygon_reduced.contour.points[pos_check]).norm() < (best_point - polygon_reduced.contour.points[pos_check]).norm())
  1461. best_point = hole_point;
  1462. }
  1463. if ((best_point - polygon_reduced.contour.points[pos_check]).norm() < scale_(0.01)) ++pos_check;
  1464. else polygon_reduced.contour.points.erase(polygon_reduced.contour.points.begin() + pos_check);
  1465. }
  1466. polygon_reduced.holes.clear();
  1467. return polygon_reduced;
  1468. }
  1469. // find one of the smallest polygon, growing polygon_to_cover, only using point into growing_area and covering polygon_to_cover.
  1470. ExPolygons dense_fill_fit_to_size(const ExPolygon& bad_polygon_to_cover,
  1471. const ExPolygon& growing_area, const coord_t offset, float coverage) {
  1472. //fix uncoverable area
  1473. ExPolygons polygons_to_cover = intersection_ex(bad_polygon_to_cover, growing_area);
  1474. if (polygons_to_cover.size() != 1)
  1475. return { growing_area };
  1476. const ExPolygon polygon_to_cover = polygons_to_cover.front();
  1477. //grow the polygon_to_check enough to cover polygon_to_cover
  1478. float current_coverage = coverage;
  1479. coord_t previous_offset = 0;
  1480. coord_t current_offset = offset;
  1481. ExPolygon polygon_reduced = try_fit_to_size2(polygon_to_cover, growing_area);
  1482. while (polygon_reduced.empty()) {
  1483. current_offset *= 2;
  1484. ExPolygons bigger_polygon = offset_ex(polygon_to_cover, double(current_offset));
  1485. if (bigger_polygon.size() != 1) break;
  1486. bigger_polygon = intersection_ex(bigger_polygon[0], growing_area);
  1487. if (bigger_polygon.size() != 1) break;
  1488. polygon_reduced = try_fit_to_size2(bigger_polygon[0], growing_area);
  1489. }
  1490. //ExPolygons to_check = offset_ex(polygon_to_cover, -offset);
  1491. ExPolygons not_covered = diff_ex(polygon_to_cover, polygon_reduced, ApplySafetyOffset::Yes);
  1492. while (!not_covered.empty()) {
  1493. //not enough, use a bigger offset
  1494. float percent_coverage = (float)(polygon_reduced.area() / growing_area.area());
  1495. float next_coverage = percent_coverage + (percent_coverage - current_coverage) * 4;
  1496. previous_offset = current_offset;
  1497. current_offset *= 2;
  1498. if (next_coverage < 0.1) current_offset *= 2;
  1499. //create the bigger polygon and test it
  1500. ExPolygons bigger_polygon = offset_ex(polygon_to_cover, double(current_offset));
  1501. if (bigger_polygon.size() != 1) {
  1502. // Error, growing a single polygon result in many/no other => abord
  1503. return ExPolygons();
  1504. }
  1505. bigger_polygon = intersection_ex(bigger_polygon[0], growing_area);
  1506. // After he intersection, we may have section of the bigger_polygon that jumped over a 'clif' to exist in an other area, have to remove them.
  1507. if (bigger_polygon.size() > 1) {
  1508. //remove polygon not in intersection with polygon_to_cover
  1509. for (int i = 0; i < (int)bigger_polygon.size(); i++) {
  1510. if (intersection_ex(bigger_polygon[i], polygon_to_cover).empty()) {
  1511. bigger_polygon.erase(bigger_polygon.begin() + i);
  1512. i--;
  1513. }
  1514. }
  1515. }
  1516. if (bigger_polygon.size() != 1 || bigger_polygon[0].area() > growing_area.area()) {
  1517. // Growing too much => we can as well use the full coverage, in this case
  1518. polygon_reduced = growing_area;
  1519. break;
  1520. //return ExPolygons() = { growing_area };
  1521. }
  1522. //polygon_reduced = try_fit_to_size(bigger_polygon[0], allowedPoints);
  1523. polygon_reduced = try_fit_to_size2(bigger_polygon[0], growing_area);
  1524. not_covered = diff_ex(polygon_to_cover, polygon_reduced, ApplySafetyOffset::Yes);
  1525. }
  1526. //ok, we have a good one, now try to optimise (unless there are almost no growth)
  1527. if (current_offset > offset * 3) {
  1528. //try to shrink
  1529. uint32_t nb_opti_max = 6;
  1530. for (uint32_t i = 0; i < nb_opti_max; ++i) {
  1531. coord_t new_offset = (previous_offset + current_offset) / 2;
  1532. ExPolygons bigger_polygon = offset_ex(polygon_to_cover, double(new_offset));
  1533. if (bigger_polygon.size() != 1) {
  1534. //Warn, growing a single polygon result in many/no other, use previous good result
  1535. break;
  1536. }
  1537. bigger_polygon = intersection_ex(bigger_polygon[0], growing_area);
  1538. if (bigger_polygon.size() != 1 || bigger_polygon[0].area() > growing_area.area()) {
  1539. //growing too much, use previous good result (imo, should not be possible to enter this branch)
  1540. break;
  1541. }
  1542. //ExPolygon polygon_test = try_fit_to_size(bigger_polygon[0], allowedPoints);
  1543. ExPolygon polygon_test = try_fit_to_size2(bigger_polygon[0], growing_area);
  1544. not_covered = diff_ex(polygon_to_cover, polygon_test, ApplySafetyOffset::Yes);
  1545. if (!not_covered.empty()) {
  1546. //bad, not enough, use a bigger offset
  1547. previous_offset = new_offset;
  1548. } else {
  1549. //good, we may now try a smaller offset
  1550. current_offset = new_offset;
  1551. polygon_reduced = polygon_test;
  1552. }
  1553. }
  1554. }
  1555. //return the area which cover the growing_area. Intersect it to retreive the holes.
  1556. ExPolygons to_print = intersection_ex(polygon_reduced, growing_area);
  1557. //remove polygon not in intersection with polygon_to_cover
  1558. for (int i = 0; i < (int)to_print.size(); i++) {
  1559. if (intersection_ex(to_print[i], polygon_to_cover).empty()) {
  1560. to_print.erase(to_print.begin() + i);
  1561. i--;
  1562. }
  1563. }
  1564. return to_print;
  1565. }
  1566. void PrintObject::tag_under_bridge() {
  1567. const float COEFF_SPLIT = 1.5;
  1568. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(this->print()->config().resolution.value));
  1569. for (size_t region_idx = 0; region_idx < this->print()->num_print_regions(); ++ region_idx) {
  1570. const PrintRegion* region = &this->print()->get_print_region(region_idx);
  1571. //count how many surface there are on each one
  1572. if (region->config().infill_dense.get_bool() && region->config().fill_density < 40) {
  1573. std::vector<LayerRegion*> layeridx2lregion;
  1574. std::vector<Surfaces> new_surfaces; //surface store, as you can't modify them when working in //
  1575. // store the LayerRegion on which we are working
  1576. layeridx2lregion.resize(this->layers().size(), nullptr);
  1577. new_surfaces.resize(this->layers().size(), Surfaces{});
  1578. for (size_t idx_layer = 0; idx_layer < this->layers().size(); ++idx_layer) {
  1579. LayerRegion* layerm = nullptr;
  1580. for (LayerRegion* lregion : this->layers()[idx_layer]->regions()) {
  1581. if (&lregion->region() == region) {
  1582. layerm = lregion;
  1583. break;
  1584. }
  1585. }
  1586. if (layerm != nullptr)
  1587. layeridx2lregion[idx_layer] = layerm;
  1588. }
  1589. // run in parallel, it's a costly thing.
  1590. Slic3r::parallel_for(size_t(0), this->layers().size() - 1,
  1591. [this, &layeridx2lregion, &new_surfaces, region, COEFF_SPLIT, scaled_resolution](const size_t idx_layer) {
  1592. // we our LayerRegion and the one on top
  1593. LayerRegion* layerm = layeridx2lregion[idx_layer];
  1594. const LayerRegion* previousOne = nullptr;
  1595. previousOne = layeridx2lregion[idx_layer + 1];
  1596. if (layerm != nullptr && previousOne != nullptr) {
  1597. Surfaces &surfs_to_add = new_surfaces[idx_layer];
  1598. // check all surfaces to cover
  1599. for (Surface& surface : layerm->set_fill_surfaces().surfaces) {
  1600. surface.maxNbSolidLayersOnTop = -1;
  1601. if (!surface.has_fill_solid()) {
  1602. Surfaces surf_to_add;
  1603. ExPolygons dense_polys;
  1604. std::vector<uint16_t> dense_priority;
  1605. const ExPolygons surfs_with_overlap = { surface.expolygon };
  1606. // create a surface with overlap to allow the dense thing to bond to the infill
  1607. coord_t scaled_width = layerm->flow(frInfill).scaled_width();
  1608. coord_t overlap = scaled_width / 4;
  1609. for (const ExPolygon& surf_with_overlap : surfs_with_overlap) {
  1610. ExPolygons sparse_polys = { surf_with_overlap };
  1611. //find the surface which intersect with the smallest maxNb possible
  1612. for (const Surface& upp : previousOne->fill_surfaces().surfaces) {
  1613. if (upp.has_fill_solid()) {
  1614. // i'm using intersection_ex because the result different than
  1615. // upp.expolygon.overlaps(surf.expolygon) or surf.expolygon.overlaps(upp.expolygon)
  1616. // and a little offset2 to remove the almost supported area
  1617. ExPolygons intersect =
  1618. offset2_ex(
  1619. intersection_ex(sparse_polys, ExPolygons{ upp.expolygon }, ApplySafetyOffset::Yes)
  1620. , (float)-layerm->flow(frInfill).scaled_width(), (float)layerm->flow(frInfill).scaled_width());
  1621. if (!intersect.empty()) {
  1622. DenseInfillAlgo algo = layerm->region().config().infill_dense_algo.value;
  1623. //if no infill, don't bother, it's always yes
  1624. if (region->config().fill_density.value == 0) {
  1625. if (dfaAutoOrEnlarged == algo)
  1626. algo = dfaAutomatic;
  1627. else if (dfaAutomatic != algo)
  1628. algo = dfaAutoNotFull;
  1629. }
  1630. if ( dfaAutoOrNothing == algo
  1631. || dfaAutoOrEnlarged == algo) {
  1632. //check if small enough
  1633. double max_nozzle_diam = 0;
  1634. for (uint16_t extruder_id : object_extruders()) {
  1635. max_nozzle_diam = std::max(max_nozzle_diam, print()->config().nozzle_diameter.get_at(extruder_id));
  1636. }
  1637. coordf_t min_width = scale_d(max_nozzle_diam) / region->config().fill_density.get_abs_value(1.);
  1638. ExPolygons smalls = offset_ex(intersect, -min_width);
  1639. //small enough ?
  1640. if (smalls.empty()) {
  1641. if (dfaAutoOrNothing == algo)
  1642. algo = dfaAutoNotFull;
  1643. if (dfaAutoOrEnlarged == algo)
  1644. algo = dfaAutomatic;
  1645. } else if (dfaAutoOrNothing == algo) {
  1646. algo = dfaDisabled;
  1647. }
  1648. }
  1649. if (dfaEnlarged == algo) {
  1650. //expand the area a bit
  1651. intersect = offset_ex(intersect, (scaled(layerm->region().config().external_infill_margin.get_abs_value(
  1652. region->config().perimeters == 0 ? 0 : (layerm->flow(frExternalPerimeter).width() + layerm->flow(frPerimeter).spacing() * (region->config().perimeters - 1))))));
  1653. intersect = intersection_ex(intersect, sparse_polys);
  1654. } else if (dfaDisabled == algo) {
  1655. intersect.clear();
  1656. } else {
  1657. double sparse_area = surf_with_overlap.area();
  1658. double area_to_cover = 0;
  1659. if (dfaAutoNotFull == algo) {
  1660. // calculate area to decide if area is small enough for autofill
  1661. for (ExPolygon poly_inter : intersect)
  1662. area_to_cover += poly_inter.area();
  1663. // if we have to fill everything, don't bother
  1664. if (area_to_cover * 1.1 > sparse_area)
  1665. intersect.clear();
  1666. }
  1667. //like intersect.empty() but more resilient
  1668. ExPolygons cover_intersect;
  1669. // it will be a dense infill, split the surface if needed
  1670. //ExPolygons cover_intersect;
  1671. for (ExPolygon& expoly_tocover : intersect) {
  1672. ExPolygons temp = dense_fill_fit_to_size(
  1673. expoly_tocover,
  1674. surf_with_overlap,
  1675. 4 * layerm->flow(frInfill).scaled_width(),
  1676. 0.01f);
  1677. cover_intersect.insert(cover_intersect.end(), temp.begin(), temp.end());
  1678. }
  1679. // calculate area to decide if area is small enough for autofill
  1680. if (dfaAutoOrEnlarged == algo) {
  1681. double area_dense_covered = 0;
  1682. for (ExPolygon poly_inter : cover_intersect)
  1683. area_dense_covered += poly_inter.area();
  1684. // if enlarge is smaller, use enlarge
  1685. intersect = offset_ex(intersect, (scaled(layerm->region().config().external_infill_margin.get_abs_value(
  1686. region->config().perimeters == 0 ? 0 : (layerm->flow(frExternalPerimeter).width() + layerm->flow(frPerimeter).spacing() * (region->config().perimeters - 1))))));
  1687. intersect = intersection_ex(intersect, sparse_polys);
  1688. double area_enlarged_covered = 0;
  1689. for (ExPolygon poly_inter : intersect)
  1690. area_enlarged_covered += poly_inter.area();
  1691. if (area_dense_covered < area_enlarged_covered) {
  1692. intersect = cover_intersect;
  1693. }
  1694. }else
  1695. intersect = cover_intersect;
  1696. }
  1697. if (!intersect.empty()) {
  1698. ExPolygons sparse_surfaces = diff_ex(sparse_polys, intersect, ApplySafetyOffset::Yes);
  1699. ExPolygons dense_surfaces = diff_ex(sparse_polys, sparse_surfaces, ApplySafetyOffset::Yes);
  1700. for (ExPolygon& poly : intersect) {
  1701. uint16_t priority = 1;
  1702. ExPolygons dense = { poly };
  1703. for (size_t idx_dense = 0; idx_dense < dense_polys.size(); idx_dense++) {
  1704. ExPolygons dense_test = diff_ex(dense, ExPolygons{ dense_polys[idx_dense] }, ApplySafetyOffset::Yes);
  1705. if (dense_test != dense) {
  1706. priority = std::max(priority, uint16_t(dense_priority[idx_dense] + 1));
  1707. }
  1708. dense = dense_test;
  1709. }
  1710. dense_polys.insert(dense_polys.end(), dense.begin(), dense.end());
  1711. for (size_t i = 0; i < dense.size(); i++)
  1712. dense_priority.push_back(priority);
  1713. }
  1714. //assign (copy)
  1715. sparse_polys = std::move(sparse_surfaces);
  1716. }
  1717. }
  1718. }
  1719. //check if we are full-dense
  1720. if (sparse_polys.empty()) break;
  1721. }
  1722. //check if we need to split the surface
  1723. if (!dense_polys.empty()) {
  1724. double area_dense = 0;
  1725. for (ExPolygon poly_inter : dense_polys) area_dense += poly_inter.area();
  1726. double area_sparse = 0;
  1727. for (ExPolygon poly_inter : sparse_polys) area_sparse += poly_inter.area();
  1728. // if almost no empty space, simplify by filling everything (else)
  1729. if (area_sparse > area_dense * 0.1) {
  1730. //split
  1731. //dense_polys = union_ex(dense_polys);
  1732. for (size_t idx_dense = 0; idx_dense < dense_polys.size(); idx_dense++) {
  1733. ExPolygon dense_poly = dense_polys[idx_dense];
  1734. //remove overlap with perimeter
  1735. ExPolygons offseted_dense_polys = layerm->fill_no_overlap_expolygons().empty()
  1736. ? ExPolygons{dense_poly}
  1737. : intersection_ex(ExPolygons{ dense_poly }, layerm->fill_no_overlap_expolygons());
  1738. //add overlap with everything
  1739. offseted_dense_polys = offset_ex(offseted_dense_polys, overlap);
  1740. ensure_valid(offseted_dense_polys, scaled_resolution);
  1741. for (ExPolygon offseted_dense_poly : offseted_dense_polys) {
  1742. Surface dense_surf(surface, offseted_dense_poly);
  1743. dense_surf.maxNbSolidLayersOnTop = 1;
  1744. dense_surf.priority = dense_priority[idx_dense];
  1745. surf_to_add.push_back(dense_surf);
  1746. }
  1747. }
  1748. sparse_polys = union_ex(sparse_polys);
  1749. ensure_valid(sparse_polys, scaled_resolution);
  1750. for (ExPolygon sparse_poly : sparse_polys) {
  1751. Surface sparse_surf(surface, sparse_poly);
  1752. surf_to_add.push_back(sparse_surf);
  1753. }
  1754. //layerm->fill_surfaces.surfaces.erase(it_surf);
  1755. } else {
  1756. surface.maxNbSolidLayersOnTop = 1;
  1757. surf_to_add.clear();
  1758. surface.expolygon.assert_valid();
  1759. surf_to_add.push_back(surface);
  1760. break;
  1761. }
  1762. } else {
  1763. surf_to_add.clear();
  1764. surface.expolygon.assert_valid();
  1765. surf_to_add.emplace_back(std::move(surface));
  1766. // mitigation: if not possible, don't try the others.
  1767. break;
  1768. }
  1769. }
  1770. // break go here
  1771. for(Surface &srf : surf_to_add) srf.expolygon.assert_valid();
  1772. surfs_to_add.insert(surfs_to_add.begin(), surf_to_add.begin(), surf_to_add.end());
  1773. } else {
  1774. surface.expolygon.assert_valid();
  1775. surfs_to_add.emplace_back(std::move(surface));
  1776. }
  1777. }
  1778. //layerm->fill_surfaces.surfaces = std::move(surfs_to_add);
  1779. }
  1780. });
  1781. // now set the new surfaces
  1782. for (size_t idx_layer = 0; idx_layer < this->layers().size() - 1; ++idx_layer) {
  1783. LayerRegion* lr = layeridx2lregion[idx_layer];
  1784. if(lr != nullptr && layeridx2lregion[idx_layer + 1] != nullptr) {
  1785. for(size_t i = 0; i < new_surfaces[idx_layer].size(); ++i) {
  1786. new_surfaces[idx_layer][i].expolygon.assert_valid();
  1787. if(new_surfaces[idx_layer][i].expolygon.contour.size() < 3){
  1788. new_surfaces[idx_layer].erase(new_surfaces[idx_layer].begin() + i);
  1789. --i;
  1790. }
  1791. }
  1792. lr->set_fill_surfaces().surfaces = new_surfaces[idx_layer];
  1793. }
  1794. }
  1795. }
  1796. }
  1797. }
  1798. // This function analyzes slices of a region (SurfaceCollection slices).
  1799. // Each region slice (instance of Surface) is analyzed, whether it is supported or whether it is the top surface.
  1800. // Initially all slices are of type stInternal.
  1801. // Slices are compared against the top / bottom slices and regions and classified to the following groups:
  1802. // stTop - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill.
  1803. // stBottomBridge - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft.
  1804. // stBottom - Part of a region, which is not supported by the same region, but it is supported either by another region, or by a soluble interface layer.
  1805. // stInternal - Part of a region, which is supported by the same region type.
  1806. // If a part of a region is of stBottom and stTop, the stBottom wins.
  1807. void PrintObject::detect_surfaces_type()
  1808. {
  1809. BOOST_LOG_TRIVIAL(info) << "Detecting solid surfaces..." << log_memory_info();
  1810. // Interface shells: the intersecting parts are treated as self standing objects supporting each other.
  1811. // Each of the objects will have a full number of top / bottom layers, even if these top / bottom layers
  1812. // are completely hidden inside a collective body of intersecting parts.
  1813. // This is useful if one of the parts is to be dissolved, or if it is transparent and the internal shells
  1814. // should be visible.
  1815. bool spiral_vase = this->print()->config().spiral_vase.value;
  1816. bool interface_shells = ! spiral_vase && m_config.interface_shells.value;
  1817. size_t num_layers = spiral_vase ? std::min(size_t(this->printing_region(0).config().bottom_solid_layers), m_layers.size()) : m_layers.size();
  1818. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  1819. BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " in parallel - start";
  1820. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  1821. for (Layer *layer : m_layers)
  1822. layer->m_regions[region_id]->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial");
  1823. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  1824. // If interface shells are allowed, the region->surfaces cannot be overwritten as they may be used by other threads.
  1825. // Cache the result of the following parallel_loop.
  1826. std::vector<Surfaces> surfaces_new;
  1827. if (interface_shells)
  1828. surfaces_new.assign(num_layers, Surfaces());
  1829. // If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating
  1830. // the support from the print.
  1831. bool has_bridges = !(m_config.support_material.value
  1832. && m_config.support_material_contact_distance_type.value == zdNone
  1833. && !m_config.dont_support_bridges);
  1834. SurfaceType surface_type_bottom_other =
  1835. !has_bridges ?
  1836. stPosBottom | stDensSolid :
  1837. stPosBottom | stDensSolid | stModBridge;
  1838. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(print()->config().resolution.value));
  1839. Slic3r::parallel_for(size_t(0),
  1840. spiral_vase ?
  1841. // In spiral vase mode, reserve the last layer for the top surface if more than 1 layer is planned for the vase bottom.
  1842. ((num_layers > 1) ? num_layers - 1 : num_layers) :
  1843. // In non-spiral vase mode, go over all layers.
  1844. m_layers.size(),
  1845. [this, region_id, interface_shells, &surfaces_new, has_bridges, surface_type_bottom_other, scaled_resolution]
  1846. (const size_t idx_layer) {
  1847. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  1848. m_print->throw_if_canceled();
  1849. // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << region_id << " and layer " << layer->print_z;
  1850. Layer *layer = m_layers[idx_layer];
  1851. LayerRegion *layerm = layer->get_region(region_id);
  1852. // comparison happens against the *full* slices (considering all regions)
  1853. // unless internal shells are requested
  1854. Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr;
  1855. Layer *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr;
  1856. // collapse very narrow parts (using the safety offset in the diff is not enough)
  1857. float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f;
  1858. ExPolygons layerm_slices_surfaces = to_expolygons(layerm->slices().surfaces);
  1859. // no_perimeter_full_bridge allow to put bridges where there are nothing, hence adding area to slice, that's why we need to start from the result of PerimeterGenerator.
  1860. if (layerm->region().config().no_perimeter_unsupported_algo.value == npuaFilled) {
  1861. append(layerm_slices_surfaces, to_expolygons(layerm->fill_surfaces().surfaces));
  1862. layerm_slices_surfaces = union_ex(layerm_slices_surfaces);
  1863. assert_valid(layerm_slices_surfaces);
  1864. }
  1865. // find top surfaces (difference between current surfaces
  1866. // of current layer and upper one)
  1867. Surfaces top;
  1868. if (upper_layer) {
  1869. for(auto &srf : top) srf.expolygon.assert_valid();
  1870. ExPolygons upper_slices = interface_shells ?
  1871. diff_ex(layerm_slices_surfaces, upper_layer->get_region(region_id)->slices().surfaces, ApplySafetyOffset::Yes) :
  1872. diff_ex(layerm_slices_surfaces, upper_layer->lslices(), ApplySafetyOffset::Yes);
  1873. ExPolygons new_top_surfaces = opening_ex(upper_slices, offset);
  1874. ensure_valid(new_top_surfaces, scaled_resolution);
  1875. assert_valid(new_top_surfaces);
  1876. surfaces_append(top, std::move(new_top_surfaces), stPosTop | stDensSolid);
  1877. for(Surface &srf : top) srf.expolygon.assert_valid();
  1878. } else {
  1879. // if no upper layer, all surfaces of this one are solid
  1880. // we clone surfaces because we're going to clear the slices collection
  1881. top = layerm->slices().surfaces;
  1882. for (Surface &surface : top)
  1883. surface.surface_type = stPosTop | stDensSolid;
  1884. for(Surface &srf : top) srf.expolygon.assert_valid();
  1885. }
  1886. // Find bottom surfaces (difference between current surfaces of current layer and lower one).
  1887. Surfaces bottom;
  1888. if (lower_layer) {
  1889. #if 0
  1890. //FIXME Why is this branch failing t\multi.t ?
  1891. Polygons lower_slices = interface_shells ?
  1892. to_polygons(lower_layer->get_region(region_id)->slices.surfaces) :
  1893. to_polygons(lower_layer->slices);
  1894. surfaces_append(bottom,
  1895. opening_ex(diff(layerm_slices_surfaces, lower_slices, true), offset),
  1896. surface_type_bottom_other);
  1897. #else
  1898. // Any surface lying on the void is a true bottom bridge (an overhang)
  1899. ExPolygons new_bot_surfs = opening_ex(
  1900. diff_ex(layerm_slices_surfaces, lower_layer->lslices(), ApplySafetyOffset::Yes),
  1901. offset);
  1902. ensure_valid(new_bot_surfs, scaled_resolution);
  1903. assert_valid(new_bot_surfs);
  1904. for(Surface &srf : bottom) srf.expolygon.assert_valid();
  1905. surfaces_append(
  1906. bottom,
  1907. std::move(new_bot_surfs),
  1908. surface_type_bottom_other);
  1909. for(auto &srf : bottom) srf.expolygon.assert_valid();
  1910. // if user requested internal shells, we need to identify surfaces
  1911. // lying on other slices not belonging to this region
  1912. if (interface_shells) {
  1913. // non-bridging bottom surfaces: any part of this layer lying
  1914. // on something else, excluding those lying on our own region
  1915. ExPolygons new_bot_interface_surfs =
  1916. opening_ex(diff_ex(intersection(layerm_slices_surfaces,
  1917. lower_layer->lslices()), // supported
  1918. lower_layer->get_region(region_id)->slices().surfaces,
  1919. ApplySafetyOffset::Yes),
  1920. offset); //-+
  1921. ensure_valid(new_bot_interface_surfs, scaled_resolution);
  1922. surfaces_append(bottom, std::move(new_bot_interface_surfs), stPosBottom | stDensSolid);
  1923. for(Surface &srf : bottom) srf.expolygon.assert_valid();
  1924. }
  1925. #endif
  1926. } else {
  1927. // if no lower layer, all surfaces of this one are solid
  1928. // we clone surfaces because we're going to clear the slices collection
  1929. bottom = layerm->slices().surfaces;
  1930. // Note: PS 2.4 changed that by "no bridge"... i dont know why?
  1931. for (Surface& surface : bottom)
  1932. surface.surface_type = //stPosBottom | stDensSolid;
  1933. (m_config.raft_layers.value > 0 && m_config.support_material_contact_distance_type.value != zdNone) ?
  1934. stPosBottom | stDensSolid | stModBridge : stPosBottom | stDensSolid;
  1935. }
  1936. // now, if the object contained a thin membrane, we could have overlapping bottom
  1937. // and top surfaces; let's do an intersection to discover them and consider them
  1938. // as bottom surfaces (to allow for bridge detection)
  1939. if (! top.empty() && ! bottom.empty()) {
  1940. // Polygons overlapping = intersection(to_polygons(top), to_polygons(bottom));
  1941. // Slic3r::debugf " layer %d contains %d membrane(s)\n", $layerm->layer->id, scalar(@$overlapping)
  1942. // if $Slic3r::debug;
  1943. Polygons top_polygons = to_polygons(std::move(top));
  1944. assert_valid(top_polygons);
  1945. for(auto &srf : bottom) srf.expolygon.assert_valid();
  1946. top.clear();
  1947. ExPolygons diff = diff_ex(top_polygons, bottom);
  1948. ensure_valid(diff, scaled_resolution);
  1949. assert_valid(diff);
  1950. surfaces_append(top, std::move(diff), stPosTop | stDensSolid);
  1951. }
  1952. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  1953. {
  1954. static int iRun = 0;
  1955. std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> expolygons_with_attributes;
  1956. expolygons_with_attributes.emplace_back(std::make_pair(union_ex(top), SVG::ExPolygonAttributes("green")));
  1957. expolygons_with_attributes.emplace_back(std::make_pair(union_ex(bottom), SVG::ExPolygonAttributes("brown")));
  1958. expolygons_with_attributes.emplace_back(std::make_pair(to_expolygons(layerm->slices().surfaces), SVG::ExPolygonAttributes("black")));
  1959. SVG::export_expolygons(debug_out_path("1_detect_surfaces_type_%d_region%d-layer_%f.svg", iRun ++, region_id, layer->print_z).c_str(), expolygons_with_attributes);
  1960. }
  1961. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  1962. // save surfaces to layer
  1963. Surfaces &surfaces_out = interface_shells ? surfaces_new[idx_layer] : layerm->m_slices.surfaces;
  1964. Surfaces surfaces_backup;
  1965. if (! interface_shells) {
  1966. surfaces_backup = std::move(surfaces_out);
  1967. for(auto &srf : surfaces_backup) srf.expolygon.assert_valid();
  1968. surfaces_out.clear();
  1969. }
  1970. //const Surfaces &surfaces_prev = interface_shells ? layerm_slices_surfaces : surfaces_backup;
  1971. const ExPolygons& surfaces_prev_expolys = interface_shells ? layerm_slices_surfaces : to_expolygons(surfaces_backup);
  1972. // find internal surfaces (difference between top/bottom surfaces and others)
  1973. {
  1974. Polygons topbottom = to_polygons(top);
  1975. polygons_append(topbottom, to_polygons(bottom));
  1976. assert_valid(topbottom);
  1977. assert_valid(surfaces_prev_expolys);
  1978. ExPolygons diff = diff_ex(surfaces_prev_expolys, topbottom);
  1979. ensure_valid(diff, scaled_resolution);
  1980. assert_valid(diff);
  1981. surfaces_append(surfaces_out, std::move(diff), stPosInternal | stDensSparse);
  1982. }
  1983. for(Surface &srf : top) srf.expolygon.assert_valid();
  1984. for(Surface &srf : bottom) srf.expolygon.assert_valid();
  1985. surfaces_append(surfaces_out, std::move(top));
  1986. surfaces_append(surfaces_out, std::move(bottom));
  1987. // Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n",
  1988. // $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug;
  1989. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  1990. layerm->export_region_slices_to_svg_debug("detect_surfaces_type-final");
  1991. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  1992. }
  1993. ); // for each layer of a region
  1994. m_print->throw_if_canceled();
  1995. if (interface_shells) {
  1996. // Move surfaces_new to layerm->slices.surfaces
  1997. // not '< num_layers' because spiral vase don't need it?
  1998. for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++idx_layer)
  1999. m_layers[idx_layer]->get_region(region_id)->m_slices.surfaces = std::move(surfaces_new[idx_layer]);
  2000. }
  2001. if (spiral_vase) {
  2002. if (num_layers > 1)
  2003. // Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
  2004. m_layers[num_layers - 1]->m_regions[region_id]->m_slices.set_type((stPosTop | stDensSolid));
  2005. for (size_t i = num_layers; i < m_layers.size(); ++i)
  2006. m_layers[i]->m_regions[region_id]->m_slices.set_type((stPosInternal | stDensSparse));
  2007. }
  2008. BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - start";
  2009. // Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
  2010. Slic3r::parallel_for(size_t(0), m_layers.size(),
  2011. [this, region_id](const size_t idx_layer) {
  2012. m_print->throw_if_canceled();
  2013. LayerRegion* layerm = m_layers[idx_layer]->get_region(region_id);
  2014. layerm->slices_to_fill_surfaces_clipped(
  2015. std::max(SCALED_EPSILON * 2,
  2016. std::max(scale_t(m_print->config().resolution) / 4,
  2017. scale_t(m_print->config().resolution_internal) / 8)));
  2018. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2019. layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final");
  2020. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2021. } // for each layer of a region
  2022. );
  2023. m_print->throw_if_canceled();
  2024. BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << region_id << " - clipping in parallel - end";
  2025. } // for each this->print->region_count
  2026. // Mark the object to have the region slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
  2027. m_typed_slices = true;
  2028. }
  2029. void PrintObject::apply_solid_infill_below_layer_area()
  2030. {
  2031. // compute the total layer surface for the bed, for solid_infill_below_layer_area
  2032. for (auto *my_layer : this->m_layers) {
  2033. bool exists = false;
  2034. for (auto *region : my_layer->m_regions) {
  2035. exists |= region->region().config().solid_infill_below_layer_area.value > 0;
  2036. }
  2037. if (!exists)
  2038. return;
  2039. double total_area = 0;
  2040. if (this->print()->config().complete_objects.value) {
  2041. // sequential printing: only consider myself
  2042. for (const ExPolygon &slice : my_layer->lslices()) { total_area += slice.area(); }
  2043. } else {
  2044. // parallel printing: get all objects
  2045. for (const PrintObject *object : this->print()->objects()) {
  2046. for (auto *layer : object->m_layers) {
  2047. if (std::abs(layer->print_z - my_layer->print_z) < EPSILON) {
  2048. for (const ExPolygon &slice : layer->lslices()) { total_area += slice.area(); }
  2049. }
  2050. }
  2051. }
  2052. }
  2053. // is it low enough to apply solid_infill_below_layer_area?
  2054. for (auto *region : my_layer->m_regions) {
  2055. if (!this->print()->config().spiral_vase.value && region->region().config().fill_density.value > 0) {
  2056. double min_area = scale_d(scale_d(region->region().config().solid_infill_below_layer_area.value));
  2057. for (Surface& surface : region->set_fill_surfaces()) {
  2058. if (surface.has_fill_sparse() && surface.has_pos_internal() && total_area <= min_area)
  2059. surface.surface_type = stPosInternal | stDensSolid;
  2060. }
  2061. }
  2062. }
  2063. }
  2064. }
  2065. void PrintObject::process_external_surfaces()
  2066. {
  2067. BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..." << log_memory_info();
  2068. // Cached surfaces covered by some extrusion, defining regions, over which the from the surfaces one layer higher are allowed to expand.
  2069. std::vector<Polygons> surfaces_covered;
  2070. // Is there any printing region, that has zero infill? If so, then we don't want the expansion to be performed over the complete voids, but only
  2071. // over voids, which are supported by the layer below.
  2072. bool has_voids = false;
  2073. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id)
  2074. if (this->printing_region(region_id).config().fill_density == 0) {
  2075. has_voids = true;
  2076. break;
  2077. }
  2078. if (has_voids && m_layers.size() > 1) {
  2079. // All but stInternal-sparse fill surfaces will get expanded and possibly trimmed.
  2080. std::vector<unsigned char> layer_expansions_and_voids(m_layers.size(), false);
  2081. // start at 1, because the only use is with `layer_expansions_and_voids[layer_idx + 1]`
  2082. for (size_t layer_idx = 1; layer_idx < m_layers.size(); ++layer_idx) {
  2083. const Layer* layer = m_layers[layer_idx];
  2084. bool expansions = false;
  2085. bool voids = false;
  2086. for (const LayerRegion *layerm : layer->regions()) {
  2087. for (const Surface &surface : layerm->fill_surfaces()) {
  2088. if (surface.surface_type == (stPosInternal | stDensSparse))
  2089. voids = true;
  2090. else
  2091. expansions = true;
  2092. if (voids && expansions) {
  2093. layer_expansions_and_voids[layer_idx] = true;
  2094. goto end;
  2095. }
  2096. }
  2097. }
  2098. end:;
  2099. }
  2100. BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - start";
  2101. surfaces_covered.resize(m_layers.size() - 1, Polygons());
  2102. Slic3r::parallel_for(size_t(0), m_layers.size() - 1,
  2103. [this, &surfaces_covered, &layer_expansions_and_voids](const size_t layer_idx) {
  2104. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2105. if (layer_expansions_and_voids[layer_idx + 1]) {
  2106. // Layer above is partially filled with solid infill (top, bottom, bridging...),
  2107. // while some sparse inill regions are empty (0% infill).
  2108. m_print->throw_if_canceled();
  2109. // Polygons voids;
  2110. // for (const LayerRegion *layerm : m_layers[layer_idx]->regions()) {
  2111. // if (layerm->region().config().fill_density.value == 0.)
  2112. // for (const Surface &surface : layerm->fill_surfaces())
  2113. // // Shrink the holes, let the layer above expand slightly inside the unsupported areas.
  2114. // polygons_append(voids, offset(surface.expolygon, unsupported_width));
  2115. // }
  2116. surfaces_covered[layer_idx] = to_polygons(this->m_layers[layer_idx]->lslices());
  2117. }
  2118. }
  2119. );
  2120. m_print->throw_if_canceled();
  2121. BOOST_LOG_TRIVIAL(debug) << "Collecting surfaces covered with extrusions in parallel - end";
  2122. }
  2123. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
  2124. BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start";
  2125. Slic3r::parallel_for(size_t(0), m_layers.size(),
  2126. [this, &surfaces_covered, region_id](const size_t layer_idx) {
  2127. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2128. m_print->throw_if_canceled();
  2129. // BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << m_layers[layer_idx]->print_z;
  2130. m_layers[layer_idx]->get_region(int(region_id))->process_external_surfaces(
  2131. // lower layer
  2132. (layer_idx == 0) ? nullptr : m_layers[layer_idx - 1],
  2133. // lower layer polygons with density > 0%
  2134. (layer_idx == 0 || surfaces_covered.empty() || surfaces_covered[layer_idx - 1].empty()) ? nullptr : &surfaces_covered[layer_idx - 1]);
  2135. }
  2136. );
  2137. m_print->throw_if_canceled();
  2138. BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - end";
  2139. }
  2140. if (this->has_raft() && ! m_layers.empty()) {
  2141. // Adjust bridge direction of 1st object layer over raft to be perpendicular to the raft contact layer direction.
  2142. Layer &layer = *m_layers.front();
  2143. assert(layer.id() > 0);
  2144. for (LayerRegion *layerm : layer.regions())
  2145. for (Surface &fill : layerm->m_fill_surfaces)
  2146. fill.bridge_angle = -1;
  2147. }
  2148. } // void PrintObject::process_external_surfaces()
  2149. void PrintObject::discover_vertical_shells()
  2150. {
  2151. BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..." << log_memory_info();
  2152. struct DiscoverVerticalShellsCacheEntry
  2153. {
  2154. // Collected polygons, offsetted
  2155. ExPolygons top_surfaces;
  2156. ExPolygons top_fill_surfaces;
  2157. ExPolygons top_perimeter_surfaces;
  2158. ExPolygons bottom_surfaces;
  2159. ExPolygons bottom_fill_surfaces;
  2160. ExPolygons bottom_perimeter_surfaces;
  2161. ExPolygons holes;
  2162. };
  2163. const bool spiral_vase = this->print()->config().spiral_vase.value;
  2164. const size_t num_layers = spiral_vase ? std::min(size_t(this->printing_region(0).config().bottom_solid_layers), m_layers.size()) : m_layers.size();
  2165. std::vector<DiscoverVerticalShellsCacheEntry> cache_top_botom_regions(num_layers, DiscoverVerticalShellsCacheEntry());
  2166. bool top_bottom_surfaces_all_regions = this->num_printing_regions() > 1 && ! m_config.interface_shells.value;
  2167. // static constexpr const float top_bottom_expansion_coeff = 1.05f;
  2168. // Just a tiny fraction of an infill extrusion width to merge neighbor regions reliably.
  2169. static constexpr const float top_bottom_expansion_coeff = 0.15f; //TODO check if not too little
  2170. if (top_bottom_surfaces_all_regions) {
  2171. // This is a multi-material print and interface_shells are disabled, meaning that the vertical shell thickness
  2172. // is calculated over all materials.
  2173. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - start : cache top / bottom";
  2174. const size_t num_regions = this->num_printing_regions();
  2175. Slic3r::parallel_for(size_t(0), num_layers,
  2176. [this, &cache_top_botom_regions, num_regions](const size_t idx_layer) {
  2177. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2178. m_print->throw_if_canceled();
  2179. const Layer& layer = *m_layers[idx_layer];
  2180. DiscoverVerticalShellsCacheEntry& cache = cache_top_botom_regions[idx_layer];
  2181. // Simulate single set of perimeters over all merged regions.
  2182. float perimeter_offset = 0.f;
  2183. float perimeter_min_spacing = FLT_MAX;
  2184. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2185. static size_t debug_idx = 0;
  2186. ++debug_idx;
  2187. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2188. for (size_t region_id = 0; region_id < num_regions; ++ region_id) {
  2189. LayerRegion &layerm = *layer.m_regions[region_id];
  2190. float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
  2191. // Top surfaces.
  2192. append(cache.top_surfaces, offset_ex(to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)), top_bottom_expansion));
  2193. append(cache.top_surfaces, offset_ex(to_expolygons(layerm.fill_surfaces().filter_by_type(stPosTop | stDensSolid)), top_bottom_expansion));
  2194. append(cache.top_fill_surfaces, offset_ex(to_expolygons(layerm.fill_surfaces().filter_by_type(stPosTop | stDensSolid)), top_bottom_expansion));
  2195. append(cache.top_perimeter_surfaces, to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)));
  2196. // Bottom surfaces.
  2197. auto surfaces_bottom = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge };
  2198. append(cache.bottom_surfaces, offset_ex(to_expolygons(layerm.slices().filter_by_types(surfaces_bottom)), top_bottom_expansion));
  2199. append(cache.bottom_surfaces, offset_ex(to_expolygons(layerm.fill_surfaces().filter_by_types(surfaces_bottom)), top_bottom_expansion));
  2200. append(cache.bottom_fill_surfaces, offset_ex(to_expolygons(layerm.fill_surfaces().filter_by_types(surfaces_bottom)), top_bottom_expansion));
  2201. append(cache.bottom_perimeter_surfaces, to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid)));
  2202. // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only.
  2203. // First find the maxium number of perimeters per region slice.
  2204. unsigned int perimeters = 0;
  2205. for (const Surface &s : layerm.slices())
  2206. perimeters = std::max<unsigned int>(perimeters, s.extra_perimeters);
  2207. perimeters += layerm.region().config().perimeters.value;
  2208. // Then calculate the infill offset.
  2209. if (perimeters > 0) {
  2210. Flow extflow = layerm.flow(frExternalPerimeter);
  2211. Flow flow = layerm.flow(frPerimeter);
  2212. perimeter_offset = std::max(perimeter_offset,
  2213. 0.5f * float(extflow.scaled_width() + extflow.scaled_spacing()) + (float(perimeters) - 1.f) * flow.scaled_spacing());
  2214. perimeter_min_spacing = std::min(perimeter_min_spacing, float(std::min(extflow.scaled_spacing(), flow.scaled_spacing())));
  2215. }
  2216. expolygons_append(cache.holes, layerm.fill_expolygons());
  2217. }
  2218. // Save some computing time by reducing the number of polygons.
  2219. cache.top_surfaces = union_ex(cache.top_surfaces);
  2220. cache.bottom_surfaces = union_ex(cache.bottom_surfaces);
  2221. // For a multi-material print, simulate perimeter / infill split as if only a single extruder has been used for the whole print.
  2222. if (perimeter_offset > 0.) {
  2223. // The layer.lslices are forced to merge by expanding them first.
  2224. expolygons_append(cache.holes, offset2_ex(layer.lslices(), 0.3f * perimeter_min_spacing, -perimeter_offset - 0.3f * perimeter_min_spacing));
  2225. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2226. {
  2227. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.lslices()));
  2228. svg.draw(layer.lslices(), "blue");
  2229. svg.draw(union_ex(cache.holes), "red");
  2230. svg.draw_outline(union_ex(cache.holes), "black", "blue", scale_(0.05));
  2231. svg.Close();
  2232. }
  2233. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2234. }
  2235. cache.holes = union_ex(cache.holes);
  2236. }
  2237. );
  2238. m_print->throw_if_canceled();
  2239. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells in parallel - end : cache top / bottom";
  2240. }
  2241. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  2242. const PrintRegion &region = this->printing_region(region_id);
  2243. //solid_over_perimeters value, to remove solid fill where there's only perimeters on multiple layers
  2244. const int nb_perimeter_layers_for_solid_fill = region.config().solid_over_perimeters.value;
  2245. const int min_layer_no_solid = region.config().bottom_solid_layers.value - 1;
  2246. const int min_z_no_solid = region.config().bottom_solid_min_thickness;
  2247. if (!top_bottom_surfaces_all_regions) {
  2248. // This is either a single material print, or a multi-material print and interface_shells are enabled, meaning that the vertical shell thickness
  2249. // is calculated over a single material.
  2250. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : cache top / bottom";
  2251. Slic3r::parallel_for(size_t(0), num_layers,
  2252. [this, region_id, &cache_top_botom_regions, nb_perimeter_layers_for_solid_fill, min_layer_no_solid, min_z_no_solid]
  2253. (const size_t idx_layer) {
  2254. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2255. m_print->throw_if_canceled();
  2256. Layer &layer = *m_layers[idx_layer];
  2257. LayerRegion &layerm = *layer.m_regions[region_id];
  2258. float top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * top_bottom_expansion_coeff;
  2259. float max_top_bottom_expansion = float(layerm.flow(frSolidInfill).scaled_spacing()) * (1.5f + top_bottom_expansion_coeff);
  2260. // Top surfaces.
  2261. auto& cache = cache_top_botom_regions[idx_layer];
  2262. ExPolygons raw_slice_temp = to_expolygons(layerm.slices().filter_by_type(stPosTop | stDensSolid));
  2263. ExPolygons raw_fill_temp = to_expolygons(layerm.fill_surfaces().filter_by_type(stPosTop | stDensSolid));
  2264. cache.top_surfaces = offset_ex(raw_slice_temp, top_bottom_expansion);
  2265. append(cache.top_surfaces, offset_ex(raw_fill_temp, top_bottom_expansion));
  2266. if (nb_perimeter_layers_for_solid_fill != 0) {
  2267. //it needs to be activated and we don't check the firs layers, where everything have to be solid.
  2268. cache.top_fill_surfaces = offset_ex(raw_fill_temp, max_top_bottom_expansion);
  2269. cache.top_perimeter_surfaces = raw_slice_temp;
  2270. }
  2271. // Bottom surfaces.
  2272. const auto surfaces_bottom = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge };
  2273. raw_slice_temp = to_expolygons(layerm.slices().filter_by_types(surfaces_bottom));
  2274. raw_fill_temp = to_expolygons(layerm.fill_surfaces().filter_by_types(surfaces_bottom));
  2275. cache.bottom_surfaces = offset_ex(raw_slice_temp, top_bottom_expansion);
  2276. append(cache.bottom_surfaces, offset_ex(raw_fill_temp, top_bottom_expansion));
  2277. if (nb_perimeter_layers_for_solid_fill != 0) {
  2278. cache.bottom_perimeter_surfaces = raw_slice_temp;
  2279. cache.bottom_fill_surfaces = offset_ex(raw_fill_temp, max_top_bottom_expansion);
  2280. }
  2281. // Holes over all regions. Only collect them once, they are valid for all idx_region iterations.
  2282. if (cache.holes.empty()) {
  2283. for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id)
  2284. expolygons_append(cache.holes, layer.get_region(region_id)->fill_expolygons());
  2285. }
  2286. }
  2287. );
  2288. m_print->throw_if_canceled();
  2289. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end : cache top / bottom";
  2290. }
  2291. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - start : ensure vertical wall thickness";
  2292. Slic3r::parallel_for(size_t(0), num_layers,
  2293. [this, region_id, &cache_top_botom_regions](const size_t idx_layer) {
  2294. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2295. // printf("discover_vertical_shells for %d \n", idx_layer);
  2296. m_print->throw_if_canceled();
  2297. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2298. static size_t debug_idx = 0;
  2299. ++ debug_idx;
  2300. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2301. Layer *layer = m_layers[idx_layer];
  2302. LayerRegion *layerm = layer->m_regions[region_id];
  2303. const PrintRegionConfig &region_config = layerm->region().config();
  2304. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2305. layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-initial");
  2306. layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-initial");
  2307. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2308. Flow solid_infill_flow = layerm->flow(frSolidInfill);
  2309. coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
  2310. // Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
  2311. ExPolygons shell;
  2312. ExPolygons fill_shell; // for nb_perimeter_layers_for_solid_fill
  2313. ExPolygons max_perimeter_shell; // for nb_perimeter_layers_for_solid_fill
  2314. ExPolygons holes;
  2315. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2316. ExPolygons shell_ex;
  2317. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2318. float min_perimeter_infill_spacing = float(infill_line_spacing) * 1.05f;
  2319. const int nb_perimeter_layers_for_solid_fill = region_config.solid_over_perimeters.value;
  2320. const int min_layer_no_solid = region_config.bottom_solid_layers.value - 1;
  2321. const int min_z_no_solid = region_config.bottom_solid_min_thickness;
  2322. #if 0
  2323. // #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2324. {
  2325. Slic3r::SVG svg_cummulative(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d.svg", debug_idx), this->bounding_box());
  2326. for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n) {
  2327. if (n < 0 || n >= (int)m_layers.size())
  2328. continue;
  2329. ExPolygons &expolys = m_layers[n]->perimeter_expolygons;
  2330. for (size_t i = 0; i < expolys.size(); ++ i) {
  2331. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", debug_idx, n, i), get_extents(expolys[i]));
  2332. svg.draw(expolys[i]);
  2333. svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
  2334. svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
  2335. svg.Close();
  2336. svg_cummulative.draw(expolys[i]);
  2337. svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
  2338. svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
  2339. }
  2340. }
  2341. }
  2342. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2343. expolygons_append(holes, cache_top_botom_regions[idx_layer].holes);
  2344. auto combine_holes = [&holes](const ExPolygons &holes2) {
  2345. if (holes.empty() || holes2.empty())
  2346. holes.clear();
  2347. else
  2348. holes = intersection_ex(holes, holes2);
  2349. };
  2350. auto combine_shells = [&shell](const ExPolygons &shells2) {
  2351. if (shell.empty())
  2352. shell = std::move(shells2);
  2353. else if (! shells2.empty()) {
  2354. expolygons_append(shell, shells2);
  2355. // Running the union_ using the Clipper library piece by piece is cheaper
  2356. // than running the union_ all at once.
  2357. shell = union_ex(shell);
  2358. }
  2359. };
  2360. static constexpr const bool one_more_layer_below_top_bottom_surfaces = false;
  2361. if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
  2362. // Gather top regions projected to this layer.
  2363. coordf_t print_z = layer->print_z;
  2364. int i = int(idx_layer) + 1;
  2365. int itop = int(idx_layer) + n_top_layers;
  2366. bool at_least_one_top_projected = false;
  2367. for (; i < int(cache_top_botom_regions.size()) &&
  2368. (i < itop || m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
  2369. ++ i) {
  2370. at_least_one_top_projected = true;
  2371. const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
  2372. combine_holes(cache.holes);
  2373. combine_shells(cache.top_surfaces);
  2374. if (nb_perimeter_layers_for_solid_fill != 0 && (idx_layer > min_layer_no_solid || print_z < min_z_no_solid)) {
  2375. if (!cache.top_fill_surfaces.empty()) {
  2376. expolygons_append(fill_shell, cache.top_fill_surfaces);
  2377. fill_shell = union_ex(fill_shell);
  2378. } if (nb_perimeter_layers_for_solid_fill > 1 && i - idx_layer < nb_perimeter_layers_for_solid_fill) {
  2379. expolygons_append(max_perimeter_shell, cache.top_perimeter_surfaces);
  2380. max_perimeter_shell = union_ex(max_perimeter_shell);
  2381. }
  2382. } }
  2383. if (!at_least_one_top_projected && i < int(cache_top_botom_regions.size())) {
  2384. // Lets consider this a special case - with only 1 top solid and minimal shell thickness settings, the
  2385. // boundaries of solid layers are not anchored over/under perimeters, so lets fix it by adding at least one
  2386. // perimeter width of area
  2387. ExPolygons anchor_area = intersection_ex(expand(cache_top_botom_regions[idx_layer].top_surfaces,
  2388. layerm->flow(frExternalPerimeter).scaled_spacing()),
  2389. to_polygons(m_layers[i]->lslices()));
  2390. combine_shells(anchor_area);
  2391. }
  2392. if (one_more_layer_below_top_bottom_surfaces)
  2393. if (i < int(cache_top_botom_regions.size()) &&
  2394. (i <= itop || m_layers[i]->bottom_z() - print_z < region_config.top_solid_min_thickness - EPSILON))
  2395. combine_holes(cache_top_botom_regions[i].holes);
  2396. }
  2397. if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
  2398. // Gather bottom regions projected to this layer.
  2399. coordf_t bottom_z = layer->bottom_z();
  2400. int i = int(idx_layer) - 1;
  2401. int ibottom = int(idx_layer) - n_bottom_layers;
  2402. bool at_least_one_bottom_projected = false;
  2403. for (; i >= 0 &&
  2404. (i > ibottom || bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
  2405. -- i) {
  2406. at_least_one_bottom_projected = true;
  2407. const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
  2408. combine_holes(cache.holes);
  2409. combine_shells(cache.bottom_surfaces);
  2410. if (nb_perimeter_layers_for_solid_fill != 0 && (idx_layer > min_layer_no_solid || layer->print_z < min_z_no_solid)) {
  2411. if (!cache.bottom_fill_surfaces.empty()) {
  2412. expolygons_append(fill_shell, cache.bottom_fill_surfaces);
  2413. fill_shell = union_ex(fill_shell);
  2414. }
  2415. if (nb_perimeter_layers_for_solid_fill > 1 && idx_layer - i < nb_perimeter_layers_for_solid_fill) {
  2416. expolygons_append(max_perimeter_shell, cache.bottom_perimeter_surfaces);
  2417. max_perimeter_shell = union_ex(max_perimeter_shell);
  2418. }
  2419. }
  2420. }
  2421. if (!at_least_one_bottom_projected && i >= 0) {
  2422. ExPolygons anchor_area = intersection_ex(expand(cache_top_botom_regions[idx_layer].bottom_surfaces,
  2423. layerm->flow(frExternalPerimeter).scaled_spacing()),
  2424. to_polygons(m_layers[i]->lslices()));
  2425. combine_shells(anchor_area);
  2426. }
  2427. if (one_more_layer_below_top_bottom_surfaces)
  2428. if (i >= 0 &&
  2429. (i > ibottom || bottom_z - m_layers[i]->print_z < region_config.bottom_solid_min_thickness - EPSILON))
  2430. combine_holes(cache_top_botom_regions[i].holes);
  2431. }
  2432. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2433. {
  2434. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-before-union-%d.svg", debug_idx), get_extents(shell));
  2435. svg.draw(shell);
  2436. svg.draw_outline(shell, "black", scale_(0.05));
  2437. svg.Close();
  2438. }
  2439. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2440. #if 0
  2441. // shell = union_(shell, true);
  2442. shell = union_(shell, false);
  2443. #endif
  2444. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2445. shell_ex = union_safety_offset_ex(shell);
  2446. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2447. //if (shell.empty())
  2448. // continue;
  2449. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2450. {
  2451. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-perimeters-after-union-%d.svg", debug_idx), get_extents(shell));
  2452. svg.draw(shell_ex);
  2453. svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
  2454. svg.Close();
  2455. }
  2456. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2457. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2458. {
  2459. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internal-wshell-%d.svg", debug_idx), get_extents(shell));
  2460. svg.draw(layerm->fill_surfaces().filter_by_type(stInternal), "yellow", 0.5);
  2461. svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternal), "black", "blue", scale_(0.05));
  2462. svg.draw(shell_ex, "blue", 0.5);
  2463. svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
  2464. svg.Close();
  2465. }
  2466. {
  2467. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalvoid-wshell-%d.svg", debug_idx), get_extents(shell));
  2468. svg.draw(layerm->fill_surfaces().filter_by_type(stInternalVoid), "yellow", 0.5);
  2469. svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
  2470. svg.draw(shell_ex, "blue", 0.5);
  2471. svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
  2472. svg.Close();
  2473. }
  2474. {
  2475. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-internalsolid-wshell-%d.svg", debug_idx), get_extents(shell));
  2476. svg.draw(layerm->fill_surfaces().filter_by_type(stInternalSolid), "yellow", 0.5);
  2477. svg.draw_outline(layerm->fill_surfaces().filter_by_type(stInternalSolid), "black", "blue", scale_(0.05));
  2478. svg.draw(shell_ex, "blue", 0.5);
  2479. svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
  2480. svg.Close();
  2481. }
  2482. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2483. // Trim the shells region by the internal & internal void surfaces.
  2484. const ExPolygons polygonsInternal = to_expolygons(layerm->fill_surfaces()
  2485. .filter_by_types({ stPosInternal | stDensSparse, stPosInternal | stDensVoid, stPosInternal | stDensSolid }));
  2486. {
  2487. shell = intersection_ex(shell, polygonsInternal, ApplySafetyOffset::Yes);
  2488. expolygons_append(shell, diff_ex(polygonsInternal, holes));
  2489. shell = union_ex(shell);
  2490. //check if a polygon is only over perimeter, in this case evict it (depends from nb_perimeter_layers_for_solid_fill value)
  2491. if (nb_perimeter_layers_for_solid_fill != 0 && (idx_layer > min_layer_no_solid || layer->print_z < min_z_no_solid)) {
  2492. ExPolygons toadd;
  2493. for (int i = 0; i < shell.size(); i++) {
  2494. if (nb_perimeter_layers_for_solid_fill < 2 || intersection_ex(ExPolygons{ shell[i] }, max_perimeter_shell, ApplySafetyOffset::No).empty()) {
  2495. ExPolygons expoly = intersection_ex(ExPolygons{ shell[i] }, fill_shell);
  2496. toadd.insert(toadd.end(), expoly.begin(), expoly.end());
  2497. shell.erase(shell.begin() + i);
  2498. i--;
  2499. }
  2500. }
  2501. expolygons_append(shell, toadd);
  2502. }
  2503. }
  2504. if (shell.empty())
  2505. return; //continue (next layer)
  2506. // Append the internal solids, so they will be merged with the new ones.
  2507. expolygons_append(shell, to_expolygons(layerm->fill_surfaces().filter_by_type(stPosInternal | stDensSolid)));
  2508. // These regions will be filled by a rectilinear full infill. Currently this type of infill
  2509. // only fills regions, which fit at least a single line. To avoid gaps in the sparse infill,
  2510. // make sure that this region does not contain parts narrower than the infill spacing width.
  2511. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2512. Polygons shell_before = shell;
  2513. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2514. ExPolygons regularized_shell;
  2515. {
  2516. // Open to remove (filter out) regions narrower than a bit less than an infill extrusion line width.
  2517. // Such narrow regions are difficult to fill in with a gap fill algorithm (or Arachne), however they are most likely
  2518. // not needed for print stability / quality.
  2519. const float narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing;
  2520. // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill,
  2521. // thus they will be merged into the solid infill.
  2522. const float narrow_sparse_infill_region_radius = 0.5f * 1.2f * min_perimeter_infill_spacing;
  2523. // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
  2524. const float tiny_overlap_radius = 0.2f * min_perimeter_infill_spacing;
  2525. regularized_shell = shrink_ex(offset2_ex(union_ex(shell),
  2526. // Open to remove (filter out) regions narrower than an infill extrusion line width.
  2527. -narrow_ensure_vertical_wall_thickness_region_radius,
  2528. // Then close gaps narrower than 1.2 * line width, such gaps are difficult to fill in with sparse infill.
  2529. narrow_ensure_vertical_wall_thickness_region_radius + narrow_sparse_infill_region_radius, ClipperLib::jtSquare),
  2530. // Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
  2531. narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare);
  2532. Polygons object_volume;
  2533. Polygons internal_volume;
  2534. {
  2535. Polygons shrinked_bottom_slice = idx_layer > 0 ? to_polygons(m_layers[idx_layer - 1]->lslices()) : Polygons{};
  2536. Polygons shrinked_upper_slice = (idx_layer + 1) < m_layers.size() ?
  2537. to_polygons(m_layers[idx_layer + 1]->lslices()) :
  2538. Polygons{};
  2539. object_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
  2540. //internal_volume = closing(polygonsInternal, float(SCALED_EPSILON));
  2541. internal_volume = offset2(polygonsInternal, float(SCALED_EPSILON), -float(SCALED_EPSILON));
  2542. }
  2543. // The regularization operation may cause scattered tiny drops on the smooth parts of the model, filter them out
  2544. // If the region checks both following conditions, it is removed:
  2545. // 1. the area is very small,
  2546. // OR the area is quite small and it is fully wrapped in model (not visible)
  2547. // the in-model condition is there due to small sloping surfaces, e.g. top of the hull of the benchy
  2548. // 2. the area does not fully cover an internal polygon
  2549. // This is there mainly for a very thin parts, where the solid layers would be missing if the part area is quite small
  2550. regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(),
  2551. [&internal_volume, &min_perimeter_infill_spacing,
  2552. &object_volume](const ExPolygon &p) {
  2553. return (p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
  2554. (p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
  2555. diff(to_polygons(p), object_volume).empty())) &&
  2556. diff(internal_volume,
  2557. expand(to_polygons(p), min_perimeter_infill_spacing))
  2558. .size() >= internal_volume.size();
  2559. }),
  2560. regularized_shell.end());
  2561. }
  2562. if (regularized_shell.empty())
  2563. return; //continue (next layer)
  2564. ExPolygons new_internal_solid = intersection_ex(polygonsInternal, regularized_shell);
  2565. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2566. {
  2567. Slic3r::SVG svg(debug_out_path("discover_vertical_shells-regularized-%d.svg", debug_idx), get_extents(shell_before));
  2568. // Source shell.
  2569. svg.draw(union_safety_offset_ex(shell_before));
  2570. // Shell trimmed to the internal surfaces.
  2571. svg.draw_outline(union_safety_offset_ex(shell), "black", "blue", scale_(0.05));
  2572. // Regularized infill region.
  2573. svg.draw_outline(new_internal_solid, "red", "magenta", scale_(0.05));
  2574. svg.Close();
  2575. }
  2576. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2577. // Trim the internal & internalvoid by the shell.
  2578. Slic3r::ExPolygons new_internal = diff_ex(to_expolygons(layerm->fill_surfaces().filter_by_type(stPosInternal | stDensSparse)), regularized_shell);
  2579. Slic3r::ExPolygons new_internal_void = diff_ex(to_expolygons(layerm->fill_surfaces().filter_by_type(stPosInternal | stDensVoid)), regularized_shell);
  2580. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2581. {
  2582. SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal-%d.svg", debug_idx), get_extents(shell), new_internal, "black", "blue", scale_(0.05));
  2583. SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal_void-%d.svg", debug_idx), get_extents(shell), new_internal_void, "black", "blue", scale_(0.05));
  2584. SVG::export_expolygons(debug_out_path("discover_vertical_shells-new_internal_solid-%d.svg", debug_idx), get_extents(shell), new_internal_solid, "black", "blue", scale_(0.05));
  2585. }
  2586. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2587. // Assign resulting internal surfaces to layer.
  2588. layerm->m_fill_surfaces.keep_types({ stPosTop | stDensSolid, stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge });
  2589. //layerm->m_fill_surfaces.keep_types_flag(stPosTop | stPosBottom);
  2590. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(print()->config().resolution.value));
  2591. ensure_valid(new_internal, scaled_resolution);
  2592. ensure_valid(new_internal_void, scaled_resolution);
  2593. ensure_valid(new_internal_solid, scaled_resolution);
  2594. layerm->m_fill_surfaces.append(new_internal, stPosInternal | stDensSparse);
  2595. layerm->m_fill_surfaces.append(new_internal_void, stPosInternal | stDensVoid);
  2596. layerm->m_fill_surfaces.append(new_internal_solid, stPosInternal | stDensSolid);
  2597. } // for each layer
  2598. );
  2599. m_print->throw_if_canceled();
  2600. BOOST_LOG_TRIVIAL(debug) << "Discovering vertical shells for region " << region_id << " in parallel - end";
  2601. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  2602. for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++idx_layer) {
  2603. LayerRegion *layerm = m_layers[idx_layer]->get_region(region_id);
  2604. layerm->export_region_slices_to_svg_debug("3_discover_vertical_shells-final");
  2605. layerm->export_region_fill_surfaces_to_svg_debug("3_discover_vertical_shells-final");
  2606. }
  2607. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  2608. } // for each region
  2609. } // void PrintObject::discover_vertical_shells()
  2610. // #define DEBUG_BRIDGE_OVER_INFILL
  2611. #ifdef DEBUG_BRIDGE_OVER_INFILL
  2612. template<typename T> void debug_draw(std::string name, const T& a, const T& b, const T& c, const T& d)
  2613. {
  2614. std::vector<std::string> colors = {"red", "green", "blue", "orange"};
  2615. BoundingBox bbox = get_extents(a);
  2616. bbox.merge(get_extents(b));
  2617. bbox.merge(get_extents(c));
  2618. bbox.merge(get_extents(d));
  2619. bbox.offset(scale_(1.));
  2620. ::Slic3r::SVG svg(debug_out_path(name.c_str()).c_str(), bbox);
  2621. svg.draw(a, colors[0], scale_(0.3));
  2622. svg.draw(b, colors[1], scale_(0.23));
  2623. svg.draw(c, colors[2], scale_(0.16));
  2624. svg.draw(d, colors[3], scale_(0.10));
  2625. svg.Close();
  2626. }
  2627. #endif
  2628. /* This method applies overextrude flow to the first internal solid layer above
  2629. bridge (which is over sparse infill) note: it's almost complete copy/paste from the method behind,
  2630. i think it should be merged before gitpull that.
  2631. */
  2632. void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it)
  2633. {
  2634. BOOST_LOG_TRIVIAL(info) << "overextrude over Bridge...";
  2635. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(print()->config().resolution.value));
  2636. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
  2637. const PrintRegion& region = this->printing_region(region_id);
  2638. // skip over-bridging in case there are no modification
  2639. if (region.config().over_bridge_flow_ratio.get_abs_value(1) == 1) continue;
  2640. for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++layer_it) {
  2641. // skip first layer
  2642. if (layer_it == this->layers().begin()) continue;
  2643. Layer* layer = *layer_it;
  2644. LayerRegion* layerm = layer->regions()[region_id];
  2645. Polygons poly_to_check;
  2646. // extract the surfaces that might be transformed
  2647. layerm->fill_surfaces().filter_by_type(st_to_replace, &poly_to_check);
  2648. Polygons poly_to_replace = poly_to_check;
  2649. // check the lower layer
  2650. if (int(layer_it - this->layers().begin()) - 1 >= 0) {
  2651. const Layer* lower_layer = this->layers()[int(layer_it - this->layers().begin()) - 1];
  2652. // iterate through regions and collect internal surfaces
  2653. Polygons lower_internal;
  2654. for (LayerRegion* lower_layerm : lower_layer->m_regions) {
  2655. lower_layerm->fill_surfaces().filter_by_type(st_under_it, &lower_internal);
  2656. }
  2657. // intersect such lower internal surfaces with the candidate solid surfaces
  2658. poly_to_replace = intersection(poly_to_replace, lower_internal);
  2659. }
  2660. if (poly_to_replace.empty()) continue;
  2661. // compute the remaning internal solid surfaces as difference
  2662. ExPolygons not_expoly_to_replace = ensure_valid(diff_ex(poly_to_check, poly_to_replace, ApplySafetyOffset::Yes), scaled_resolution);
  2663. // build the new collection of fill_surfaces
  2664. {
  2665. Surfaces new_surfaces;
  2666. for (Surfaces::const_iterator surface = layerm->fill_surfaces().surfaces.begin(); surface != layerm->fill_surfaces().surfaces.end(); ++surface) {
  2667. if (surface->surface_type != st_to_replace) {
  2668. surface->expolygon.assert_valid();
  2669. new_surfaces.push_back(*surface);
  2670. }
  2671. }
  2672. for (ExPolygon& ex : ensure_valid(union_ex(poly_to_replace), scaled_resolution)) {
  2673. ex.assert_valid();
  2674. new_surfaces.push_back(Surface(st_replacement, ex));
  2675. }
  2676. for (ExPolygon& ex : not_expoly_to_replace) {
  2677. ex.assert_valid();
  2678. new_surfaces.push_back(Surface(st_to_replace, ex));
  2679. }
  2680. layerm->set_fill_surfaces().surfaces = new_surfaces;
  2681. }
  2682. }
  2683. }
  2684. }
  2685. // This method applies bridge flow to the first internal solid layer above sparse infill.
  2686. void PrintObject::bridge_over_infill()
  2687. {
  2688. BOOST_LOG_TRIVIAL(info) << "Bridge over infill - Start" << log_memory_info();
  2689. struct CandidateSurface
  2690. {
  2691. CandidateSurface(const Surface *original_surface,
  2692. int layer_index,
  2693. Polygons new_polys,
  2694. const LayerRegion *region,
  2695. double bridge_angle)
  2696. : original_surface(original_surface)
  2697. , layer_index(layer_index)
  2698. , new_polys(new_polys)
  2699. , region(region)
  2700. , bridge_angle(bridge_angle)
  2701. {}
  2702. const Surface *original_surface;
  2703. int layer_index;
  2704. Polygons new_polys;
  2705. const LayerRegion *region;
  2706. double bridge_angle;
  2707. };
  2708. std::map<size_t, std::vector<CandidateSurface>> surfaces_by_layer;
  2709. // SECTION to gather and filter surfaces for expanding, and then cluster them by layer
  2710. {
  2711. tbb::concurrent_vector<CandidateSurface> candidate_surfaces;
  2712. Slic3r::parallel_for(size_t(0), this->layers().size(),
  2713. [po = static_cast<const PrintObject *>(this), &candidate_surfaces](const size_t lidx) {
  2714. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2715. const Layer *layer = po->get_layer(lidx);
  2716. if (layer->lower_layer != nullptr) {
  2717. double spacing = layer->regions().front()->flow(frSolidInfill).scaled_spacing();
  2718. // unsupported area will serve as a filter for polygons worth bridging.
  2719. Polygons unsupported_area;
  2720. Polygons lower_layer_solids;
  2721. for (const LayerRegion *region : layer->lower_layer->regions()) {
  2722. Polygons fill_polys = to_polygons(region->fill_expolygons());
  2723. // initially consider the whole layer unsupported, but also gather solid layers to later cut off supported parts
  2724. unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end());
  2725. for (const Surface &surface : region->fill_surfaces()) {
  2726. // > 80 instead of ==100, because at 80% it's like solid for bridge, it doesn't have space.
  2727. if ( (surface.surface_type & stDensSolid) == stDensSolid || region->region().config().fill_density.value > 80) {
  2728. Polygons p = to_polygons(surface.expolygon);
  2729. lower_layer_solids.insert(lower_layer_solids.end(), p.begin(), p.end());
  2730. }
  2731. }
  2732. }
  2733. unsupported_area = closing(unsupported_area, float(SCALED_EPSILON));
  2734. // By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
  2735. // NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
  2736. lower_layer_solids = shrink(lower_layer_solids, 1 * spacing); // first remove thin regions that will not support anything
  2737. lower_layer_solids = expand(lower_layer_solids, (1 + 3) * spacing); // then expand back (opening), and further for parts supported by internal solids
  2738. // By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
  2739. unsupported_area = shrink(unsupported_area, 3 * spacing);
  2740. unsupported_area = diff(unsupported_area, lower_layer_solids);
  2741. for (const LayerRegion *region : layer->regions()) {
  2742. SurfacesPtr region_internal_solids = region->fill_surfaces().filter_by_type(stPosInternal | stDensSolid);
  2743. for (const Surface *s : region_internal_solids) {
  2744. Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area);
  2745. // The following flag marks those surfaces, which overlap with unuspported area, but at least part of them is supported.
  2746. // These regions can be filtered by area, because they for sure are touching solids on lower layers, and it does not make sense to bridge their tiny overhangs
  2747. bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON;
  2748. if (!unsupported.empty() && (!partially_supported || area(unsupported) > 3 * 3 * spacing * spacing)) {
  2749. Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 4 * spacing));
  2750. // after we extracted the part worth briding, we go over the leftovers and merge the tiny ones back, to not brake the surface too much
  2751. for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) {
  2752. double area = p.area();
  2753. if (area < spacing * scale_(12.0) && area > spacing * spacing) {
  2754. worth_bridging.push_back(p);
  2755. }
  2756. }
  2757. worth_bridging = intersection(closing(worth_bridging, float(SCALED_EPSILON)), s->expolygon);
  2758. candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0));
  2759. #ifdef DEBUG_BRIDGE_OVER_INFILL
  2760. debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)),
  2761. to_lines(region->layer()->lslices()), to_lines(s->expolygon), to_lines(worth_bridging),
  2762. to_lines(unsupported_area));
  2763. #endif
  2764. #ifdef DEBUG_BRIDGE_OVER_INFILL
  2765. debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(unsupported)),
  2766. to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))),
  2767. to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))),
  2768. to_lines(unsupported_area));
  2769. #endif
  2770. }
  2771. }
  2772. }
  2773. }
  2774. });
  2775. for (const CandidateSurface &c : candidate_surfaces) {
  2776. surfaces_by_layer[c.layer_index].push_back(c);
  2777. }
  2778. }
  2779. // LIGHTNING INFILL SECTION - If lightning infill is used somewhere, we check the areas that are going to be bridges, and those that rely on the
  2780. // lightning infill under them get expanded. This somewhat helps to ensure that most of the extrusions are anchored to the lightning infill at the ends.
  2781. // It requires modifying this instance of print object in a specific way, so that we do not invalidate the pointers in our surfaces_by_layer structure.
  2782. bool has_lightning_infill = false;
  2783. for (size_t i = 0; i < this->num_printing_regions(); i++) {
  2784. if (this->printing_region(i).config().fill_pattern.value == InfillPattern::ipLightning) {
  2785. has_lightning_infill = true;
  2786. break;
  2787. }
  2788. }
  2789. if (has_lightning_infill) {
  2790. // Prepare backup data for the Layer Region infills. Before modfiyng the layer region, we backup its fill surfaces by moving! them into this map.
  2791. // then a copy is created, modifiyed and passed to lightning infill generator. After generator is created, we restore the original state of the fills
  2792. // again by moving the data from this map back to the layer regions. This ensures that pointers to surfaces stay valid.
  2793. std::map<size_t, std::map<const LayerRegion *, SurfaceCollection>> backup_surfaces;
  2794. for (size_t lidx = 0; lidx < this->layer_count(); lidx++) {
  2795. backup_surfaces[lidx] = {};
  2796. }
  2797. Slic3r::parallel_for(size_t(0), this->layers().size(),
  2798. [po = this, &backup_surfaces, &surfaces_by_layer](const size_t lidx) {
  2799. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2800. if (surfaces_by_layer.find(lidx) == surfaces_by_layer.end())
  2801. return; //continue (next layer)
  2802. Layer *layer = po->get_layer(lidx);
  2803. const Layer *lower_layer = layer->lower_layer;
  2804. if (lower_layer == nullptr)
  2805. return; //continue (next layer)
  2806. Polygons lightning_fill;
  2807. for (const LayerRegion *region : lower_layer->regions()) {
  2808. if (region->region().config().fill_pattern.value == InfillPattern::ipLightning) {
  2809. Polygons lf = to_polygons(region->fill_surfaces().filter_by_type(stPosInternal | stDensSparse));
  2810. lightning_fill.insert(lightning_fill.end(), lf.begin(), lf.end());
  2811. }
  2812. }
  2813. if (lightning_fill.empty())
  2814. return; //continue (next layer)
  2815. for (LayerRegion *region : layer->regions()) {
  2816. backup_surfaces[lidx][region] = std::move(
  2817. region->m_fill_surfaces); // Make backup copy by move!! so that pointers in candidate surfaces stay valid
  2818. // Copy the surfaces back, this will make copy, but we will later discard it anyway
  2819. region->m_fill_surfaces = backup_surfaces[lidx][region];
  2820. for(auto &srf : region->m_fill_surfaces)
  2821. srf.expolygon.assert_valid();
  2822. }
  2823. for (LayerRegion *region : layer->regions()) {
  2824. ExPolygons sparse_infill = to_expolygons(region->fill_surfaces().filter_by_type(stPosInternal | stDensSparse));
  2825. ExPolygons solid_infill = to_expolygons(region->fill_surfaces().filter_by_type(stPosInternal | stDensSolid));
  2826. if (sparse_infill.empty()) {
  2827. break;
  2828. }
  2829. for (const auto &surface : surfaces_by_layer[lidx]) {
  2830. if (surface.region != region)
  2831. continue;
  2832. ExPolygons expansion = intersection_ex(sparse_infill, expand(surface.new_polys, scaled<float>(3.0)));
  2833. solid_infill.insert(solid_infill.end(), expansion.begin(), expansion.end());
  2834. }
  2835. solid_infill = union_safety_offset_ex(solid_infill);
  2836. sparse_infill = diff_ex(sparse_infill, solid_infill);
  2837. region->m_fill_surfaces.remove_types({stPosInternal | stDensSolid, stPosInternal | stDensSparse});
  2838. for (const ExPolygon &ep : solid_infill) {
  2839. ep.assert_valid();
  2840. region->m_fill_surfaces.surfaces.emplace_back(stPosInternal | stDensSolid, ep);
  2841. }
  2842. for (const ExPolygon &ep : sparse_infill) {
  2843. ep.assert_valid();
  2844. region->m_fill_surfaces.surfaces.emplace_back(stPosInternal | stDensSparse, ep);
  2845. }
  2846. }
  2847. }
  2848. );
  2849. // Use the modified surfaces to generate expanded lightning anchors
  2850. this->m_lightning_generator = this->prepare_lightning_infill_data();
  2851. // And now restore carefully the original surfaces, again using move to avoid reallocation and preserving the validity of the
  2852. // pointers in surface candidates
  2853. for (size_t lidx = 0; lidx < this->layer_count(); lidx++) {
  2854. Layer *layer = this->get_layer(lidx);
  2855. for (LayerRegion *region : layer->regions()) {
  2856. if (backup_surfaces[lidx].find(region) != backup_surfaces[lidx].end()) {
  2857. region->m_fill_surfaces = std::move(backup_surfaces[lidx][region]);
  2858. for(auto &srf : region->m_fill_surfaces)
  2859. srf.expolygon.assert_valid();
  2860. }
  2861. }
  2862. }
  2863. }
  2864. std::map<size_t, Polylines> infill_lines;
  2865. // SECTION to generate infill polylines
  2866. {
  2867. std::vector<std::pair<const Surface *, float>> surfaces_w_bottom_z;
  2868. for (const auto &pair : surfaces_by_layer) {
  2869. for (const CandidateSurface &c : pair.second) {
  2870. surfaces_w_bottom_z.emplace_back(c.original_surface, c.region->m_layer->bottom_z());
  2871. }
  2872. }
  2873. this->m_adaptive_fill_octrees = this->prepare_adaptive_infill_data(surfaces_w_bottom_z);
  2874. std::vector<size_t> layers_to_generate_infill;
  2875. for (const auto &pair : surfaces_by_layer) {
  2876. assert(pair.first > 0);
  2877. infill_lines[pair.first - 1] = {};
  2878. layers_to_generate_infill.push_back(pair.first - 1);
  2879. }
  2880. Slic3r::parallel_for(size_t(0), layers_to_generate_infill.size(),
  2881. [po = static_cast<const PrintObject *>(this), &layers_to_generate_infill, &infill_lines]
  2882. (const size_t job_idx) {
  2883. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2884. size_t lidx = layers_to_generate_infill[job_idx];
  2885. infill_lines.at(
  2886. lidx) = po->get_layer(lidx)->generate_sparse_infill_polylines_for_anchoring(po->m_adaptive_fill_octrees.first.get(),
  2887. po->m_adaptive_fill_octrees.second.get(),
  2888. po->m_lightning_generator.get());
  2889. }
  2890. );
  2891. #ifdef DEBUG_BRIDGE_OVER_INFILL
  2892. for (const auto &il : infill_lines) {
  2893. debug_draw(std::to_string(il.first) + "_infill_lines", to_lines(get_layer(il.first)->lslices()), to_lines(il.second), {}, {});
  2894. }
  2895. #endif
  2896. }
  2897. // cluster layers by depth needed for thick bridges. Each cluster is to be processed by single thread sequentially, so that bridges cannot appear one on another
  2898. std::vector<std::vector<size_t>> clustered_layers_for_threads;
  2899. float target_flow_height_factor = 0.9f;
  2900. {
  2901. std::vector<size_t> layers_with_candidates;
  2902. std::map<size_t, Polygons> layer_area_covered_by_candidates;
  2903. for (const auto& pair : surfaces_by_layer) {
  2904. layers_with_candidates.push_back(pair.first);
  2905. layer_area_covered_by_candidates[pair.first] = {};
  2906. }
  2907. // prepare inflated filter for each candidate on each layer. layers will be put into single thread cluster if they are close to each other (z-axis-wise)
  2908. // and if the inflated AABB polygons overlap somewhere
  2909. Slic3r::parallel_for(size_t(0), layers_with_candidates.size(),
  2910. [&layers_with_candidates, &surfaces_by_layer, &layer_area_covered_by_candidates]
  2911. (const size_t job_idx) {
  2912. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  2913. size_t lidx = layers_with_candidates[job_idx];
  2914. for (const auto &candidate : surfaces_by_layer.at(lidx)) {
  2915. Polygon candiate_inflated_aabb = get_extents(candidate.new_polys).inflated(scale_(7)).polygon();
  2916. layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx),
  2917. Polygons{candiate_inflated_aabb});
  2918. }
  2919. }
  2920. );
  2921. // note: surfaces_by_layer is ordered map
  2922. for (auto pair : surfaces_by_layer) {
  2923. const LayerRegion *first_lregion = this->get_layer(pair.first)->regions()[0];
  2924. if (clustered_layers_for_threads.empty() ||
  2925. this->get_layer(clustered_layers_for_threads.back().back())->print_z <
  2926. this->get_layer(pair.first)->print_z -
  2927. first_lregion->bridging_flow(frSolidInfill, first_lregion->region().config().bridge_type.value).height() * target_flow_height_factor -
  2928. EPSILON ||
  2929. intersection(layer_area_covered_by_candidates[clustered_layers_for_threads.back().back()],
  2930. layer_area_covered_by_candidates[pair.first])
  2931. .empty()) {
  2932. clustered_layers_for_threads.push_back({pair.first});
  2933. } else {
  2934. clustered_layers_for_threads.back().push_back(pair.first);
  2935. }
  2936. }
  2937. #ifdef DEBUG_BRIDGE_OVER_INFILL
  2938. std::cout << "BRIDGE OVER INFILL CLUSTERED LAYERS FOR SINGLE THREAD" << std::endl;
  2939. for (auto cluster : clustered_layers_for_threads) {
  2940. std::cout << "CLUSTER: ";
  2941. for (auto l : cluster) {
  2942. std::cout << l << " ";
  2943. }
  2944. std::cout << std::endl;
  2945. }
  2946. #endif
  2947. }
  2948. // LAMBDA to gather areas with sparse infill deep enough that we can fit thick bridges there.
  2949. auto gather_areas_w_depth = [target_flow_height_factor](const PrintObject *po, int lidx, float target_flow_height) {
  2950. // Gather layers sparse infill areas, to depth defined by used bridge flow
  2951. ExPolygons layers_sparse_infill{};
  2952. ExPolygons not_sparse_infill{};
  2953. double bottom_z = po->get_layer(lidx)->print_z - target_flow_height * target_flow_height_factor - EPSILON;
  2954. for (int i = int(lidx) - 1; i >= 0; --i) {
  2955. // Stop iterating if layer is lower than bottom_z and at least one iteration was made
  2956. const Layer *layer = po->get_layer(i);
  2957. if (layer->print_z < bottom_z && i < int(lidx) - 1)
  2958. break;
  2959. for (const LayerRegion *region : layer->regions()) {
  2960. bool has_low_density = region->region().config().fill_density.value < 100;
  2961. for (const Surface &surface : region->fill_surfaces()) {
  2962. if ((surface.surface_type == (stPosInternal | stDensSparse) && has_low_density) || surface.surface_type == (stPosInternal | stDensVoid) ) {
  2963. layers_sparse_infill.push_back(surface.expolygon);
  2964. } else {
  2965. not_sparse_infill.push_back(surface.expolygon);
  2966. }
  2967. }
  2968. }
  2969. }
  2970. layers_sparse_infill = union_ex(layers_sparse_infill);
  2971. layers_sparse_infill = closing_ex(layers_sparse_infill, float(SCALED_EPSILON));
  2972. not_sparse_infill = union_ex(not_sparse_infill);
  2973. not_sparse_infill = closing_ex(not_sparse_infill, float(SCALED_EPSILON));
  2974. return diff(layers_sparse_infill, not_sparse_infill);
  2975. };
  2976. // LAMBDA do determine optimal bridging angle
  2977. auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern) {
  2978. AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
  2979. std::map<double, int> counted_directions;
  2980. for (const Polygon &p : bridged_area) {
  2981. double acc_distance = 0;
  2982. for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
  2983. Vec2d start = p.points[point_idx].cast<double>();
  2984. Vec2d next = p.points[point_idx + 1].cast<double>();
  2985. Vec2d v = next - start; // vector from next to current
  2986. double dist_to_next = v.norm();
  2987. acc_distance += dist_to_next;
  2988. if (acc_distance > scaled(2.0)) {
  2989. acc_distance = 0.0;
  2990. v.normalize();
  2991. int lines_count = int(std::ceil(dist_to_next / scaled(2.0)));
  2992. float step_size = dist_to_next / lines_count;
  2993. for (int i = 0; i < lines_count; ++i) {
  2994. Point a = (start + v * (i * step_size)).cast<coord_t>();
  2995. auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
  2996. double angle = lines_tree.get_line(index).orientation();
  2997. if (angle > PI) {
  2998. angle -= PI;
  2999. }
  3000. angle += PI * 0.5;
  3001. counted_directions[angle]++;
  3002. }
  3003. }
  3004. }
  3005. }
  3006. std::pair<double, int> best_dir{0, 0};
  3007. // sliding window accumulation
  3008. for (const auto &dir : counted_directions) {
  3009. int score_acc = 0;
  3010. double dir_acc = 0;
  3011. double window_start_angle = dir.first - PI * 0.1;
  3012. double window_end_angle = dir.first + PI * 0.1;
  3013. for (auto dirs_window = counted_directions.lower_bound(window_start_angle);
  3014. dirs_window != counted_directions.upper_bound(window_end_angle); dirs_window++) {
  3015. dir_acc += dirs_window->first * dirs_window->second;
  3016. score_acc += dirs_window->second;
  3017. }
  3018. // current span of directions is 0.5 PI to 1.5 PI (due to the aproach.). Edge values should also account for the
  3019. // opposite direction.
  3020. if (window_start_angle < 0.5 * PI) {
  3021. for (auto dirs_window = counted_directions.lower_bound(1.5 * PI - (0.5 * PI - window_start_angle));
  3022. dirs_window != counted_directions.end(); dirs_window++) {
  3023. dir_acc += dirs_window->first * dirs_window->second;
  3024. score_acc += dirs_window->second;
  3025. }
  3026. }
  3027. if (window_start_angle > 1.5 * PI) {
  3028. for (auto dirs_window = counted_directions.begin();
  3029. dirs_window != counted_directions.upper_bound(window_start_angle - 1.5 * PI); dirs_window++) {
  3030. dir_acc += dirs_window->first * dirs_window->second;
  3031. score_acc += dirs_window->second;
  3032. }
  3033. }
  3034. if (score_acc > best_dir.second) {
  3035. best_dir = {dir_acc / score_acc, score_acc};
  3036. }
  3037. }
  3038. double bridging_angle = best_dir.first;
  3039. if (bridging_angle == 0) {
  3040. bridging_angle = 0.001;
  3041. }
  3042. switch (dominant_pattern) {
  3043. case ipHilbertCurve: bridging_angle += 0.25 * PI; break;
  3044. case ipOctagramSpiral: bridging_angle += (1.0 / 16.0) * PI; break;
  3045. default: break;
  3046. }
  3047. return bridging_angle;
  3048. };
  3049. // LAMBDA that will fill given polygons with lines, exapand the lines to the nearest anchor, and reconstruct polygons from the newly
  3050. // generated lines
  3051. auto construct_anchored_polygon = [](Polygons bridged_area, Lines anchors, const Flow &bridging_flow, double bridging_angle) {
  3052. auto lines_rotate = [](Lines &lines, double cos_angle, double sin_angle) {
  3053. for (Line &l : lines) {
  3054. double ax = double(l.a.x());
  3055. double ay = double(l.a.y());
  3056. l.a.x() = coord_t(round(cos_angle * ax - sin_angle * ay));
  3057. l.a.y() = coord_t(round(cos_angle * ay + sin_angle * ax));
  3058. double bx = double(l.b.x());
  3059. double by = double(l.b.y());
  3060. l.b.x() = coord_t(round(cos_angle * bx - sin_angle * by));
  3061. l.b.y() = coord_t(round(cos_angle * by + sin_angle * bx));
  3062. }
  3063. };
  3064. auto segments_overlap = [](coord_t alow, coord_t ahigh, coord_t blow, coord_t bhigh) {
  3065. return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) ||
  3066. (bhigh >= alow && bhigh <= ahigh);
  3067. };
  3068. Polygons expanded_bridged_area{};
  3069. double aligning_angle = -bridging_angle + PI * 0.5;
  3070. {
  3071. polygons_rotate(bridged_area, aligning_angle);
  3072. lines_rotate(anchors, cos(aligning_angle), sin(aligning_angle));
  3073. BoundingBox bb_x = get_extents(bridged_area);
  3074. BoundingBox bb_y = get_extents(anchors);
  3075. const size_t n_vlines = (bb_x.max.x() - bb_x.min.x() + bridging_flow.scaled_spacing() - 1) / bridging_flow.scaled_spacing();
  3076. std::vector<Line> vertical_lines(n_vlines);
  3077. for (size_t i = 0; i < n_vlines; i++) {
  3078. coord_t x = bb_x.min.x() + i * bridging_flow.scaled_spacing();
  3079. coord_t y_min = bb_y.min.y() - bridging_flow.scaled_spacing();
  3080. coord_t y_max = bb_y.max.y() + bridging_flow.scaled_spacing();
  3081. vertical_lines[i].a = Point{x, y_min};
  3082. vertical_lines[i].b = Point{x, y_max};
  3083. }
  3084. auto anchors_and_walls_tree = AABBTreeLines::LinesDistancer<Line>{std::move(anchors)};
  3085. auto bridged_area_tree = AABBTreeLines::LinesDistancer<Line>{to_lines(bridged_area)};
  3086. std::vector<std::vector<Line>> polygon_sections(n_vlines);
  3087. for (size_t i = 0; i < n_vlines; i++) {
  3088. auto area_intersections = bridged_area_tree.intersections_with_line<true>(vertical_lines[i]);
  3089. for (int intersection_idx = 0; intersection_idx < int(area_intersections.size()) - 1; intersection_idx++) {
  3090. if (bridged_area_tree.outside(
  3091. (area_intersections[intersection_idx].first + area_intersections[intersection_idx + 1].first) / 2) < 0) {
  3092. polygon_sections[i].emplace_back(area_intersections[intersection_idx].first,
  3093. area_intersections[intersection_idx + 1].first);
  3094. }
  3095. }
  3096. auto anchors_intersections = anchors_and_walls_tree.intersections_with_line<true>(vertical_lines[i]);
  3097. for (Line &section : polygon_sections[i]) {
  3098. auto maybe_below_anchor = std::upper_bound(anchors_intersections.rbegin(), anchors_intersections.rend(), section.a,
  3099. [](const Point &a, const std::pair<Point, size_t> &b) {
  3100. return a.y() > b.first.y();
  3101. });
  3102. if (maybe_below_anchor != anchors_intersections.rend()) {
  3103. section.a = maybe_below_anchor->first;
  3104. section.a.y() -= bridging_flow.scaled_width() * (0.5 + 0.5);
  3105. }
  3106. auto maybe_upper_anchor = std::upper_bound(anchors_intersections.begin(), anchors_intersections.end(), section.b,
  3107. [](const Point &a, const std::pair<Point, size_t> &b) {
  3108. return a.y() < b.first.y();
  3109. });
  3110. if (maybe_upper_anchor != anchors_intersections.end()) {
  3111. section.b = maybe_upper_anchor->first;
  3112. section.b.y() += bridging_flow.scaled_width() * (0.5 + 0.5);
  3113. }
  3114. }
  3115. for (int section_idx = 0; section_idx < int(polygon_sections[i].size()) - 1; section_idx++) {
  3116. Line &section_a = polygon_sections[i][section_idx];
  3117. Line &section_b = polygon_sections[i][section_idx + 1];
  3118. if (segments_overlap(section_a.a.y(), section_a.b.y(), section_b.a.y(), section_b.b.y())) {
  3119. section_b.a = section_a.a.y() < section_b.a.y() ? section_a.a : section_b.a;
  3120. section_b.b = section_a.b.y() < section_b.b.y() ? section_b.b : section_a.b;
  3121. section_a.a = section_a.b;
  3122. }
  3123. }
  3124. polygon_sections[i].erase(std::remove_if(polygon_sections[i].begin(), polygon_sections[i].end(),
  3125. [](const Line &s) { return s.a == s.b; }),
  3126. polygon_sections[i].end());
  3127. std::sort(polygon_sections[i].begin(), polygon_sections[i].end(),
  3128. [](const Line &a, const Line &b) { return a.a.y() < b.b.y(); });
  3129. }
  3130. // reconstruct polygon from polygon sections
  3131. struct TracedPoly
  3132. {
  3133. Points lows;
  3134. Points highs;
  3135. };
  3136. std::vector<TracedPoly> current_traced_polys;
  3137. for (const auto &polygon_slice : polygon_sections) {
  3138. std::unordered_set<const Line *> used_segments;
  3139. for (TracedPoly &traced_poly : current_traced_polys) {
  3140. auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
  3141. [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
  3142. auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
  3143. [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
  3144. bool segment_added = false;
  3145. for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
  3146. if (used_segments.find(&(*candidate)) != used_segments.end()) {
  3147. continue;
  3148. }
  3149. if ((traced_poly.lows.back() - candidate->a).cast<double>().squaredNorm() <
  3150. 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
  3151. traced_poly.lows.push_back(candidate->a);
  3152. } else {
  3153. traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
  3154. traced_poly.lows.push_back(candidate->a - Point{bridging_flow.scaled_spacing() / 2, 0});
  3155. traced_poly.lows.push_back(candidate->a);
  3156. }
  3157. if ((traced_poly.highs.back() - candidate->b).cast<double>().squaredNorm() <
  3158. 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
  3159. traced_poly.highs.push_back(candidate->b);
  3160. } else {
  3161. traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
  3162. traced_poly.highs.push_back(candidate->b - Point{bridging_flow.scaled_spacing() / 2, 0});
  3163. traced_poly.highs.push_back(candidate->b);
  3164. }
  3165. segment_added = true;
  3166. used_segments.insert(&(*candidate));
  3167. }
  3168. if (!segment_added) {
  3169. // Zero overlapping segments, we just close this polygon
  3170. traced_poly.lows.push_back(traced_poly.lows.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
  3171. traced_poly.highs.push_back(traced_poly.highs.back() + Point{bridging_flow.scaled_spacing() / 2, 0});
  3172. Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
  3173. new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
  3174. traced_poly.lows.clear();
  3175. traced_poly.highs.clear();
  3176. }
  3177. }
  3178. current_traced_polys.erase(std::remove_if(current_traced_polys.begin(), current_traced_polys.end(),
  3179. [](const TracedPoly &tp) { return tp.lows.empty(); }),
  3180. current_traced_polys.end());
  3181. for (const auto &segment : polygon_slice) {
  3182. if (used_segments.find(&segment) == used_segments.end()) {
  3183. TracedPoly &new_tp = current_traced_polys.emplace_back();
  3184. new_tp.lows.push_back(segment.a - Point{bridging_flow.scaled_spacing() / 2, 0});
  3185. new_tp.lows.push_back(segment.a);
  3186. new_tp.highs.push_back(segment.b - Point{bridging_flow.scaled_spacing() / 2, 0});
  3187. new_tp.highs.push_back(segment.b);
  3188. }
  3189. }
  3190. }
  3191. // add not closed polys
  3192. for (TracedPoly &traced_poly : current_traced_polys) {
  3193. Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
  3194. new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
  3195. }
  3196. expanded_bridged_area = union_safety_offset(expanded_bridged_area);
  3197. }
  3198. polygons_rotate(expanded_bridged_area, -aligning_angle);
  3199. return expanded_bridged_area;
  3200. };
  3201. Slic3r::parallel_for(size_t(0), clustered_layers_for_threads.size(),
  3202. [po = static_cast<const PrintObject *>(this), target_flow_height_factor, &surfaces_by_layer, &clustered_layers_for_threads,
  3203. gather_areas_w_depth, &infill_lines, determine_bridging_angle, construct_anchored_polygon]
  3204. (const size_t cluster_idx) {
  3205. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  3206. for (size_t job_idx = 0; job_idx < clustered_layers_for_threads[cluster_idx].size(); job_idx++) {
  3207. size_t lidx = clustered_layers_for_threads[cluster_idx][job_idx];
  3208. const Layer *layer = po->get_layer(lidx);
  3209. // this thread has exclusive access to all surfaces in layers enumerated in
  3210. // clustered_layers_for_threads[cluster_idx]
  3211. // Presort the candidate polygons. This will help choose the same angle for neighbournig surfaces, that
  3212. // would otherwise compete over anchoring sparse infill lines, leaving one area unachored
  3213. std::sort(surfaces_by_layer[lidx].begin(), surfaces_by_layer[lidx].end(),
  3214. [](const CandidateSurface &left, const CandidateSurface &right) {
  3215. auto a = get_extents(left.new_polys);
  3216. auto b = get_extents(right.new_polys);
  3217. if (a.min.x() == b.min.x()) {
  3218. return a.min.y() < b.min.y();
  3219. };
  3220. return a.min.x() < b.min.x();
  3221. });
  3222. if (surfaces_by_layer[lidx].size() > 2) {
  3223. Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
  3224. std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
  3225. [origin](const CandidateSurface &left, const CandidateSurface &right) {
  3226. auto a = get_extents(left.new_polys);
  3227. auto b = get_extents(right.new_polys);
  3228. return (origin - a.min.cast<double>()).squaredNorm() <
  3229. (origin - b.min.cast<double>()).squaredNorm();
  3230. });
  3231. }
  3232. // Gather deep infill areas, where thick bridges fit
  3233. const LayerRegion *first_lregion = surfaces_by_layer[lidx].front().region;
  3234. Flow bridge_flow = first_lregion->bridging_flow(frSolidInfill, first_lregion->region().config().bridge_type);
  3235. const coord_t spacing = bridge_flow.scaled_spacing();
  3236. const float bridge_height = std::max(float(layer->height), bridge_flow.height());
  3237. //const coord_t bridge_width = bridge_flow.scaled_width();
  3238. const coord_t target_flow_height = bridge_flow.height() * target_flow_height_factor;
  3239. Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
  3240. {
  3241. // Now also remove area that has been already filled on lower layers by bridging expansion - For this
  3242. // reason we did the clustering of layers per thread.
  3243. Polygons filled_polyons_on_lower_layers;
  3244. double bottom_z = layer->print_z - (bridge_height) - EPSILON;
  3245. if (job_idx > 0) {
  3246. for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
  3247. size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
  3248. const Layer *lower_layer = po->get_layer(lower_layer_idx);
  3249. if (lower_layer->print_z >= bottom_z) {
  3250. for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
  3251. filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
  3252. c.new_polys.end());
  3253. }
  3254. } else {
  3255. break;
  3256. }
  3257. }
  3258. }
  3259. deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
  3260. }
  3261. deep_infill_area = expand(deep_infill_area, spacing * 1.5);
  3262. // Now gather expansion polygons - internal infill on current layer, from which we can cut off anchors
  3263. Polygons lightning_area;
  3264. Polygons expansion_area;
  3265. Polygons total_fill_area;
  3266. for (const LayerRegion *region : layer->regions()) {
  3267. Polygons internal_polys = to_polygons(region->fill_surfaces().filter_by_types({(stPosInternal | stDensSparse), (stPosInternal | stDensSolid)}));
  3268. expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
  3269. Polygons fill_polys = to_polygons(region->fill_expolygons());
  3270. total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());
  3271. if (region->region().config().fill_pattern.value == ipLightning) {
  3272. Polygons l = to_polygons(region->fill_surfaces().filter_by_type((stPosInternal | stDensSparse)));
  3273. lightning_area.insert(lightning_area.end(), l.begin(), l.end());
  3274. }
  3275. }
  3276. total_fill_area = closing(total_fill_area, float(SCALED_EPSILON));
  3277. expansion_area = closing(expansion_area, float(SCALED_EPSILON));
  3278. expansion_area = intersection(expansion_area, deep_infill_area);
  3279. Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
  3280. Polygons internal_unsupported_area = shrink(deep_infill_area, spacing * 4.5);
  3281. #ifdef DEBUG_BRIDGE_OVER_INFILL
  3282. debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
  3283. to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
  3284. #endif
  3285. std::vector<CandidateSurface> expanded_surfaces;
  3286. expanded_surfaces.reserve(surfaces_by_layer[lidx].size());
  3287. for (const CandidateSurface &candidate : surfaces_by_layer[lidx]) {
  3288. const Flow &flow = candidate.region->bridging_flow(frSolidInfill, candidate.region->region().config().bridge_type);
  3289. Polygons area_to_be_bridge = expand(candidate.new_polys, flow.scaled_spacing());
  3290. area_to_be_bridge = intersection(area_to_be_bridge, deep_infill_area);
  3291. area_to_be_bridge.erase(std::remove_if(area_to_be_bridge.begin(), area_to_be_bridge.end(),
  3292. [internal_unsupported_area](const Polygon &p) {
  3293. return intersection({p}, internal_unsupported_area).empty();
  3294. }),
  3295. area_to_be_bridge.end());
  3296. Polygons limiting_area = union_(area_to_be_bridge, expansion_area);
  3297. if (area_to_be_bridge.empty())
  3298. continue;
  3299. Polylines boundary_plines = to_polylines(expand(total_fill_area, 1.3 * flow.scaled_spacing()));
  3300. {
  3301. Polylines limiting_plines = to_polylines(expand(limiting_area, 0.3*flow.spacing()));
  3302. boundary_plines.insert(boundary_plines.end(), limiting_plines.begin(), limiting_plines.end());
  3303. }
  3304. #ifdef DEBUG_BRIDGE_OVER_INFILL
  3305. int r = rand();
  3306. debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
  3307. "_anchors_" + std::to_string(r),
  3308. to_lines(area_to_be_bridge), to_lines(boundary_plines), to_lines(anchors), to_lines(expansion_area));
  3309. #endif
  3310. double bridging_angle = 0;
  3311. if (!anchors.empty()) {
  3312. bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors),
  3313. candidate.region->region().config().fill_pattern.value);
  3314. } else {
  3315. // use expansion boundaries as anchors.
  3316. // Also, use Infill pattern that is neutral for angle determination, since there are no infill lines.
  3317. bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine);
  3318. }
  3319. boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
  3320. if (!lightning_area.empty() && !intersection(area_to_be_bridge, lightning_area).empty()) {
  3321. boundary_plines = intersection_pl(boundary_plines, expand(area_to_be_bridge, scale_(10)));
  3322. }
  3323. Polygons bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle);
  3324. // Check collision with other expanded surfaces
  3325. {
  3326. bool reconstruct = false;
  3327. Polygons tmp_expanded_area = expand(bridging_area, 3.0 * flow.scaled_spacing());
  3328. for (const CandidateSurface &s : expanded_surfaces) {
  3329. if (!intersection(s.new_polys, tmp_expanded_area).empty()) {
  3330. bridging_angle = s.bridge_angle;
  3331. reconstruct = true;
  3332. break;
  3333. }
  3334. }
  3335. if (reconstruct) {
  3336. bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle);
  3337. }
  3338. }
  3339. bridging_area = opening(bridging_area, flow.scaled_spacing());
  3340. bridging_area = closing(bridging_area, flow.scaled_spacing());
  3341. bridging_area = intersection(bridging_area, limiting_area);
  3342. bridging_area = intersection(bridging_area, total_fill_area);
  3343. expansion_area = diff(expansion_area, bridging_area);
  3344. #ifdef DEBUG_BRIDGE_OVER_INFILL
  3345. debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_expanded_bridging" + std::to_string(r),
  3346. to_lines(layer->lslices()), to_lines(boundary_plines), to_lines(candidate.new_polys), to_lines(bridging_area));
  3347. #endif
  3348. expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area,
  3349. candidate.region, bridging_angle));
  3350. }
  3351. surfaces_by_layer[lidx].swap(expanded_surfaces);
  3352. expanded_surfaces.clear();
  3353. }
  3354. }
  3355. );
  3356. BOOST_LOG_TRIVIAL(info) << "Bridge over infill - Directions and expanded surfaces computed" << log_memory_info();
  3357. Slic3r::parallel_for(size_t(0), this->layers().size(),
  3358. [po = this, &surfaces_by_layer]
  3359. (const size_t lidx) {
  3360. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(po->print()->config().resolution.value));
  3361. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  3362. if (!(surfaces_by_layer.find(lidx) == surfaces_by_layer.end() && surfaces_by_layer.find(lidx + 1) == surfaces_by_layer.end())) {
  3363. Layer *layer = po->get_layer(lidx);
  3364. Polygons cut_from_infill{};
  3365. if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
  3366. for (const auto &surface : surfaces_by_layer.at(lidx)) {
  3367. cut_from_infill.insert(cut_from_infill.end(), surface.new_polys.begin(), surface.new_polys.end());
  3368. }
  3369. }
  3370. Polygons additional_ensuring_areas{};
  3371. if (surfaces_by_layer.find(lidx + 1) != surfaces_by_layer.end()) {
  3372. for (const auto &surface : surfaces_by_layer.at(lidx + 1)) {
  3373. auto additional_area = diff(surface.new_polys,
  3374. shrink(surface.new_polys, surface.region->flow(frSolidInfill).scaled_spacing()));
  3375. additional_ensuring_areas.insert(additional_ensuring_areas.end(), additional_area.begin(), additional_area.end());
  3376. }
  3377. }
  3378. for (LayerRegion *region : layer->regions()) {
  3379. Surfaces new_surfaces;
  3380. Polygons near_perimeters = to_polygons(union_safety_offset_ex(to_polygons(region->fill_surfaces().surfaces)));
  3381. near_perimeters = diff(near_perimeters, shrink(near_perimeters, region->flow(frSolidInfill).scaled_spacing()));
  3382. ExPolygons additional_ensuring = intersection_ex(additional_ensuring_areas, near_perimeters);
  3383. SurfacesPtr internal_infills = region->m_fill_surfaces.filter_by_type((stPosInternal | stDensSparse));
  3384. ExPolygons new_internal_infills = diff_ex(internal_infills, cut_from_infill);
  3385. new_internal_infills = diff_ex(new_internal_infills, additional_ensuring);
  3386. ensure_valid(new_internal_infills, scaled_resolution);
  3387. assert_valid(new_internal_infills);
  3388. for (const ExPolygon &ep : new_internal_infills) {
  3389. ep.assert_valid();
  3390. new_surfaces.emplace_back((stPosInternal | stDensSparse), ep);
  3391. }
  3392. SurfacesPtr internal_solids = region->m_fill_surfaces.filter_by_type((stPosInternal | stDensSolid));
  3393. if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
  3394. for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
  3395. for (const Surface *surface : internal_solids) {
  3396. if (cs.original_surface == surface) {
  3397. Surface tmp{*surface, {}};
  3398. tmp.surface_type = (stPosInternal | stDensSolid | stModBridge);
  3399. tmp.bridge_angle = cs.bridge_angle;
  3400. for (const ExPolygon &ep : ensure_valid(union_ex(cs.new_polys), scaled_resolution)) {
  3401. ep.assert_valid();
  3402. new_surfaces.emplace_back(tmp, ep);
  3403. }
  3404. break;
  3405. }
  3406. }
  3407. }
  3408. }
  3409. ExPolygons new_internal_solids = to_expolygons(internal_solids);
  3410. new_internal_solids.insert(new_internal_solids.end(), additional_ensuring.begin(), additional_ensuring.end());
  3411. new_internal_solids = diff_ex(new_internal_solids, cut_from_infill);
  3412. new_internal_solids = union_safety_offset_ex(new_internal_solids);
  3413. ensure_valid(new_internal_solids, scaled_resolution);
  3414. for (const ExPolygon &ep : new_internal_solids) {
  3415. ep.assert_valid();
  3416. new_surfaces.emplace_back((stPosInternal | stDensSolid), ep);
  3417. }
  3418. #ifdef DEBUG_BRIDGE_OVER_INFILL
  3419. debug_draw("Aensuring_" + std::to_string(reinterpret_cast<uint64_t>(&region)), to_polylines(additional_ensuring),
  3420. to_polylines(near_perimeters), to_polylines(to_polygons(internal_infills)),
  3421. to_polylines(to_polygons(internal_solids)));
  3422. debug_draw("Aensuring_" + std::to_string(reinterpret_cast<uint64_t>(&region)) + "_new", to_polylines(additional_ensuring),
  3423. to_polylines(near_perimeters), to_polylines(to_polygons(new_internal_infills)),
  3424. to_polylines(to_polygons(new_internal_solids)));
  3425. #endif
  3426. region->m_fill_surfaces.remove_types({(stPosInternal | stDensSolid), (stPosInternal | stDensSparse)});
  3427. for(auto &srf : new_surfaces)
  3428. srf.expolygon.assert_valid();
  3429. region->m_fill_surfaces.append(new_surfaces);
  3430. }
  3431. }
  3432. });
  3433. BOOST_LOG_TRIVIAL(info) << "Bridge over infill - End" << log_memory_info();
  3434. } // void PrintObject::bridge_over_infill()
  3435. static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
  3436. {
  3437. if (opt.value > (int)num_extruders)
  3438. // assign the default extruder
  3439. opt.value = 1;
  3440. }
  3441. PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
  3442. {
  3443. PrintObjectConfig config = default_object_config;
  3444. {
  3445. DynamicPrintConfig src_normalized(object.config.get());
  3446. src_normalized.normalize_fdm();
  3447. config.apply(src_normalized, true);
  3448. }
  3449. // Clamp invalid extruders to the default extruder (with index 1).
  3450. clamp_exturder_to_default(config.support_material_extruder, num_extruders);
  3451. clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
  3452. return config;
  3453. }
  3454. const std::string key_extruder { "extruder" };
  3455. static constexpr const std::initializer_list<const std::string_view> keys_extruders { "infill_extruder"sv, "solid_infill_extruder"sv, "perimeter_extruder"sv };
  3456. static void apply_to_print_region_config(PrintRegionConfig &out, const DynamicPrintConfig &in)
  3457. {
  3458. // 1) Copy the "extruder key to infill_extruder and perimeter_extruder.
  3459. auto *opt_extruder = in.opt<ConfigOptionInt>(key_extruder);
  3460. if (opt_extruder)
  3461. if (int extruder = opt_extruder->value; extruder != 0) {
  3462. // Not a default extruder.
  3463. out.infill_extruder .value = extruder;
  3464. out.solid_infill_extruder.value = extruder;
  3465. out.perimeter_extruder .value = extruder;
  3466. }
  3467. // 2) Copy the rest of the values.
  3468. for (auto it = in.cbegin(); it != in.cend(); ++ it)
  3469. if (it->first != key_extruder)
  3470. if (ConfigOption* my_opt = out.option(it->first, false); my_opt != nullptr) {
  3471. if (one_of(it->first, keys_extruders)) {
  3472. assert(dynamic_cast<ConfigOptionInt*>(my_opt));
  3473. // Ignore "default" extruders.
  3474. int extruder = static_cast<const ConfigOptionInt*>(it->second.get())->value;
  3475. if (extruder > 0)
  3476. static_cast<ConfigOptionInt *>(my_opt)->value = (extruder);
  3477. } else
  3478. my_opt->set(it->second.get());
  3479. }
  3480. }
  3481. PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_or_parent_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders)
  3482. {
  3483. PrintRegionConfig config = default_or_parent_region_config;
  3484. if (volume.is_model_part()) {
  3485. // default_or_parent_region_config contains the Print's PrintRegionConfig.
  3486. // Override with ModelObject's PrintRegionConfig values.
  3487. apply_to_print_region_config(config, volume.get_object()->config.get());
  3488. } else {
  3489. // default_or_parent_region_config contains parent PrintRegion config, which already contains ModelVolume's config.
  3490. }
  3491. if (layer_range_config != nullptr) {
  3492. // Not applicable to modifiers.
  3493. assert(volume.is_model_part());
  3494. apply_to_print_region_config(config, *layer_range_config);
  3495. }
  3496. apply_to_print_region_config(config, volume.config.get());
  3497. if (! volume.material_id().empty())
  3498. apply_to_print_region_config(config, volume.material()->config.get());
  3499. // Clamp invalid extruders to the default extruder (with index 1).
  3500. clamp_exturder_to_default(config.infill_extruder, num_extruders);
  3501. clamp_exturder_to_default(config.perimeter_extruder, num_extruders);
  3502. clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
  3503. if (config.fill_density.value < 0.00011f)
  3504. // Switch of infill for very low infill rates, also avoid division by zero in infill generator for these very low rates.
  3505. // See GH issue #5910.
  3506. config.fill_density.value = 0;
  3507. else
  3508. config.fill_density.value = std::min(config.fill_density.value, 100.);
  3509. if (config.fuzzy_skin.value != FuzzySkinType::None && (config.fuzzy_skin_point_dist.value < 0.01 || config.fuzzy_skin_thickness.value < 0.001))
  3510. config.fuzzy_skin.value = FuzzySkinType::None;
  3511. return config;
  3512. }
  3513. void PrintObject::update_slicing_parameters()
  3514. {
  3515. if (!m_slicing_params || !m_slicing_params->valid)
  3516. m_slicing_params = SlicingParameters::create_from_config(
  3517. this->print()->config(), m_config, this->print()->default_region_config(), this->model_object()->max_z()/*bounding_box().max.z()*/, this->object_extruders());
  3518. }
  3519. std::shared_ptr<SlicingParameters> PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
  3520. {
  3521. PrintConfig print_config;
  3522. PrintObjectConfig object_config;
  3523. PrintRegionConfig default_region_config;
  3524. print_config.apply(full_config, true);
  3525. object_config.apply(full_config, true);
  3526. default_region_config.apply(full_config, true);
  3527. size_t num_extruders = print_config.nozzle_diameter.size();
  3528. object_config = object_config_from_model_object(object_config, model_object, num_extruders);
  3529. std::set<uint16_t> object_extruders;
  3530. for (const ModelVolume* model_volume : model_object.volumes)
  3531. if (model_volume->is_model_part()) {
  3532. PrintRegion::collect_object_printing_extruders(
  3533. print_config,
  3534. object_config,
  3535. region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
  3536. object_extruders);
  3537. for (const std::pair<const t_layer_height_range, ModelConfig>& range_and_config : model_object.layer_config_ranges)
  3538. if (range_and_config.second.has("perimeter_extruder") ||
  3539. range_and_config.second.has("infill_extruder") ||
  3540. range_and_config.second.has("solid_infill_extruder"))
  3541. PrintRegion::collect_object_printing_extruders(
  3542. print_config,
  3543. object_config,
  3544. region_config_from_model_volume(default_region_config, &range_and_config.second.get(), *model_volume, num_extruders),
  3545. object_extruders);
  3546. }
  3547. //FIXME add painting extruders
  3548. if (object_max_z <= 0.f)
  3549. object_max_z = (float)model_object.raw_bounding_box().size().z();
  3550. return SlicingParameters::create_from_config(print_config, object_config, default_region_config, object_max_z, object_extruders);
  3551. }
  3552. // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
  3553. std::set<uint16_t> PrintObject::object_extruders() const
  3554. {
  3555. std::set<uint16_t> extruders;
  3556. for (const PrintRegion &region : this->all_regions())
  3557. region.collect_object_printing_extruders(*this->print(), extruders);
  3558. return extruders;
  3559. }
  3560. double PrintObject::get_first_layer_height() const
  3561. {
  3562. //get object first layer height
  3563. double object_first_layer_height = config().first_layer_height.value;
  3564. if (config().first_layer_height.percent) {
  3565. object_first_layer_height = 1000000000;
  3566. for (uint16_t extruder_id : object_extruders()) {
  3567. double nozzle_diameter = print()->config().nozzle_diameter.get_at(extruder_id);
  3568. object_first_layer_height = std::fmin(object_first_layer_height, config().first_layer_height.get_abs_value(nozzle_diameter));
  3569. }
  3570. }
  3571. assert(object_first_layer_height < 1000000000);
  3572. return object_first_layer_height;
  3573. }
  3574. bool PrintObject::update_layer_height_profile(const ModelObject& model_object, const SlicingParameters& slicing_parameters, std::vector<coordf_t>& layer_height_profile)
  3575. {
  3576. bool updated = false;
  3577. if (layer_height_profile.empty()) {
  3578. // use the constructor because the assignement is crashing on ASAN OsX
  3579. layer_height_profile = model_object.layer_height_profile.get();
  3580. // layer_height_profile = model_object.layer_height_profile;
  3581. // The layer height returned is sampled with high density for the UI layer height painting
  3582. // and smoothing tool to work.
  3583. updated = true;
  3584. }
  3585. // Verify the layer_height_profile.
  3586. if (!layer_height_profile.empty() &&
  3587. // Must not be of even length.
  3588. ((layer_height_profile.size() & 1) != 0 ||
  3589. // Last entry must be at the top of the object.
  3590. std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max + slicing_parameters.object_print_z_min) > 10 * EPSILON)) {
  3591. if ((layer_height_profile.size() & 1) != 0) {
  3592. BOOST_LOG_TRIVIAL(error) << "Error: can't apply the layer hight profile: layer_height_profile array is odd, not even.";
  3593. } else {
  3594. BOOST_LOG_TRIVIAL(error) << "Error: can't apply the layer hight profile: layer_height_profile last layer is at "
  3595. << layer_height_profile[layer_height_profile.size() - 2]
  3596. <<", and it's too far away from object_print_z_max = "<<(slicing_parameters.object_print_z_max + slicing_parameters.object_print_z_min);
  3597. }
  3598. layer_height_profile.clear();
  3599. }
  3600. if (layer_height_profile.empty()) {
  3601. //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
  3602. layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
  3603. // The layer height profile is already compressed.
  3604. updated = true;
  3605. }
  3606. return updated;
  3607. }
  3608. // Only active if config->infill_only_where_needed. This step trims the sparse infill,
  3609. // so it acts as an internal support. It maintains all other infill types intact.
  3610. // Here the internal surfaces and perimeters have to be supported by the sparse infill.
  3611. //FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
  3612. // Likely the sparse infill will not be anchored correctly, so it will not work as intended.
  3613. // Also one wishes the perimeters to be supported by a full infill.
  3614. // Idempotence of this method is guaranteed by the fact that we don't remove things from
  3615. // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
  3616. // void PrintObject::clip_fill_surfaces()
  3617. // {
  3618. // bool has_lightning_infill = false;
  3619. // for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
  3620. // if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern.value == ipLightning)
  3621. // has_lightning_infill = true;
  3622. // // For Lightning infill, infill_only_where_needed is ignored because both
  3623. // // do a similar thing, and their combination doesn't make much sense.
  3624. // if (! m_config.infill_only_where_needed.value || has_lightning_infill)
  3625. // return;
  3626. // bool has_infill = false;
  3627. // for (size_t i = 0; i < this->num_printing_regions(); ++ i)
  3628. // if (this->printing_region(i).config().fill_density > 0) {
  3629. // has_infill = true;
  3630. // break;
  3631. // }
  3632. // if (! has_infill)
  3633. // return;
  3634. // // We only want infill under ceilings; this is almost like an
  3635. // // internal support material.
  3636. // // Proceed top-down, skipping the bottom layer.
  3637. // Polygons upper_internal;
  3638. // for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) {
  3639. // Layer *layer = m_layers[layer_id];
  3640. // Layer *lower_layer = m_layers[layer_id - 1];
  3641. // // Detect things that we need to support.
  3642. // // Cummulative fill surfaces.
  3643. // Polygons fill_surfaces;
  3644. // // Solid surfaces to be supported.
  3645. // Polygons overhangs;
  3646. // for (const LayerRegion *layerm : layer->m_regions)
  3647. // for (const Surface &surface : layerm->fill_surfaces()) {
  3648. // Polygons polygons = to_polygons(surface.expolygon);
  3649. // if (surface.has_fill_solid())
  3650. // polygons_append(overhangs, polygons);
  3651. // polygons_append(fill_surfaces, std::move(polygons));
  3652. // }
  3653. // Polygons lower_layer_fill_surfaces;
  3654. // Polygons lower_layer_internal_surfaces;
  3655. // for (const LayerRegion *layerm : lower_layer->m_regions)
  3656. // for (const Surface &surface : layerm->fill_surfaces()) {
  3657. // Polygons polygons = to_polygons(surface.expolygon);
  3658. // if (surface.has_pos_internal() && (surface.has_fill_sparse() || surface.has_fill_void()))
  3659. // polygons_append(lower_layer_internal_surfaces, polygons);
  3660. // polygons_append(lower_layer_fill_surfaces, std::move(polygons));
  3661. // }
  3662. // // We also need to support perimeters when there's at least one full unsupported loop
  3663. // {
  3664. // // Get perimeters area as the difference between slices and fill_surfaces
  3665. // // Only consider the area that is not supported by lower perimeters
  3666. // Polygons perimeters = intersection(diff(layer->lslices(), fill_surfaces), lower_layer_fill_surfaces);
  3667. // // Only consider perimeter areas that are at least one extrusion width thick.
  3668. // //FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
  3669. // //Should the pw not be half of the current value?
  3670. // float pw = FLT_MAX;
  3671. // for (const LayerRegion *layerm : layer->m_regions)
  3672. // pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
  3673. // // Append such thick perimeters to the areas that need support
  3674. // polygons_append(overhangs, opening(perimeters, pw));
  3675. // }
  3676. // // Merge the new overhangs, find new internal infill.
  3677. // polygons_append(upper_internal, std::move(overhangs));
  3678. // static constexpr const auto closing_radius = scaled<float>(2.f);
  3679. // upper_internal = intersection(
  3680. // // Regularize the overhang regions, so that the infill areas will not become excessively jagged.
  3681. // smooth_outward(
  3682. // closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.),
  3683. // scaled<coord_t>(0.1)),
  3684. // lower_layer_internal_surfaces);
  3685. // // Apply new internal infill to regions.
  3686. // for (LayerRegion *layerm : lower_layer->m_regions) {
  3687. // if (layerm->region().config().fill_density.value == 0 || layerm->region().config().infill_dense.value)
  3688. // continue;
  3689. // Polygons internal;
  3690. // for (Surface &surface : layerm->m_fill_surfaces.surfaces)
  3691. // if (surface.surface_type == (stPosInternal | stDensSparse) || surface.surface_type == stInternalVoid)
  3692. // polygons_append(internal, std::move(surface.expolygon));
  3693. // layerm->m_fill_surfaces.remove_types({ stPosInternal | stDensSparse, stPosInternal | stDensVoid });
  3694. // layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stPosInternal | stDensSparse);
  3695. // layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stPosInternal | stDensVoid);
  3696. // // If there are voids it means that our internal infill is not adjacent to
  3697. // // perimeters. In this case it would be nice to add a loop around infill to
  3698. // // make it more robust and nicer. TODO.
  3699. // #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  3700. // layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
  3701. // #endif
  3702. // }
  3703. // m_print->throw_if_canceled();
  3704. // }
  3705. // } // void PrintObject::clip_fill_surfaces()
  3706. void PrintObject::discover_horizontal_shells()
  3707. {
  3708. BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()";
  3709. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
  3710. for (size_t i = 0; i < m_layers.size(); ++i) {
  3711. m_print->throw_if_canceled();
  3712. Layer *layer = m_layers[i];
  3713. LayerRegion *layerm = layer->get_region(region_id);
  3714. const PrintRegionConfig &region_config = layerm->region().config();
  3715. if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
  3716. (i % region_config.solid_infill_every_layers) == 0) {
  3717. // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
  3718. SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ?
  3719. (stPosInternal | stDensSolid) :
  3720. (stPosInternal | stDensSolid | stModBridge);
  3721. for (Surface& surface : layerm->m_fill_surfaces.surfaces)
  3722. if (surface.surface_type == (stPosInternal | stDensSparse))
  3723. surface.surface_type = type;
  3724. }
  3725. // The rest has already been performed by discover_vertical_shells().
  3726. } // for each layer
  3727. } // for each region
  3728. #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
  3729. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) {
  3730. for (const Layer *layer : m_layers) {
  3731. const LayerRegion *layerm = layer->m_regions[region_id];
  3732. layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells");
  3733. layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells");
  3734. } // for each layer
  3735. } // for each region
  3736. #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
  3737. } // void PrintObject::discover_horizontal_shells()
  3738. void merge_surfaces(LayerRegion* lregion) {
  3739. coord_t scaled_resolution = std::max(SCALED_EPSILON, scale_t(lregion->layer()->object()->print()->config().resolution.value));
  3740. //merge regions with same type (other things are all the same anyway)
  3741. std::map< SurfaceType, std::vector<const Surface*>> type2srfs;
  3742. for (const Surface& surface : lregion->fill_surfaces().surfaces) {
  3743. type2srfs[surface.surface_type].push_back(&surface);
  3744. }
  3745. bool changed = false;
  3746. std::map< SurfaceType, ExPolygons> type2newpolys;
  3747. for (auto& entry : type2srfs) {
  3748. if (entry.second.size() > 2) {
  3749. ExPolygons merged = ensure_valid(union_safety_offset_ex(to_expolygons(entry.second)), scaled_resolution);
  3750. if (merged.size() < entry.second.size()) {
  3751. changed = true;
  3752. type2newpolys[entry.first] = std::move(merged);
  3753. }
  3754. }
  3755. }
  3756. if (changed) {
  3757. Surfaces newSrfs;
  3758. for (auto& entry : type2srfs) {
  3759. if (type2newpolys.find(entry.first) == type2newpolys.end()) {
  3760. for (const Surface* srfPtr : entry.second) {
  3761. srfPtr->expolygon.assert_valid();
  3762. newSrfs.emplace_back(*srfPtr);
  3763. }
  3764. } else {
  3765. for (ExPolygon& expoly : type2newpolys[entry.first]) {
  3766. expoly.assert_valid();
  3767. newSrfs.emplace_back(*entry.second.front(), expoly);
  3768. }
  3769. }
  3770. }
  3771. lregion->set_fill_surfaces().surfaces = std::move(newSrfs);
  3772. }
  3773. }
  3774. void PrintObject::clean_surfaces() {
  3775. Slic3r::parallel_for(size_t(0), this->layers().size() - 1,
  3776. [this](const size_t idx_layer) {
  3777. for (LayerRegion* lregion : this->layers()[idx_layer]->regions()) {
  3778. coord_t extrusion_width = lregion->flow(frInfill).scaled_width();
  3779. merge_surfaces(lregion);
  3780. // collapse too thin solid surfaces.
  3781. bool changed_type = false;
  3782. for (Surface& surface : lregion->set_fill_surfaces().surfaces) {
  3783. if (surface.has_fill_solid() && surface.has_pos_internal()) {
  3784. if (offset2_ex(ExPolygons{ surface.expolygon }, -extrusion_width / 2, extrusion_width / 2).empty()) {
  3785. //convert to sparse
  3786. surface.surface_type = (surface.surface_type ^ SurfaceType::stDensSolid) | SurfaceType::stDensSparse;
  3787. changed_type = true;
  3788. }
  3789. }
  3790. }
  3791. merge_surfaces(lregion);
  3792. }
  3793. }
  3794. );
  3795. }
  3796. // combine fill surfaces across layers to honor the "infill every N layers" option
  3797. // Idempotence of this method is guaranteed by the fact that we don't remove things from
  3798. // fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
  3799. void PrintObject::combine_infill()
  3800. {
  3801. // Work on each region separately.
  3802. for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
  3803. const PrintRegion &region = this->printing_region(region_id);
  3804. // can't have void if using infill_dense
  3805. const size_t every = region.config().infill_dense.value ? 1 : region.config().infill_every_layers.value;
  3806. if (every < 2 || region.config().fill_density == 0.)
  3807. continue;
  3808. // Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
  3809. //FIXME limit the layer height to max_layer_height
  3810. double nozzle_diameter = std::min(
  3811. this->print()->config().nozzle_diameter.get_at(region.config().infill_extruder.value - 1),
  3812. this->print()->config().nozzle_diameter.get_at(region.config().solid_infill_extruder.value - 1));
  3813. // define the combinations
  3814. std::vector<size_t> combine(m_layers.size(), 0);
  3815. {
  3816. double current_height = 0.;
  3817. size_t num_layers = 0;
  3818. for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
  3819. m_print->throw_if_canceled();
  3820. const Layer *layer = m_layers[layer_idx];
  3821. if (layer->id() == 0)
  3822. // Skip first print layer (which may not be first layer in array because of raft).
  3823. continue;
  3824. // Check whether the combination of this layer with the lower layers' buffer
  3825. // would exceed max layer height or max combined layer count.
  3826. if (current_height + layer->height >= nozzle_diameter + EPSILON || num_layers >= every) {
  3827. // Append combination to lower layer.
  3828. combine[layer_idx - 1] = num_layers;
  3829. current_height = 0.;
  3830. num_layers = 0;
  3831. }
  3832. current_height += layer->height;
  3833. ++ num_layers;
  3834. }
  3835. // Append lower layers (if any) to uppermost layer.
  3836. combine[m_layers.size() - 1] = num_layers;
  3837. }
  3838. // loop through layers to which we have assigned layers to combine
  3839. for (size_t layer_idx = 0; layer_idx < m_layers.size(); ++ layer_idx) {
  3840. m_print->throw_if_canceled();
  3841. size_t num_layers = combine[layer_idx];
  3842. if (num_layers <= 1)
  3843. continue;
  3844. // Get all the LayerRegion objects to be combined.
  3845. std::vector<LayerRegion*> layerms;
  3846. layerms.reserve(num_layers);
  3847. for (size_t i = layer_idx + 1 - num_layers; i <= layer_idx; ++ i)
  3848. layerms.emplace_back(m_layers[i]->regions()[region_id]);
  3849. // We need to perform a multi-layer intersection, so let's split it in pairs.
  3850. // Initialize the intersection with the candidates of the lowest layer.
  3851. ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces().filter_by_type(stPosInternal | stDensSparse));
  3852. // Start looping from the second layer and intersect the current intersection with it.
  3853. for (size_t i = 1; i < layerms.size(); ++i)
  3854. intersection = intersection_ex(to_expolygons(layerms[i]->fill_surfaces().filter_by_type(stPosInternal | stDensSparse)), intersection);
  3855. double area_threshold = layerms.front()->infill_area_threshold();
  3856. if (! intersection.empty() && area_threshold > 0.)
  3857. intersection.erase(std::remove_if(intersection.begin(), intersection.end(),
  3858. [area_threshold](const ExPolygon &expoly) { return expoly.area() <= area_threshold; }),
  3859. intersection.end());
  3860. if (intersection.empty())
  3861. continue;
  3862. // Slic3r::debugf " combining %d %s regions from layers %d-%d\n",
  3863. // scalar(@$intersection),
  3864. // ($type == stInternal ? 'internal' : 'internal-solid'),
  3865. // $layer_idx-($every-1), $layer_idx;
  3866. // intersection now contains the regions that can be combined across the full amount of layers,
  3867. // so let's remove those areas from all layers.
  3868. Polygons intersection_with_clearance;
  3869. intersection_with_clearance.reserve(intersection.size());
  3870. //TODO: check if that 'hack' isn't counter-productive : the overlap is done at perimetergenerator (so before this)
  3871. // and the not-overlap area is stored in the LayerRegion object
  3872. float clearance_offset =
  3873. 0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
  3874. // Because fill areas for rectilinear and honeycomb are grown
  3875. // later to overlap perimeters, we need to counteract that too.
  3876. ((region.config().fill_pattern.value == ipRectilinear ||
  3877. region.config().fill_pattern.value == ipMonotonic ||
  3878. region.config().fill_pattern.value == ipGrid ||
  3879. region.config().fill_pattern.value == ipLine ||
  3880. region.config().fill_pattern.value == ipHoneycomb) ? 1.5f : 0.5f) *
  3881. layerms.back()->flow(frSolidInfill).scaled_width();
  3882. for (ExPolygon& expoly : intersection) {
  3883. expoly.assert_valid();
  3884. polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));
  3885. }
  3886. for (LayerRegion *layerm : layerms) {
  3887. Polygons internal = to_polygons(layerm->fill_surfaces().filter_by_type(stPosInternal | stDensSparse));
  3888. layerm->m_fill_surfaces.remove_type(stPosInternal | stDensSparse);
  3889. ExPolygons only_internal = diff_ex(internal, intersection_with_clearance);
  3890. assert_valid(only_internal);
  3891. layerm->m_fill_surfaces.append(std::move(only_internal), stPosInternal | stDensSparse);
  3892. if (layerm == layerms.back()) {
  3893. // Apply surfaces back with adjusted depth to the uppermost layer.
  3894. Surface templ(stPosInternal | stDensSparse, ExPolygon());
  3895. templ.thickness = 0.;
  3896. for (LayerRegion* layerm2 : layerms) {
  3897. templ.thickness += layerm2->layer()->height;
  3898. }
  3899. templ.thickness_layers = (unsigned short)layerms.size();
  3900. layerm->m_fill_surfaces.append(intersection, templ);
  3901. } else {
  3902. // Save void surfaces.
  3903. ExPolygons only_void = intersection_ex(internal, intersection_with_clearance);
  3904. assert_valid(only_void);
  3905. layerm->m_fill_surfaces.append(std::move(only_void), stPosInternal | stDensVoid);
  3906. }
  3907. }
  3908. }
  3909. }
  3910. } // void PrintObject::combine_infill()
  3911. void PrintObject::_generate_support_material()
  3912. {
  3913. if (this->has_support() && (m_config.support_material_style.value == smsTree || m_config.support_material_style.value == smsOrganic)) {
  3914. fff_tree_support_generate(*this, std::function<void()>([this](){ this->throw_if_canceled(); }));
  3915. } else {
  3916. // If support style is set to Organic however only raft will be built but no support,
  3917. // build snug raft instead.
  3918. PrintObjectSupportMaterial support_material(this, m_slicing_params);
  3919. support_material.generate(*this);
  3920. }
  3921. }
  3922. static void project_triangles_to_slabs(SpanOfConstPtrs<Layer> layers, const indexed_triangle_set &custom_facets, const Transform3f &tr, bool seam, std::vector<Polygons> &out)
  3923. {
  3924. if (custom_facets.indices.empty())
  3925. return;
  3926. const float tr_det_sign = (tr.matrix().determinant() > 0. ? 1.f : -1.f);
  3927. // The projection will be at most a pentagon. Let's minimize heap
  3928. // reallocations by saving in in the following struct.
  3929. // Points are used so that scaling can be done in parallel
  3930. // and they can be moved from to create an ExPolygon later.
  3931. struct LightPolygon {
  3932. LightPolygon() { pts.reserve(5); }
  3933. LightPolygon(const std::array<Vec2f, 3>& tri) {
  3934. pts.reserve(3);
  3935. pts.emplace_back(scaled<coord_t>(tri.front()));
  3936. pts.emplace_back(scaled<coord_t>(tri[1]));
  3937. pts.emplace_back(scaled<coord_t>(tri.back()));
  3938. }
  3939. Points pts;
  3940. void add(const Vec2f& pt) {
  3941. pts.emplace_back(scaled<coord_t>(pt));
  3942. assert(pts.size() <= 5);
  3943. }
  3944. };
  3945. // Structure to collect projected polygons. One element for each triangle.
  3946. // Saves vector of polygons and layer_id of the first one.
  3947. struct TriangleProjections {
  3948. size_t first_layer_id;
  3949. std::vector<LightPolygon> polygons;
  3950. };
  3951. // Vector to collect resulting projections from each triangle.
  3952. std::vector<TriangleProjections> projections_of_triangles(custom_facets.indices.size());
  3953. // Iterate over all triangles.
  3954. Slic3r::parallel_for(size_t(0), custom_facets.indices.size(),
  3955. [&custom_facets, &tr, tr_det_sign, seam, layers, &projections_of_triangles]
  3956. (const size_t idx) {
  3957. PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
  3958. std::array<Vec3f, 3> facet;
  3959. // Transform the triangle into worlds coords.
  3960. for (int i=0; i<3; ++i)
  3961. facet[i] = tr * custom_facets.vertices[custom_facets.indices[idx](i)];
  3962. // Ignore triangles with upward-pointing normal. Don't forget about mirroring.
  3963. float z_comp = (facet[1]-facet[0]).cross(facet[2]-facet[0]).z();
  3964. if (! seam && tr_det_sign * z_comp > 0.)
  3965. return; //continue (next facet idx)
  3966. // The algorithm does not process vertical triangles, but it should for seam.
  3967. // In that case, tilt the triangle a bit so the projection does not degenerate.
  3968. if (seam && z_comp == 0.f)
  3969. facet[0].x() += float(EPSILON);
  3970. // Sort the three vertices according to z-coordinate.
  3971. std::sort(facet.begin(), facet.end(),
  3972. [](const Vec3f& pt1, const Vec3f&pt2) {
  3973. return pt1.z() < pt2.z();
  3974. });
  3975. std::array<Vec2f, 3> trianglef;
  3976. for (int i=0; i<3; ++i)
  3977. trianglef[i] = to_2d(facet[i]);
  3978. // Find lowest slice not below the triangle.
  3979. auto it = std::lower_bound(layers.begin(), layers.end(), facet[0].z()+EPSILON,
  3980. [](const Layer* l1, float z) {
  3981. return l1->slice_z < z;
  3982. });
  3983. // Count how many projections will be generated for this triangle
  3984. // and allocate respective amount in projections_of_triangles.
  3985. size_t first_layer_id = projections_of_triangles[idx].first_layer_id = it - layers.begin();
  3986. size_t last_layer_id = first_layer_id;
  3987. // The cast in the condition below is important. The comparison must
  3988. // be an exact opposite of the one lower in the code where
  3989. // the polygons are appended. And that one is on floats.
  3990. while (last_layer_id + 1 < layers.size()
  3991. && float(layers[last_layer_id]->slice_z) <= facet[2].z())
  3992. ++last_layer_id;
  3993. if (first_layer_id == last_layer_id) {
  3994. // The triangle fits just a single slab, just project it. This also avoids division by zero for horizontal triangles.
  3995. float dz = facet[2].z() - facet[0].z();
  3996. assert(dz >= 0);
  3997. // The face is nearly horizontal and it crosses the slicing plane at first_layer_id - 1.
  3998. // Rather add this face to both the planes.
  3999. bool add_below = dz < float(2. * EPSILON) && first_layer_id > 0 && layers[first_layer_id - 1]->slice_z > facet[0].z() - EPSILON;
  4000. projections_of_triangles[idx].polygons.reserve(add_below ? 2 : 1);
  4001. projections_of_triangles[idx].polygons.emplace_back(trianglef);
  4002. if (add_below) {
  4003. -- projections_of_triangles[idx].first_layer_id;
  4004. projections_of_triangles[idx].polygons.emplace_back(trianglef);
  4005. }
  4006. return; //continue (next facet idx)
  4007. }
  4008. projections_of_triangles[idx].polygons.resize(last_layer_id - first_layer_id + 1);
  4009. // Calculate how to move points on triangle sides per unit z increment.
  4010. Vec2f ta(trianglef[1] - trianglef[0]);
  4011. Vec2f tb(trianglef[2] - trianglef[0]);
  4012. ta *= 1.f/(facet[1].z() - facet[0].z());
  4013. tb *= 1.f/(facet[2].z() - facet[0].z());
  4014. // Projection on current slice will be built directly in place.
  4015. LightPolygon* proj = &projections_of_triangles[idx].polygons[0];
  4016. proj->add(trianglef[0]);
  4017. bool passed_first = false;
  4018. bool stop = false;
  4019. // Project a sub-polygon on all slices intersecting the triangle.
  4020. while (it != layers.end()) {
  4021. const float z = float((*it)->slice_z);
  4022. // Projections of triangle sides intersections with slices.
  4023. // a moves along one side, b tracks the other.
  4024. Vec2f a;
  4025. Vec2f b;
  4026. // If the middle vertex was already passed, append the vertex
  4027. // and use ta for tracking the remaining side.
  4028. if (z > facet[1].z() && ! passed_first) {
  4029. proj->add(trianglef[1]);
  4030. ta = trianglef[2]-trianglef[1];
  4031. ta *= 1.f/(facet[2].z() - facet[1].z());
  4032. passed_first = true;
  4033. }
  4034. // This slice is above the triangle already.
  4035. if (z > facet[2].z() || it+1 == layers.end()) {
  4036. proj->add(trianglef[2]);
  4037. stop = true;
  4038. }
  4039. else {
  4040. // Move a, b along the side it currently tracks to get
  4041. // projected intersection with current slice.
  4042. a = passed_first ? (trianglef[1]+ta*(z-facet[1].z()))
  4043. : (trianglef[0]+ta*(z-facet[0].z()));
  4044. b = trianglef[0]+tb*(z-facet[0].z());
  4045. proj->add(a);
  4046. proj->add(b);
  4047. }
  4048. if (stop)
  4049. break;
  4050. // Advance to the next layer.
  4051. ++it;
  4052. ++proj;
  4053. assert(proj <= &projections_of_triangles[idx].polygons.back() );
  4054. // a, b are first two points of the polygon for the next layer.
  4055. proj->add(b);
  4056. proj->add(a);
  4057. }
  4058. }); // end of parallel_for
  4059. // Make sure that the output vector can be used.
  4060. out.resize(layers.size());
  4061. // Now append the collected polygons to respective layers.
  4062. for (auto& trg : projections_of_triangles) {
  4063. int layer_id = int(trg.first_layer_id);
  4064. for (LightPolygon &poly : trg.polygons) {
  4065. if (layer_id >= int(out.size()))
  4066. break; // part of triangle could be projected above top layer
  4067. assert(! poly.pts.empty());
  4068. // The resulting triangles are fed to the Clipper library, which seem to handle flipped triangles well.
  4069. // if (cross2(Vec2d((poly.pts[1] - poly.pts[0]).cast<double>()), Vec2d((poly.pts[2] - poly.pts[1]).cast<double>())) < 0)
  4070. // std::swap(poly.pts.front(), poly.pts.back());
  4071. out[layer_id].emplace_back(std::move(poly.pts));
  4072. ++layer_id;
  4073. }
  4074. }
  4075. }
  4076. void PrintObject::project_and_append_custom_facets(
  4077. bool seam, EnforcerBlockerType type, std::vector<Polygons>& out) const
  4078. {
  4079. for (const ModelVolume* mv : this->model_object()->volumes)
  4080. if (mv->is_model_part()) {
  4081. const indexed_triangle_set custom_facets = seam
  4082. ? mv->seam_facets.get_facets_strict(*mv, type)
  4083. : mv->supported_facets.get_facets_strict(*mv, type);
  4084. if (! custom_facets.indices.empty()) {
  4085. if (seam)
  4086. project_triangles_to_slabs(this->layers(), custom_facets,
  4087. (this->trafo_centered() * mv->get_matrix()).cast<float>(),
  4088. seam, out);
  4089. else {
  4090. std::vector<Polygons> projected;
  4091. // Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane.
  4092. slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){});
  4093. // Merge these projections with the output, layer by layer.
  4094. assert(! projected.empty());
  4095. assert(out.empty() || out.size() == projected.size());
  4096. if (out.empty())
  4097. out = std::move(projected);
  4098. else
  4099. for (size_t i = 0; i < out.size(); ++ i)
  4100. append(out[i], std::move(projected[i]));
  4101. }
  4102. }
  4103. }
  4104. }
  4105. const Layer* PrintObject::get_layer_at_printz(coordf_t print_z) const {
  4106. auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
  4107. return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
  4108. }
  4109. Layer* PrintObject::get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
  4110. // Get a layer approximately at print_z.
  4111. const Layer* PrintObject::get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
  4112. coordf_t limit = print_z - epsilon;
  4113. auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
  4114. return (it == m_layers.end() || (*it)->print_z > print_z + epsilon) ? nullptr : *it;
  4115. }
  4116. Layer* PrintObject::get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
  4117. const Layer *PrintObject::get_first_layer_bellow_printz(coordf_t print_z, coordf_t epsilon) const
  4118. {
  4119. coordf_t limit = print_z + epsilon;
  4120. auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
  4121. return (it == m_layers.begin()) ? nullptr : *(--it);
  4122. }
  4123. } // namespace Slic3r