From 3dc80593bdb88e8b93d6bcb39b4c3d877971be96 Mon Sep 17 00:00:00 2001 From: Kiss Lorand <50251547+kisslorand@users.noreply.github.com> Date: Mon, 29 Dec 2025 03:35:44 +0200 Subject: [PATCH] Brim: optionally generate brim from Elephant Foot Compensation outline (#11760) * Brim can follow EFC outline * Optimization * Update Spanish EFC brim description Adopt reviewer-proposed wording from RF47. Co-authored-by: RF47 * Tag Orca specific changes Tag Orca specific changes vs. Bambu using the comment //ORCA: . This helps when reviewing merge commits from upstream Bambu so we don't end up causing regressions when pulling in commits from upstream * Tooltip update --------- Co-authored-by: RF47 Co-authored-by: Ioannis Giannakas <59056762+igiannakas@users.noreply.github.com> --- localization/i18n/OrcaSlicer.pot | 13 + localization/i18n/ca/OrcaSlicer_ca.po | 20 + localization/i18n/cs/OrcaSlicer_cs.po | 20 + localization/i18n/de/OrcaSlicer_de.po | 20 + localization/i18n/en/OrcaSlicer_en.po | 20 + localization/i18n/es/OrcaSlicer_es.po | 20 + localization/i18n/fr/OrcaSlicer_fr.po | 20 + localization/i18n/hu/OrcaSlicer_hu.po | 20 + localization/i18n/it/OrcaSlicer_it.po | 20 + localization/i18n/ja/OrcaSlicer_ja.po | 20 + localization/i18n/ko/OrcaSlicer_ko.po | 20 + localization/i18n/lt/OrcaSlicer_lt.po | 20 + localization/i18n/nl/OrcaSlicer_nl.po | 20 + localization/i18n/pl/OrcaSlicer_pl.po | 20 + localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 20 + localization/i18n/ru/OrcaSlicer_ru.po | 20 + localization/i18n/sv/OrcaSlicer_sv.po | 20 + localization/i18n/tr/OrcaSlicer_tr.po | 20 + localization/i18n/uk/OrcaSlicer_uk.po | 20 + localization/i18n/vi/OrcaSlicer_vi.po | 20 + localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 22 +- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 22 +- src/libslic3r/Brim.cpp | 1169 +++---------------- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 10 + src/libslic3r/PrintConfig.hpp | 1 + src/libslic3r/PrintObject.cpp | 1 + src/slic3r/GUI/ConfigManipulation.cpp | 1 + src/slic3r/GUI/GUI_Factories.cpp | 16 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + 31 files changed, 624 insertions(+), 1016 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index accaf4ea66..4901a6b7a5 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -11108,6 +11108,19 @@ msgid "" "easily." msgstr "" +msgid "Brim follows compensated outline" +msgstr "" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" + msgid "Brim ears" msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index cfb35a2480..d29d05b06b 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -12177,6 +12177,26 @@ msgstr "" "Un espai entre la línia de la Vora d'Adherència més interna i l'objecte pot " "fer que la Vora d'Adherència s'elimini més fàcilment" +msgid "Brim follows compensated outline" +msgstr "Vora d'Adherència segueix un esquema compensat" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Quan està activat, vora d'adherència s'alinea amb la geometria del perímetre de la primera capa " +"després d'aplicar la compensació del peu d'elefant.\n" +"Aquesta opció està pensada per als casos en què la compensació del peu d'elefant " +"altera significativament la petjada de la primera capa.\n" +"\n" +"Si la vostra configuració actual ja funciona bé, activar-la pot ser innecessari i " +"pot fer que el vora d'adherència es fusioni amb les capes superiors." + msgid "Brim ears" msgstr "Orelles de la Vora d'Adherència" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index 9cc4976536..933c3b3504 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -11730,6 +11730,26 @@ msgid "" msgstr "" "Mezera mezi nejvnitřnějším límcem a předmětem může usnadnit odstranění límce" +msgid "Brim follows compensated outline" +msgstr "Límec sleduje kompenzovaný obrys" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Když je povoleno, límec je zarovnán s obvodovou geometrií první vrstvy " +"po použití kompenzace sloní nohy.\n" +"Tato možnost je určena pro případy, kdy je kompenzace sloní nohy " +"výrazně mění stopu první vrstvy.\n" +"\n" +"Pokud vaše aktuální nastavení již funguje dobře, jeho povolení může být zbytečné a " +"může způsobit spojení límec s horními vrstvami." + msgid "Brim ears" msgstr "Uši límce" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index f0a0be35b4..15b84734a4 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -12766,6 +12766,26 @@ msgstr "" "Eine Lücke zwischen der innersten Randlinie und dem Objekt kann das Abnehmen " "des Randes erleichtern" +msgid "Brim follows compensated outline" +msgstr "Umrandung folgt einem kompensierten Umriss" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Wenn diese Option aktiviert ist, wird umrandung an der Umfangsgeometrie der ersten Ebene ausgerichtet " +"nach Anwendung der Elefantenfußkompensation.\n" +"Diese Option ist für Fälle gedacht, in denen eine Elefantenfuß-Entschädigung vorliegt " +"verändert den Footprint der ersten Schicht erheblich.\n" +"\n" +"Wenn Ihr aktuelles Setup bereits gut funktioniert, kann es unnötig sein, es zu aktivieren " +"kann dazu führen, dass der umrandung mit den oberen Schichten verschmilzt." + msgid "Brim ears" msgstr "Brim Ohren" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 647f62ee13..02b4dd6c18 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -11327,6 +11327,26 @@ msgstr "" "This creates a gap between the innermost brim line and the object and can " "make the brim easier to remove." +msgid "Brim follows compensated outline" +msgstr "Brim follows compensated outline" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." + msgid "Brim ears" msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 85079d85fe..19c81d480d 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -12147,6 +12147,26 @@ msgstr "" "Un hueco entre la línea más interna del borde de adherencia y el objeto " "puede hacer que el borde de adherencia se retire más fácilmente" +msgid "Brim follows compensated outline" +msgstr "Borde de adherencia sigue el esquema compensado" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Cuando está habilitado, el borde de adherencia está alineado con la geometría del perímetro de la primera capa " +"después de aplicar la compensación de pata de elefante.\n" +"Esta opción está destinada a casos en los que la Compensación por pata de elefante " +"altera significativamente la huella de la primera capa.\n" +"\n" +"Si su configuración actual ya funciona bien, habilitarla puede ser innecesario y " +"puede hacer que el borde de adherencia se fusione con las capas superiores." + msgid "Brim ears" msgstr "Orejas de borde" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 1dd903bc10..5a80f34757 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -12298,6 +12298,26 @@ msgstr "" "Un espace entre la ligne de bord la plus interne et l'objet peut faciliter " "le retrait du bord" +msgid "Brim follows compensated outline" +msgstr "Bordure suit le contour compensé" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Lorsqu'il est activé, le bordure est aligné avec la géométrie du périmètre de la première couche " +"après l'application de la compensation du pied d'éléphant.\n" +"Cette option est destinée aux cas où la compensation du pied d'éléphant " +"modifie considérablement l’empreinte de la première couche.\n" +"\n" +"Si votre configuration actuelle fonctionne déjà bien, son activation peut être inutile et " +"peut provoquer la fusion du bordure avec les couches supérieures." + msgid "Brim ears" msgstr "Bordures à oreilles" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index ddd70907ba..ba898f64ac 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -11603,6 +11603,26 @@ msgstr "" "A legbelső peremvonal és a tárgy közötti rés, ami megkönnyítheti a perem " "eltávolítását" +msgid "Brim follows compensated outline" +msgstr "A Perem a kompenzált körvonalat követi" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Ha engedélyezve van, a perem igazodik az első réteg kerületi geometriájához " +"az elefánttalp-kompenzáció alkalmazása után.\n" +"Ez az opció arra az esetre szolgál, amikor az elefánttalp-kompenzáció " +"jelentősen megváltoztatja az első réteg alapterületét.\n" +"\n" +"Ha a jelenlegi beállítás már jól működik, előfordulhat, hogy az engedélyezése felesleges és " +"a perem összeolvadását okozhatja a felső rétegekkel." + msgid "Brim ears" msgstr "Karimás fülek" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index 43ee2d09c0..222467d02a 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -12234,6 +12234,26 @@ msgstr "" "Crea uno spazio tra la linea più interna della tesa e l'oggetto per rendere " "più facile la rimozione della tesa." +msgid "Brim follows compensated outline" +msgstr "Tesa segue il contorno compensato" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Quando abilitato, tesa è allineato con la geometria perimetrale del primo strato " +"dopo l'applicazione della compensazione del piede di elefante.\n" +"Questa opzione è prevista per i casi in cui è prevista la compensazione del piede di elefante " +"altera significativamente l'impronta del primo strato.\n" +"\n" +"Se la tua configurazione attuale funziona già bene, abilitarla potrebbe non essere necessaria e " +"può causare la fusione del tesa con gli strati superiori." + msgid "Brim ears" msgstr "Tesa ad orecchio" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 120ccae558..3258a45800 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -11394,6 +11394,26 @@ msgstr "" "ブリムを取り外しやすくする為、一番内側のブリムラインをモデルと少し距離を設け" "ます。" +msgid "Brim follows compensated outline" +msgstr "ブリム は補正されたアウトラインに従います" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"有効にすると、ブリム は最初の層の周囲ジオメトリと位置合わせされます。 " +"エレファント・フット・コンペンセーション適用後。\n" +"このオプションは、象の足の補正が必要な場合を対象としています。 " +"最初の層のフットプリントを大幅に変更します。\n" +"\n" +"現在の設定がすでにうまく機能している場合は、それを有効にする必要はないかもしれません。 " +"ブリム が上位層と融合する可能性があります。" + msgid "Brim ears" msgstr "" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index fbc550e415..cf3d9dea71 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -11817,6 +11817,26 @@ msgstr "" "가장 안쪽 브림 라인과 객체 사이에 간격을 주어 쉽게 브림을 제거 할 수 있게 합" "니다" +msgid "Brim follows compensated outline" +msgstr "브림는 보상된 아웃라인을 따릅니다." + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"활성화되면 브림은 첫 번째 레이어 주변 형상과 정렬됩니다 " +"코끼리 발 보정이 적용된 후.\n" +"이 옵션은 코끼리 발 보상이 적용되는 경우를 위한 것입니다 " +"첫 번째 레이어 공간을 크게 변경합니다.\n" +"\n" +"현재 설정이 이미 잘 작동하는 경우 활성화할 필요가 없으며 " +"브림이 상위 레이어와 융합될 수 있습니다." + msgid "Brim ears" msgstr "브림 귀" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 052250e63f..ec9f6ce417 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -12183,6 +12183,26 @@ msgstr "" "Sukuriamas tarpas tarp vidinės krašto linijos ir objekto, todėl galima " "lengviau jį atskirti." +msgid "Brim follows compensated outline" +msgstr "Kraštas atitinka kompensuotą kontūrą" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Kai įjungta, kraštas yra sulygiuotas su pirmojo sluoksnio perimetro geometrija " +"pritaikius dramblio pėdos kompensaciją.\n" +"Ši parinktis skirta tais atvejais, kai kompensuojama dramblio pėda " +"žymiai pakeičia pirmojo sluoksnio pėdsaką.\n" +"\n" +"Jei dabartinė sąranka jau veikia gerai, jos įjungti gali nebūti ir " +"gali sukelti kraštas susiliejimą su viršutiniais sluoksniais." + msgid "Brim ears" msgstr "Krašto \"ausys\"" diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 2f1c24f60d..923ea51aec 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -11751,6 +11751,26 @@ msgstr "" "Dit creëert ruimte tussen de binnenste brimlijn en het object en zorgt " "ervoor dat het object eenvoudiger van het printbed kan worden verwijderd." +msgid "Brim follows compensated outline" +msgstr "Rand volgt de gecompenseerde omtrek" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Indien ingeschakeld, wordt de rand uitgelijnd met de omtrekgeometrie van de eerste laag " +"nadat olifantenvoetcompensatie is toegepast.\n" +"Deze optie is bedoeld voor gevallen waarin sprake is van olifantenvoetcompensatie " +"verandert de voetafdruk van de eerste laag aanzienlijk.\n" +"\n" +"Als uw huidige configuratie al goed werkt, kan het inschakelen hiervan niet nodig zijn " +"kan ervoor zorgen dat de rand samensmelt met de bovenste lagen." + msgid "Brim ears" msgstr "Rand oren" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index 81afc09e9b..5c2896d962 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -12130,6 +12130,26 @@ msgstr "" "Szczelina między najbardziej wewnętrzną linią brimu a obiektem może ułatwić " "usunięcie brimu" +msgid "Brim follows compensated outline" +msgstr "Brim podąża za skompensowanym konturem" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Po włączeniu brim jest wyrównany z geometrią obwodu pierwszej warstwy " +"po zastosowaniu Kompensacji Stopy Słonia.\n" +"Ta opcja jest przeznaczona dla przypadków, w których występuje kompensacja stopy słonia " +"znacząco zmienia ślad pierwszej warstwy.\n" +"\n" +"Jeśli Twoja bieżąca konfiguracja już działa dobrze, włączenie jej może być niepotrzebne i " +"może spowodować stopienie brim z górnymi warstwami." + msgid "Brim ears" msgstr "Uszy brim" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 73fcdb50ea..cffab32de6 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -12555,6 +12555,26 @@ msgstr "" "Um espaço entre a linha mais interna da borda e o objeto pode facilitar a " "remoção da borda." +msgid "Brim follows compensated outline" +msgstr "Borda segue contorno compensado" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Quando ativado, o borda fica alinhado com a geometria do perímetro da primeira camada " +"após a aplicação da Compensação da Pé de Elefante.\n" +"Esta opção destina-se aos casos em que a Compensação da Pé de Elefante " +"altera significativamente a pegada da primeira camada.\n" +"\n" +"Se a sua configuração atual já funciona bem, ativá-la pode ser desnecessário e " +"pode fazer com que o borda se funda com as camadas superiores." + msgid "Brim ears" msgstr "Orelhas da borda" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index d9ff700c16..4364ce8306 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -12291,6 +12291,26 @@ msgid "" "easily." msgstr "Смещение каймы от печатаемой модели, может облегчить её удаление." +msgid "Brim follows compensated outline" +msgstr "Кайма соответствует компенсированному контуру" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Если этот параметр включен, кайма выравнивается по геометрии периметра первого слоя " +"после применения компенсации «слоновьей стопы».\n" +"Эта опция предназначена для случаев, когда «Компенсация слоновой стопы» " +"существенно изменяет след первого слоя.\n" +"\n" +"Если ваша текущая настройка уже работает хорошо, ее включение может быть ненужным и " +"может привести к слиянию кайма с верхними слоями." + msgid "Brim ears" msgstr "Ушки каймы" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 04c2d4d565..ab1944d79e 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -11574,6 +11574,26 @@ msgstr "" "Mellanrum mellan innersta brim linjen och objektet kan underlätta vid " "borttagande av brim" +msgid "Brim follows compensated outline" +msgstr "Brim följer kompenserad disposition" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"När den är aktiverad, är brim justerad med det första lagrets omkretsgeometri " +"efter att elefantfotskompensation tillämpas.\n" +"Detta alternativ är avsett för fall där elefantfotskompensation " +"förändrar det första skiktets fotavtryck avsevärt.\n" +"\n" +"Om din nuvarande inställning redan fungerar bra kan det vara onödigt att aktivera det och " +"kan få brim att smälta samman med de övre lagren." + msgid "Brim ears" msgstr "Brätte öron" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index a817dd919e..b10eacfc6e 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -12097,6 +12097,26 @@ msgstr "" "En içteki kenar çizgisi ile nesne arasındaki boşluk, kenarlığın daha kolay " "çıkarılmasını sağlayabilir." +msgid "Brim follows compensated outline" +msgstr "Kenar telafi edilen taslağı takip ediyor" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Etkinleştirildiğinde, kenar birinci katmanın çevre geometrisiyle hizalanır " +"Fil Ayağı Telafisi uygulandıktan sonra.\n" +"Bu seçenek Fil Ayağı Telafisinin geçerli olmadığı durumlar için tasarlanmıştır " +"ilk katmanın ayak izini önemli ölçüde değiştirir.\n" +"\n" +"Mevcut kurulumunuz zaten iyi çalışıyorsa, bunu etkinleştirmek gereksiz olabilir ve " +"kenar'in üst katmanlarla kaynaşmasına neden olabilir." + msgid "Brim ears" msgstr "Kenar kulakları" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index 05482e66d1..296efbe5bd 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -12138,6 +12138,26 @@ msgstr "" "Зазор між першою внутрішньою лінією кайми та об'єктом може сприяти легшому " "відокремленню кайми" +msgid "Brim follows compensated outline" +msgstr "Кайма має компенсований контур" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Якщо ввімкнено, кайма вирівнюється з геометрією периметра першого рівня " +"після застосування Elephant Foot Compensation.\n" +"Ця опція призначена для випадків компенсації слонячої стопи " +"значно змінює поверхню першого шару.\n" +"\n" +"Якщо ваші поточні налаштування вже працюють добре, увімкнення їх може бути непотрібним " +"може призвести до злиття кайма з верхніми шарами." + msgid "Brim ears" msgstr "Вушка кайми" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index f14576ceed..5017bc246f 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -11926,6 +11926,26 @@ msgstr "" "Khoảng cách giữa đường brim trong cùng và đối tượng có thể làm cho brim dễ " "dàng tháo hơn." +msgid "Brim follows compensated outline" +msgstr "Brim tuân theo phác thảo được bù đắp" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"Khi được bật, brim sẽ được căn chỉnh theo hình học chu vi lớp đầu tiên " +"sau khi áp dụng Bồi thường bàn chân voi.\n" +"Tùy chọn này dành cho các trường hợp Bồi thường chân voi " +"làm thay đổi đáng kể dấu chân lớp đầu tiên.\n" +"\n" +"Nếu thiết lập hiện tại của bạn đã hoạt động tốt, việc bật nó có thể không cần thiết và " +"có thể khiến brim kết hợp với các lớp trên." + msgid "Brim ears" msgstr "Tai brim" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 952bd49555..8cad4e58a5 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -2490,7 +2490,7 @@ msgid "Plate" msgstr "盘" msgid "Brim" -msgstr "Brim" +msgstr "边缘" msgid "Object/Part Setting" msgstr "对象/零件设置" @@ -11493,6 +11493,26 @@ msgid "" "easily." msgstr "在brim和模型之间设置间隙,能够让brim更容易剥离" +msgid "Brim follows compensated outline" +msgstr "边缘 遵循补偿轮廓" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"启用后,边缘 与第一层周边几何体对齐 " +"应用象脚补偿后。\n" +"此选项适用于象脚补偿的情况 " +"显着改变第一层足迹。\n" +"\n" +"如果您当前的设置已经运行良好,则可能没有必要启用它,并且 " +"可以导致 边缘 与上层融合。" + msgid "Brim ears" msgstr "圆盘" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 01c3669856..51d89cca21 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -2493,7 +2493,7 @@ msgid "Plate" msgstr "列印板" msgid "Brim" -msgstr "Brim" +msgstr "邊緣" msgid "Object/Part Setting" msgstr "物件/零件 設定" @@ -11560,6 +11560,26 @@ msgid "" "easily." msgstr "在 Brim 和模型之間設定間隙,能夠讓 Brim 更容易拆除" +msgid "Brim follows compensated outline" +msgstr "邊緣 遵循補償輪廓" + +msgid "" +"When enabled, the brim is aligned with the first-layer perimeter geometry " +"after Elephant Foot Compensation is applied.\n" +"This option is intended for cases where Elephant Foot Compensation " +"significantly alters the first-layer footprint.\n" +"\n" +"If your current setup already works well, enabling it may be unnecessary and " +"can cause the brim to fuse with upper layers." +msgstr "" +"啟用後,邊緣 與第一層周邊幾何體對齊 " +"應用像腳補償後。\n" +"此選項適用於像腳補償的情況 " +"顯著改變第一層足跡。\n" +"\n" +"如果您當前的設置已經運行良好,則可能沒有必要啟用它,並且 " +"可以導致 邊緣 與上層融合。" + msgid "Brim ears" msgstr "耳狀 Brim" diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index d21ed2e544..35d971a465 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -1,5 +1,3 @@ -#include "clipper/clipper_z.hpp" - #include "ClipperUtils.hpp" #include "EdgeGrid.hpp" #include "Layer.hpp" @@ -10,8 +8,8 @@ #include "MaterialType.hpp" #include "Model.hpp" #include -#include -#include +#include +#include #include #include @@ -54,16 +52,63 @@ static void append_and_translate(Polygons &dst, const Polygons &src, const Print dst[dst_idx].translate(instance_shift); } -static float max_brim_width(const ConstPrintObjectPtrsAdaptor &objects) +//ORCA: Brim can follow the post-EFC outline when enabled. +static bool use_brim_efc_outline(const PrintObject &object) { - assert(!objects.empty()); - return float(std::accumulate(objects.begin(), objects.end(), 0., - [](double partial_result, const PrintObject *object) { - return std::max(partial_result, object->config().brim_type == btNoBrim ? 0. : object->config().brim_width.value); - })); + return object.config().brim_use_efc_outline.value + && object.config().elefant_foot_compensation.value > 0. + && object.config().elefant_foot_compensation_layers.value > 0 + && object.config().raft_layers.value == 0; } -// Returns ExPolygons of the bottom layer of the print object after elephant foot compensation. +//ORCA: Helper for snapping painted ears to the EFC outline. +static bool closest_point_on_expolygons(const ExPolygons &polygons, const Point &from, Point &closest_out) +{ + double min_dist2 = std::numeric_limits::max(); + bool found = false; + + for (const ExPolygon &poly : polygons) { + for (int i = 0; i < poly.num_contours(); ++i) { + const Point *candidate = poly.contour_or_hole(i).closest_point(from); + if (candidate == nullptr) + continue; + const int64_t dx = int64_t(candidate->x()) - int64_t(from.x()); + const int64_t dy = int64_t(candidate->y()) - int64_t(from.y()); + const double dist2 = double(dx * dx + dy * dy); + if (dist2 < min_dist2) { + min_dist2 = dist2; + closest_out = *candidate; + found = true; + } + } + } + return found; +} + +//ORCA: Helper for matching painted ears to their original island before EFC snapping. +static int find_containing_expolygon_index(const ExPolygons &polygons, const Point &from) +{ + for (size_t idx = 0; idx < polygons.size(); ++idx) { + if (polygons[idx].contains(from)) + return int(idx); + } + return -1; +} + +//ORCA: Keep painted ear snapping on the matching island when using EFC outline. +static bool closest_point_on_matching_island(const ExPolygons &raw_outline, const ExPolygons &efc_outline, const Point &from, Point &closest_out) +{ + const int island_idx = find_containing_expolygon_index(raw_outline, from); + if (island_idx >= 0) { + ExPolygons island_outline = intersection_ex(efc_outline, raw_outline[island_idx]); + if (!island_outline.empty()) + return closest_point_on_expolygons(island_outline, from, closest_out); + } + return closest_point_on_expolygons(efc_outline, from, closest_out); +} +//ORCA: Use post-processed first-layer slices (including EFC) for brim outline. +// Returns ExPolygons of the bottom layer after all first-layer modifiers +// (including elephant foot compensation, if enabled) have been applied. static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &print_object) { ExPolygons ex_polygons; @@ -71,506 +116,6 @@ static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &pr Slic3r::append(ex_polygons, closing_ex(region->slices.surfaces, float(SCALED_EPSILON))); return ex_polygons; } - -// Returns ExPolygons of bottom layer for every print object in Print after elephant foot compensation. -static std::vector get_print_bottom_layers_expolygons(const Print &print) -{ - std::vector bottom_layers_expolygons; - bottom_layers_expolygons.reserve(print.objects().size()); - for (const PrintObject *object : print.objects()) - bottom_layers_expolygons.emplace_back(get_print_object_bottom_layer_expolygons(*object)); - - return bottom_layers_expolygons; -} - -static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, const std::vector &bottom_layers_expolygons) -{ - assert(print.objects().size() == bottom_layers_expolygons.size()); - Polygons islands; - ConstPrintObjectPtrs island_to_object; - for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) { - const PrintObject *object = print.objects()[print_object_idx]; - Polygons islands_object; - islands_object.reserve(bottom_layers_expolygons[print_object_idx].size()); - for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) - islands_object.emplace_back(ex_poly.contour); - - islands.reserve(islands.size() + object->instances().size() * islands_object.size()); - for (const PrintInstance& instance : object->instances()) { - Point instance_shift = instance.shift_without_plate_offset(); - for (Polygon& poly : islands_object) { - islands.emplace_back(poly); - islands.back().translate(instance_shift); - island_to_object.emplace_back(object); - } - } - } - assert(islands.size() == island_to_object.size()); - - ClipperLib_Z::Paths islands_clip; - islands_clip.reserve(islands.size()); - for (const Polygon &poly : islands) { - islands_clip.emplace_back(); - ClipperLib_Z::Path &island_clip = islands_clip.back(); - island_clip.reserve(poly.points.size()); - int island_idx = int(&poly - &islands.front()); - // The Z coordinate carries index of the island used to get the pointer to the object. - for (const Point &pt : poly.points) - island_clip.emplace_back(pt.x(), pt.y(), island_idx + 1); - } - - // Init Clipper - ClipperLib_Z::Clipper clipper; - // Assign the maximum Z from four points. This values is valid index of the island - clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, - const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) { - pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z())); - }); - // Add islands - clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true); - // Execute union operation to construct polytree - ClipperLib_Z::PolyTree islands_polytree; - //FIXME likely pftNonZero or ptfPositive would be better. Why are we using ptfEvenOdd for Unions? - clipper.Execute(ClipperLib_Z::ctUnion, islands_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); - - std::unordered_set processed_objects_idx; - ConstPrintObjectPtrs top_level_objects_with_brim; - for (int i = 0; i < islands_polytree.ChildCount(); ++i) { - for (const ClipperLib_Z::IntPoint &point : islands_polytree.Childs[i]->Contour) { - if (point.z() != 0 && processed_objects_idx.find(island_to_object[point.z() - 1]->id().id) == processed_objects_idx.end()) { - top_level_objects_with_brim.emplace_back(island_to_object[point.z() - 1]); - processed_objects_idx.insert(island_to_object[point.z() - 1]->id().id); - } - } - } - return top_level_objects_with_brim; -} - -static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim, const double scaled_resolution) -{ - Polygons islands; - for (const PrintObject *object : top_level_objects_with_brim) { - if (!object->has_brim()) - continue; - - //FIXME how about the brim type? - auto brim_object_gap = float(scale_(object->config().brim_object_gap.value)); - Polygons islands_object; - for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) { - Polygons contour_offset = offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare); - for (Polygon &poly : contour_offset) - poly.douglas_peucker(scaled_resolution); - - polygons_append(islands_object, std::move(contour_offset)); - } - - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - Polygons contour_offset = offset(support_contour, brim_object_gap, ClipperLib::jtSquare); - for (Polygon& poly : contour_offset) - poly.douglas_peucker(scaled_resolution); - - polygons_append(islands_object, std::move(contour_offset)); - } - } - - for (const PrintInstance &instance : object->instances()) - append_and_translate(islands, islands_object, instance); - } - return islands; -} - -static ExPolygons top_level_outer_brim_area(const Print &print, - const ConstPrintObjectPtrs &top_level_objects_with_brim, - const std::vector &bottom_layers_expolygons, - const float no_brim_offset, - // BBS - double& brim_width_max, - std::map& brim_width_map) -{ - const auto scaled_resolution = scaled(print.config().resolution.value); - - assert(print.objects().size() == bottom_layers_expolygons.size()); - std::unordered_set top_level_objects_idx; - top_level_objects_idx.reserve(top_level_objects_with_brim.size()); - for (const PrintObject *object : top_level_objects_with_brim) - top_level_objects_idx.insert(object->id().id); - - ExPolygons brim_area; - ExPolygons no_brim_area; - brim_width_max = 0; - for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) { - const PrintObject *object = print.objects()[print_object_idx]; - const BrimType brim_type = object->config().brim_type.value; - const float brim_object_gap = scale_(object->config().brim_object_gap.value); - // recording the autoAssigned brimWidth and corresponding objs - double brimWidthAuto = object->config().brim_width.value; - double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR; - brimWidthAuto = floor(brimWidthAuto / flowWidth / 2) * flowWidth * 2; - brim_width_map.insert(std::make_pair(object->id(), brimWidthAuto)); - brim_width_max = std::max(brim_width_max, brimWidthAuto); - const float brim_width = scale_(brimWidthAuto); - const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end(); - - ExPolygons brim_area_object; - ExPolygons no_brim_area_object; - for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) { - if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim) - append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_object_gap, ClipperLib::jtRound, scaled_resolution), offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare))); - - // After 7ff76d07684858fd937ef2f5d863f105a10f798e offset and shrink don't work with CW polygons (holes), so let's make it CCW. - Polygons ex_poly_holes_reversed = ex_poly.holes; - polygons_reverse(ex_poly_holes_reversed); - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare)); - - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed)); - - if (brim_type != BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ExPolygon(ex_poly.contour), brim_object_gap, ClipperLib::jtSquare)); - - no_brim_area_object.emplace_back(ex_poly.contour); - } - - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim) - append(brim_area_object, diff_ex(offset(support_contour, brim_width + brim_object_gap, ClipperLib::jtRound, scaled_resolution), offset(support_contour, brim_object_gap))); - - if (brim_type != BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ExPolygon(support_contour), brim_object_gap)); - - no_brim_area_object.emplace_back(support_contour); - } - } - - for (const PrintInstance &instance : object->instances()) { - append_and_translate(brim_area, brim_area_object, instance); - append_and_translate(no_brim_area, no_brim_area_object, instance); - } - } - - return diff_ex(brim_area, no_brim_area); -} - -// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders -static ExPolygons top_level_outer_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, - const float no_brim_offset, double& brim_width_max, std::map& brim_width_map, - std::map& brimAreaMap, - std::map& supportBrimAreaMap, std::vector>& objPrintVec) -{ - std::unordered_set top_level_objects_idx; - top_level_objects_idx.reserve(top_level_objects_with_brim.size()); - for (const PrintObject* object : top_level_objects_with_brim) - top_level_objects_idx.insert(object->id().id); - - unsigned int support_material_extruder = 1; - if (print.has_support_material()) { - assert(top_level_objects_with_brim.front()->config().support_filament >= 0); - if (top_level_objects_with_brim.front()->config().support_filament > 0) - support_material_extruder = top_level_objects_with_brim.front()->config().support_filament; - } - - ExPolygons brim_area; - ExPolygons no_brim_area; - brim_width_max = 0; - struct brimWritten { - bool obj; - bool sup; - }; - std::map brimToWrite; - for (const auto& objectWithExtruder : objPrintVec) - brimToWrite.insert({ objectWithExtruder.first, {true,true} }); - - for (unsigned int extruderNo : print.extruders()) { - ++extruderNo; - for (const auto &objectWithExtruder : objPrintVec) { - const PrintObject* object = print.get_object(objectWithExtruder.first); - const BrimType brim_type = object->config().brim_type.value; - const float brim_offset = scale_(object->config().brim_object_gap.value); - // recording the autoAssigned brimWidth and corresponding objs - double brimWidthAuto = object->config().brim_width.value; - double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR; - brimWidthAuto = floor(brimWidthAuto / flowWidth / 2) * flowWidth * 2; - brim_width_map.insert(std::make_pair(object->id(), brimWidthAuto)); - brim_width_max = std::max(brim_width_max, brimWidthAuto); - const float brim_width = scale_(brimWidthAuto); - const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end(); - - ExPolygons nullBrim; - brimAreaMap.insert(std::make_pair(object->id(), nullBrim)); - ExPolygons brim_area_object; - ExPolygons brim_area_support; - ExPolygons no_brim_area_object; - ExPolygons no_brim_area_support; - if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) { - for (const ExPolygon& ex_poly : object->layers().front()->lslices) { - if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim) { - append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION), - offset_ex(ex_poly.contour, brim_offset))); - } - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset)); - - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly.holes)); - - if (brim_type != BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ExPolygon(ex_poly.contour), brim_offset)); - - no_brim_area_object.emplace_back(ex_poly.contour); - } - brimToWrite.at(object->id()).obj = false; - for (const PrintInstance& instance : object->instances()) { - if (!brim_area_object.empty()) - append_and_translate(brim_area, brim_area_object, instance, print, brimAreaMap); - append_and_translate(no_brim_area, no_brim_area_object, instance); - } - if (brimAreaMap.find(object->id()) != brimAreaMap.end()) - expolygons_append(brim_area, brimAreaMap[object->id()]); - } - if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) { - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - //BBS: no brim offset for supports - if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) && is_top_outer_brim) - append(brim_area_support, diff_ex(offset(support_contour, brim_width, jtRound, SCALED_RESOLUTION), offset(support_contour, 0))); - - if (brim_type != BrimType::btNoBrim) - append(no_brim_area_support, offset_ex(support_contour, 0)); - - no_brim_area_support.emplace_back(support_contour); - } - } - - brimToWrite.at(object->id()).sup = false; - for (const PrintInstance& instance : object->instances()) { - if (!brim_area_support.empty()) - append_and_translate(brim_area, brim_area_support, instance, print, supportBrimAreaMap); - append_and_translate(no_brim_area, no_brim_area_support, instance); - } - if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end()) - expolygons_append(brim_area, supportBrimAreaMap[object->id()]); - } - } - } - for (const PrintObject* object : print.objects()) { - if (brimAreaMap.find(object->id()) != brimAreaMap.end()) - brimAreaMap[object->id()] = diff_ex(brimAreaMap[object->id()], no_brim_area); - if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end()) - supportBrimAreaMap[object->id()] = diff_ex(supportBrimAreaMap[object->id()], no_brim_area); - } - return diff_ex(std::move(brim_area), no_brim_area); -} -static ExPolygons inner_brim_area(const Print &print, - const ConstPrintObjectPtrs &top_level_objects_with_brim, - const std::vector &bottom_layers_expolygons, - const float no_brim_offset) -{ - assert(print.objects().size() == bottom_layers_expolygons.size()); - std::unordered_set top_level_objects_idx; - top_level_objects_idx.reserve(top_level_objects_with_brim.size()); - for (const PrintObject *object : top_level_objects_with_brim) - top_level_objects_idx.insert(object->id().id); - - ExPolygons brim_area; - ExPolygons no_brim_area; - Polygons holes; - for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) { - const PrintObject *object = print.objects()[print_object_idx]; - const BrimType brim_type = object->config().brim_type.value; - const float brim_object_gap = scale_(object->config().brim_object_gap.value); - double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR; - const float brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2); - const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end(); - - ExPolygons brim_area_object; - ExPolygons no_brim_area_object; - Polygons holes_object; - for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) { - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) { - if (top_outer_brim) - no_brim_area_object.emplace_back(ex_poly); - else - append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_object_gap, ClipperLib::jtSquare), offset(ex_poly.contour, brim_object_gap, ClipperLib::jtSquare))); - } - - // After 7ff76d07684858fd937ef2f5d863f105a10f798e offset and shrink don't work with CW polygons (holes), so let's make it CCW. - Polygons ex_poly_holes_reversed = ex_poly.holes; - polygons_reverse(ex_poly_holes_reversed); - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) - append(brim_area_object, diff_ex(shrink_ex(ex_poly_holes_reversed, brim_object_gap, ClipperLib::jtSquare), shrink_ex(ex_poly_holes_reversed, brim_width + brim_object_gap, ClipperLib::jtSquare))); - - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset, ClipperLib::jtSquare), ex_poly_holes_reversed)); - - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, diff_ex(ExPolygon(ex_poly.contour), shrink_ex(ex_poly_holes_reversed, no_brim_offset, ClipperLib::jtSquare))); - - append(holes_object, ex_poly_holes_reversed); - } - append(no_brim_area_object, offset_ex(bottom_layers_expolygons[print_object_idx], brim_object_gap, ClipperLib::jtSquare)); - - for (const PrintInstance &instance : object->instances()) { - append_and_translate(brim_area, brim_area_object, instance); - append_and_translate(no_brim_area, no_brim_area_object, instance); - append_and_translate(holes, holes_object, instance); - } - } - - return diff_ex(intersection_ex(to_polygons(std::move(brim_area)), holes), no_brim_area); -} - -// BBS: the brims of different objs will not overlapped with each other, and are stored by objs and by extruders -static ExPolygons inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, - const float no_brim_offset, std::map& brimAreaMap, - std::map& supportBrimAreaMap, - std::vector>& objPrintVec) -{ - std::unordered_set top_level_objects_idx; - top_level_objects_idx.reserve(top_level_objects_with_brim.size()); - for (const PrintObject* object : top_level_objects_with_brim) - top_level_objects_idx.insert(object->id().id); - - unsigned int support_material_extruder = 1; - if (print.has_support_material()) { - assert(top_level_objects_with_brim.front()->config().support_filament >= 0); - if (top_level_objects_with_brim.front()->config().support_filament > 0) - support_material_extruder = top_level_objects_with_brim.front()->config().support_filament; - } - - ExPolygons brim_area; - ExPolygons no_brim_area; - Polygons holes; - Polygon bedShape(get_bed_shape(print.config())); - holes.emplace_back(get_bed_shape(print.config())); - std::map innerBrimAreaMap; - std::map innerSupportBrimAreaMap; - - struct brimWritten { - bool obj; - bool sup; - }; - std::map brimToWrite; - for (const auto& objectWithExtruder : objPrintVec) - brimToWrite.insert({ objectWithExtruder.first, {true,true} }); - - - for (unsigned int extruderNo : print.extruders()) { - ++extruderNo; - for (const auto& objectWithExtruder : objPrintVec) { - const PrintObject* object = print.get_object(objectWithExtruder.first); - const BrimType brim_type = object->config().brim_type.value; - const float brim_offset = scale_(object->config().brim_object_gap.value); - double flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR; - const float brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2); - const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end(); - - ExPolygons brim_area_object; - ExPolygons no_brim_area_object; - ExPolygons brim_area_support; - ExPolygons no_brim_area_support; - Polygons holes_object; - Polygons holes_support; - if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) { - for (const ExPolygon& ex_poly : object->layers().front()->lslices) { - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) { - if (top_outer_brim) - no_brim_area_object.emplace_back(ex_poly); - else - append(brim_area_object, diff_ex(offset_ex(ex_poly.contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION), offset_ex(ex_poly.contour, brim_offset))); - } - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btOuterAndInner) - append(brim_area_object, diff_ex(offset_ex(ex_poly.holes, -brim_offset), offset_ex(ex_poly.holes, -brim_width - brim_offset))); - if (brim_type == BrimType::btInnerOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly.holes)); - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btNoBrim) - append(no_brim_area_object, offset_ex(ex_poly.holes, -no_brim_offset)); - append(holes_object, ex_poly.holes); - } - append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset)); - brimToWrite.at(object->id()).obj = false; - for (const PrintInstance& instance : object->instances()) { - if (!brim_area_object.empty()) - append_and_translate(brim_area, brim_area_object, instance, print, innerBrimAreaMap); - append_and_translate(no_brim_area, no_brim_area_object, instance); - append_and_translate(holes, holes_object, instance); - } - if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end()) - expolygons_append(brim_area, innerBrimAreaMap[object->id()]); - } - if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) { - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner || brim_type == BrimType::btAutoBrim) { - if (!top_outer_brim) - append(brim_area_support, diff_ex(offset_ex(support_contour, brim_width + brim_offset, jtRound, SCALED_RESOLUTION), offset_ex(support_contour, brim_offset))); - } - if (brim_type != BrimType::btNoBrim) - append(no_brim_area_support, offset_ex(support_contour, 0)); - no_brim_area_support.emplace_back(support_contour); - } - } - } - brimToWrite.at(object->id()).sup = false; - for (const PrintInstance& instance : object->instances()) { - if (!brim_area_support.empty()) - append_and_translate(brim_area, brim_area_support, instance, print, innerSupportBrimAreaMap); - append_and_translate(no_brim_area, no_brim_area_support, instance); - append_and_translate(holes, holes_support, instance); - } - if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) - expolygons_append(brim_area, innerSupportBrimAreaMap[object->id()]); - } - } - for (const PrintObject* object : print.objects()) { - if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end()) { - innerBrimAreaMap[object->id()] = intersection_ex(to_polygons(innerBrimAreaMap[object->id()]), holes); - append(brimAreaMap[object->id()], innerBrimAreaMap[object->id()]); - } - if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) { - innerSupportBrimAreaMap[object->id()] = intersection_ex(to_polygons(innerSupportBrimAreaMap[object->id()]), holes); - append(supportBrimAreaMap[object->id()], innerSupportBrimAreaMap[object->id()]); - } - } - for (const PrintObject* object : print.objects()) { - if (brimAreaMap.find(object->id()) != brimAreaMap.end()) - brimAreaMap[object->id()] = diff_ex(brimAreaMap[object->id()], no_brim_area); - if (supportBrimAreaMap.find(object->id()) != supportBrimAreaMap.end()) - supportBrimAreaMap[object->id()] = diff_ex(supportBrimAreaMap[object->id()], no_brim_area); - } - brim_area = intersection_ex(to_polygons(brim_area), holes); - append(no_brim_area, brim_area); - return no_brim_area; -} - -//BBS maximum temperature difference from print object class -double getTemperatureFromExtruder(const PrintObject* printObject) { - auto print = printObject->print(); - std::vector extrudersFirstLayer; - auto firstLayerRegions = printObject->layers().front()->regions(); - if (!firstLayerRegions.empty()) { - for (const LayerRegion* regionPtr : firstLayerRegions) { - if (regionPtr->has_extrusions()) - extrudersFirstLayer.push_back(regionPtr->region().extruder(frExternalPerimeter)); - } - } - - const PrintConfig& config = print->config(); - int curr_bed_type = config.option("curr_bed_type")->getInt(); - const ConfigOptionInts* bed_temp_1st_layer_opt = config.option(get_bed_temp_1st_layer_key((BedType)curr_bed_type)); - - double maxDeltaTemp = 0; - for (auto extruderID : extrudersFirstLayer) { - int bedTemp = bed_temp_1st_layer_opt->get_at(extruderID - 1); - if (bedTemp > maxDeltaTemp) - maxDeltaTemp = bedTemp; - } - - return maxDeltaTemp; -} //BBS adhesion coefficients from print object class double getadhesionCoeff(const PrintObject* printObject) { @@ -711,50 +256,6 @@ bool compSecondMoment(const ExPolygons& expolys, double& smExpolysX, double& smE return true; } - - - -//BBS: config brimwidth by volumes -double configBrimWidthByVolumes(double deltaT, double adhesion, double maxSpeed, const ModelVolume* modelVolumePtr, const ExPolygons& expolys) -{ - // height of a volume - double height = 0; - if (modelVolumePtr->is_model_part()) { - auto rawBoundingbox = modelVolumePtr->mesh().transformed_bounding_box(modelVolumePtr->get_matrix()); - auto bbox = modelVolumePtr->get_object()->instances.front()->transform_bounding_box(rawBoundingbox); - auto bbox_size = bbox.size(); - height = bbox_size(2); - } - - // sencond moment of the expolygons of the first layer of the volume - double Ixx = -1.e30, Iyy = -1.e30; - if (!expolys.empty()) { - if (!compSecondMoment(expolys, Ixx, Iyy)) - Ixx = Iyy = -1.e30; - } - Ixx = Ixx * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR; - Iyy = Iyy * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR * SCALING_FACTOR; - - // bounding box of the expolygons of the first layer of the volume - BoundingBox bbox2; - for (const auto& expoly : expolys) - bbox2.merge(get_extents(expoly.contour)); - const double& bboxX = bbox2.size()(0); - const double& bboxY = bbox2.size()(1); - double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR; - double thermalLengthRef = Model::getThermalLength(modelVolumePtr); - - double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR)); - double brim_width = adhesion * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength); - // small brims are omitted - if (brim_width < 5 && brim_width < 1.5 * thermalLength) - brim_width = 0; - // large brims are omitted - if (brim_width > 18) brim_width = 18.; - - return brim_width; -} - //BBS: config brimwidth by group of volumes double configBrimWidthByVolumeGroups(double adhesion, double maxSpeed, const std::vector modelVolumePtrs, const ExPolygons& expolys, double &groupHeight) { @@ -857,6 +358,14 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi if (brim_ear_points.size() <= 0) { return mouse_ears_ex; } + //ORCA: Painted ears can snap to the EFC-adjusted outline when enabled. + const bool use_efc_outline = use_brim_efc_outline(*object); + const ExPolygons &raw_outline = object->layers().front()->lslices; + //ORCA: Lazily computed EFC-adjusted bottom outline. + //Stored separately so we can avoid recomputation unless EFC snapping is used. + ExPolygons efc_outline_storage; + const ExPolygons* efc_outline = nullptr; + const Geometry::Transformation& trsf = object->model_object()->instances[0]->get_transformation(); Transform3d model_trsf = trsf.get_matrix_no_offset(); const Point ¢er_offset = object->center_offset(); @@ -880,6 +389,29 @@ static ExPolygons make_brim_ears(const PrintObject* object, const double& flowWi Vec3f pos = pt.transform(model_trsf); int32_t pt_x = scale_(pos.x()); int32_t pt_y = scale_(pos.y()); + + //ORCA: Snap painted ears to the EFC-adjusted outline when enabled. + if (use_efc_outline) { + if (efc_outline == nullptr) { + //ORCA: Compute EFC-adjusted outline lazily for painted ear snapping. + efc_outline_storage = get_print_object_bottom_layer_expolygons(*object); + efc_outline = &efc_outline_storage; + } + + if (!efc_outline->empty()) { + Point closest_point; + //ORCA: Snap within the matching island to avoid drifting to another island. + if (closest_point_on_matching_island( + raw_outline, + *efc_outline, + Point(pt_x, pt_y), + closest_point)) { + pt_x = closest_point.x(); + pt_y = closest_point.y(); + } + } + } + mouse_ears_ex.back().contour.translate(Point(pt_x, pt_y)); } return mouse_ears_ex; @@ -926,6 +458,14 @@ static ExPolygons outer_inner_brim_area(const Print& print, const bool has_outer_brim = brim_type == btOuterOnly || brim_type == btOuterAndInner || brim_type == btAutoBrim || use_auto_brim_ears || use_brim_ears; coord_t ear_detection_length = scale_(object->config().brim_ears_detection_length.value); coordf_t brim_ears_max_angle = object->config().brim_ears_max_angle.value; + //ORCA: Select brim base slices from EFC-compensated outline when enabled. + const bool use_efc_outline = use_brim_efc_outline(*object); + ExPolygons brim_slices_storage; + const ExPolygons* brim_slices = nullptr; + //ORCA: Select EFC-adjusted bottom outline when enabled. + if (use_efc_outline) + brim_slices_storage = get_print_object_bottom_layer_expolygons(*object); + brim_slices = use_efc_outline ? &brim_slices_storage : &object->layers().front()->lslices; ExPolygons brim_area_object; ExPolygons no_brim_area_object; @@ -961,64 +501,72 @@ static ExPolygons outer_inner_brim_area(const Print& print, double brimWidthRaw = configBrimWidthByVolumeGroups(adhesion, maxSpeed, groupVolumePtrs, volumeGroup.slices, groupHeight); brim_width = scale_(floor(brimWidthRaw / flowWidth / 2) * flowWidth * 2); } - for (const ExPolygon& ex_poly : volumeGroup.slices) { - // BBS: additional brim width will be added if part's adhesion area is too small and brim is not generated - float brim_width_mod; - if (brim_width < scale_(5.) && has_brim_auto && groupHeight > 10.) { - brim_width_mod = ex_poly.area() / ex_poly.contour.length() < scaled_half_min_adh_length - && brim_width < scaled_flow_width ? brim_width + scaled_additional_brim_width : brim_width; - } - else { - brim_width_mod = brim_width; - } - //BBS: brim width should be limited to the 1.5*boundingboxSize of a single polygon. - if (has_brim_auto) { - BoundingBox bbox2 = ex_poly.contour.bounding_box(); - brim_width_mod = std::min(brim_width_mod, float(std::max(bbox2.size()(0), bbox2.size()(1)))); - } - brim_width_mod = floor(brim_width_mod / scaled_flow_width / 2) * scaled_flow_width * 2; - - Polygons ex_poly_holes_reversed = ex_poly.holes; - polygons_reverse(ex_poly_holes_reversed); - - if (has_outer_brim) { - // BBS: inner and outer boundary are offset from the same polygon incase of round off error. - auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION); - ExPolygons outerExpoly; - if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true); - //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); - } else if (use_auto_brim_ears) { - coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing()); - outerExpoly = make_brim_ears_auto(innerExpoly, size_ear, ear_detection_length, brim_ears_max_angle, true); - }else { - outerExpoly = offset_ex(innerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); - } - append(brim_area_object, diff_ex(outerExpoly, innerExpoly)); - } - if (has_inner_brim) { - ExPolygons outerExpoly; - auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset); - if (use_brim_ears) { - outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false); - } else if (use_auto_brim_ears) { - coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); - outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false); - }else { - outerExpoly = offset_ex(ex_poly_holes_reversed, -brim_offset); - } - append(brim_area_object, intersection_ex(diff_ex(outerExpoly, innerExpoly), ex_poly_holes_reversed)); - } - if (!has_inner_brim) { - // BBS: brim should be apart from holes - append(no_brim_area_object, diff_ex(ex_poly_holes_reversed, offset_ex(ex_poly_holes_reversed, -no_brim_offset))); - } - if (!has_outer_brim) - append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly_holes_reversed)); - append(holes_object, ex_poly_holes_reversed); + ExPolygons volume_group_slices_efc; + const ExPolygons* volume_group_slices = &volumeGroup.slices; + if (use_efc_outline) { + //ORCA: When using EFC outline, restrict per-volume-group slices to the + // EFC-adjusted bottom footprint to keep brim width heuristics consistent. + volume_group_slices_efc = intersection_ex(*brim_slices, volumeGroup.slices); + volume_group_slices = &volume_group_slices_efc; } - } - auto objectIsland = offset_ex(object->layers().front()->lslices, brim_offset, jtRound, SCALED_RESOLUTION); + for (const ExPolygon& ex_poly : *volume_group_slices) { + // BBS: additional brim width will be added if part's adhesion area is too small and brim is not generated + float brim_width_mod; + if (brim_width < scale_(5.) && has_brim_auto && groupHeight > 10.) { + brim_width_mod = ex_poly.area() / ex_poly.contour.length() < scaled_half_min_adh_length + && brim_width < scaled_flow_width ? brim_width + scaled_additional_brim_width : brim_width; + } + else { + brim_width_mod = brim_width; + } + //BBS: brim width should be limited to the 1.5*boundingboxSize of a single polygon. + if (has_brim_auto) { + BoundingBox bbox2 = ex_poly.contour.bounding_box(); + brim_width_mod = std::min(brim_width_mod, float(std::max(bbox2.size()(0), bbox2.size()(1)))); + } + brim_width_mod = floor(brim_width_mod / scaled_flow_width / 2) * scaled_flow_width * 2; + + Polygons ex_poly_holes_reversed = ex_poly.holes; + polygons_reverse(ex_poly_holes_reversed); + + if (has_outer_brim) { + // BBS: inner and outer boundary are offset from the same polygon incase of round off error. + auto innerExpoly = offset_ex(ex_poly.contour, brim_offset, jtRound, SCALED_RESOLUTION); + ExPolygons outerExpoly; + if (use_brim_ears) { + outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, true); + //outerExpoly = offset_ex(outerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); + } else if (use_auto_brim_ears) { + coord_t size_ear = (brim_width_mod - brim_offset - flow.scaled_spacing()); + outerExpoly = make_brim_ears_auto(innerExpoly, size_ear, ear_detection_length, brim_ears_max_angle, true); + }else { + outerExpoly = offset_ex(innerExpoly, brim_width_mod, jtRound, SCALED_RESOLUTION); + } + append(brim_area_object, diff_ex(outerExpoly, innerExpoly)); + } + if (has_inner_brim) { + ExPolygons outerExpoly; + auto innerExpoly = offset_ex(ex_poly_holes_reversed, -brim_width - brim_offset); + if (use_brim_ears) { + outerExpoly = make_brim_ears(object, flowWidth, brim_offset, flow, false); + } else if (use_auto_brim_ears) { + coord_t size_ear = (brim_width - brim_offset - flow.scaled_spacing()); + outerExpoly = make_brim_ears_auto(offset_ex(ex_poly_holes_reversed, -brim_offset), size_ear, ear_detection_length, brim_ears_max_angle, false); + }else { + outerExpoly = offset_ex(ex_poly_holes_reversed, -brim_offset); + } + append(brim_area_object, intersection_ex(diff_ex(outerExpoly, innerExpoly), ex_poly_holes_reversed)); + } + if (!has_inner_brim) { + // BBS: brim should be apart from holes + append(no_brim_area_object, diff_ex(ex_poly_holes_reversed, offset_ex(ex_poly_holes_reversed, -no_brim_offset))); + } + if (!has_outer_brim) + append(no_brim_area_object, diff_ex(offset(ex_poly.contour, no_brim_offset), ex_poly_holes_reversed)); + append(holes_object, ex_poly_holes_reversed); + } + } + auto objectIsland = offset_ex(*brim_slices, brim_offset, jtRound, SCALED_RESOLUTION); append(no_brim_area_object, objectIsland); brimToWrite.at(object->id()).obj = false; @@ -1261,393 +809,8 @@ static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_ return std::move(polylines); } - -// BBS: this function is used to generate brim for inner island inside holes -// Collect island + brim area to be minused when generating inner brim for holes -static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, - ExtrusionEntityCollection &brim, ExPolygons &islands_area_ex) -{ - const auto scaled_resolution = scaled(print.config().resolution.value); - - auto save_polygon_if_is_inner_island = [scaled_resolution](const Polygons& holes_area, Polygon& contour, std::map& hole_island_pair) { - for (size_t i = 0; i < holes_area.size(); i++) { - Polygons contour_polys; - contour_polys.push_back(contour); - if (diff_ex(contour_polys, { holes_area[i] }).empty()) { - // BBS: this is an inner island inside holes_area[i], save - contour.douglas_peucker(scaled_resolution); - hole_island_pair[i].push_back(contour); - break; - } - } - }; - - Flow flow = print.brim_flow(); - for (const PrintObject* object : top_level_objects_with_brim) { - const BrimType brim_type = object->config().brim_type.value; - // BBS: don't need to handle this object if hasn't enabled outer_brim - if (brim_type == BrimType::btNoBrim) - continue; - - //BBS: 1 collect holes area which is used to limit the brim of inner island - Polygons holes_area; - for (const ExPolygon& ex_poly : object->layers().front()->lslices) - polygons_append(holes_area, ex_poly.holes); - - - //BBS: 2 get the island polygons inside holes, saved as map - std::map hole_island_pair; - for (const ExPolygon& ex_poly : object->layers().front()->lslices) { - Polygon counter = ex_poly.contour; - save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair); - } - - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - Polygon counter = support_contour; - save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair); - } - } - - //BBS: 3 generate loops, only save part of loop which inside hole - const float brim_offset = scale_(object->config().brim_object_gap.value); - const float brim_width = scale_(object->config().brim_width.value); - if (brim_type == BrimType::btInnerOnly) { - // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island. - // Only update islands_area_ex and return - for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) { - ExPolygons islands_area_ex_object = intersection_ex(offset(it->second, brim_offset), offset(holes_area[it->first], -brim_offset)); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_object, instance); - } - } - else { - size_t num_loops = size_t(floor(brim_width / float(flow.scaled_spacing()))); - for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) { - Polygons loops; - Polygons inner_islands = offset(it->second, brim_offset); - Polygons brimable_area = offset(holes_area[it->first], -brim_offset); //offset to keep away from hole - Polygons contour = inner_islands; - for (size_t i = 0; i < num_loops; ++i) { - contour = offset(contour, float(flow.scaled_spacing()), jtSquare); - for (Polygon& poly : contour) - poly.douglas_peucker(scaled_resolution); - polygons_append(loops, offset(contour, -0.5f * float(flow.scaled_spacing()))); - } - // BBS: to be checked. - //loops = union_pt_chained_outside_in(loops, false); - loops = union_pt_chained_outside_in(loops); - - std::vector loops_pl_by_levels; - { - Polylines loops_pl = to_polylines(loops); - loops_pl_by_levels.assign(loops_pl.size(), Polylines()); - tbb::parallel_for(tbb::blocked_range(0, loops_pl.size()), - [&loops_pl_by_levels, &loops_pl, &brimable_area](const tbb::blocked_range& range) { - for (size_t i = range.begin(); i < range.end(); ++i) { - loops_pl_by_levels[i] = chain_polylines(intersection_pl({ std::move(loops_pl[i]) }, brimable_area)); - } - }); - } - - // BBS: Reduce down to the ordered list of polylines. - Polylines all_loops_object; - for (Polylines& polylines : loops_pl_by_levels) - append(all_loops_object, std::move(polylines)); - loops_pl_by_levels.clear(); - - optimize_polylines_by_reversing(&all_loops_object); - all_loops_object = connect_brim_lines(std::move(all_loops_object), offset(inner_islands, float(SCALED_EPSILON)), float(flow.scaled_spacing()) * 2.f); - - Polylines final_loops; - for (const PrintInstance& instance : object->instances()) { - size_t dst_idx = final_loops.size(); - final_loops.insert(final_loops.end(), all_loops_object.begin(), all_loops_object.end()); - Point instance_shift = instance.shift_without_plate_offset(); - for (; dst_idx < final_loops.size(); ++dst_idx) - final_loops[dst_idx].translate(instance_shift); - - } - extrusion_entities_append_loops_and_paths(brim.entities, std::move(final_loops), - erBrim, float(flow.mm3_per_mm()), float(flow.width()), - float(print.skirt_first_layer_height())); - - //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes - //Inner brim of holes must not occupy this area - ExPolygons islands_area_ex_object = intersection_ex(contour, brimable_area); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_object, instance); - } - } - } -} - -//BBS: the brim are generated one by one, and sorted by objs/supports and extruders -static void make_inner_island_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, - std::map& innerbrimAreaMap, - std::map& innerSupportBrimAreaMap, - ExPolygons& islands_area_ex, ExPolygons& NobrimArea, - std::vector>& objPrintVec) -{ - auto save_polygon_if_is_inner_island = [](const Polygons& holes_area, Polygon& counter, std::map& hole_island_pair) { - for (size_t i = 0; i < holes_area.size(); i++) { - if (diff_ex(Polygons{ counter }, { holes_area[i] }).empty()) { - // BBS: this is an inner island inside holes_area[i], save - counter.douglas_peucker(SCALED_RESOLUTION); - hole_island_pair[i].push_back(counter); - break; - } - } - }; - - unsigned int support_material_extruder = 1; - if (print.has_support_material()) { - assert(top_level_objects_with_brim.front()->config().support_filament >= 0); - if (top_level_objects_with_brim.front()->config().support_filament > 0) - support_material_extruder = top_level_objects_with_brim.front()->config().support_filament; - } - - std::unordered_set top_level_objects_idx; - top_level_objects_idx.reserve(top_level_objects_with_brim.size()); - for (const PrintObject* object : top_level_objects_with_brim) - top_level_objects_idx.insert(object->id().id); - - struct brimWritten { - bool obj; - bool sup; - }; - std::map brimToWrite; - for (const auto& objectWithExtruder : objPrintVec) - if (top_level_objects_idx.find(objectWithExtruder.first.id) != top_level_objects_idx.end()) - brimToWrite.insert({ objectWithExtruder.first, {true,true} }); - - Flow flow = print.brim_flow(); - for (unsigned int extruderNo : print.extruders()) { - ++extruderNo; - for (const auto& objectWithExtruder : objPrintVec) { - if (top_level_objects_idx.find(objectWithExtruder.first.id) != top_level_objects_idx.end()) { - const PrintObject* object = print.get_object(objectWithExtruder.first); - const BrimType brim_type = object->config().brim_type.value; - // BBS: don't need to handle this object if hasn't enabled outer_brim - if (brim_type == BrimType::btNoBrim) - continue; - - //BBS: 1 collect holes area which is used to limit the brim of inner island - Polygons holes_area; - for (const ExPolygon& ex_poly : object->layers().front()->lslices) - polygons_append(holes_area, ex_poly.holes); - - - //BBS: 2 get the island polygons inside holes, saved as map - std::map hole_island_pair; - for (const ExPolygon& ex_poly : object->layers().front()->lslices) { - Polygon counter = ex_poly.contour; - save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair); - } - std::map hole_island_pair_supports; - if (!object->support_layers().empty()) { - for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { - Polygon counter = support_contour; - save_polygon_if_is_inner_island(holes_area, counter, hole_island_pair_supports); - } - } - - //BBS: 3 generate loops, only save part of loop which inside hole - const float brim_offset = scale_(object->config().brim_object_gap.value); - const float brim_width = floor(scale_(object->config().brim_width.value) / 2 / flow.scaled_spacing()) * 2 * flow.scaled_spacing(); - if (objectWithExtruder.second == extruderNo && brimToWrite.at(object->id()).obj) { - if (brim_type == BrimType::btInnerOnly) { - // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island. - // Only update islands_area_ex and return - for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) { - ExPolygons islands_area_ex_object = intersection_ex(offset(it->second, brim_offset), offset(holes_area[it->first], -brim_offset)); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_object, instance); - } - brimToWrite.at(object->id()).obj = false; - } - else { - for (auto it = hole_island_pair.begin(); it != hole_island_pair.end(); it++) { - Polygons loops; - Polygons inner_islands = offset(it->second, brim_offset); - Polygons brimable_area = offset(holes_area[it->first], -brim_offset); //offset to keep away from hole - Polygons contour = offset(inner_islands, brim_offset + brim_width, jtRound, SCALED_RESOLUTION); - for (Polygon& poly : contour) - poly.douglas_peucker(SCALED_RESOLUTION); - - - //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes - //Inner brim of holes must not occupy this area - ExPolygons islands_area_ex_object = intersection_ex(contour, brimable_area); - ExPolygons inner_islands_exp = offset_ex(inner_islands, 0.); - islands_area_ex_object = diff_ex(islands_area_ex_object, inner_islands_exp); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_object, instance, print, innerbrimAreaMap); - } - brimToWrite.at(object->id()).obj = false; - } - if (innerbrimAreaMap.find(object->id()) != innerbrimAreaMap.end()) - expolygons_append(islands_area_ex, innerbrimAreaMap[object->id()]); - } - - - if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) { - if (brim_type == BrimType::btInnerOnly) { - // If brim_type is btInnerOnly, we actually doesn't generate loops for inner island. - // Only update islands_area_ex and return - for (auto it = hole_island_pair_supports.begin(); it != hole_island_pair_supports.end(); it++) { - ExPolygons islands_area_ex_support = intersection_ex(offset(it->second, 0), offset(holes_area[it->first], 0)); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_support, instance); - } - brimToWrite.at(object->id()).sup = false; - } - else { - for (auto it = hole_island_pair_supports.begin(); it != hole_island_pair_supports.end(); it++) { - Polygons loops; - Polygons inner_islands = offset(it->second, 0); - Polygons brimable_area = offset(holes_area[it->first], -float(flow.scaled_spacing())); //offset to keep away from hole - Polygons contour = offset(inner_islands, brim_width, jtRound, SCALED_RESOLUTION); - for (Polygon& poly : contour) - poly.douglas_peucker(SCALED_RESOLUTION); - - - //BBS: save all inner island and inner island brim area here, which is necesary if generate inner brim for holes - //Inner brim of holes must not occupy this area - ExPolygons islands_area_ex_support = intersection_ex(contour, brimable_area); - ExPolygons inner_islands_exp = offset_ex(inner_islands, 0.); - islands_area_ex_support = diff_ex(islands_area_ex_support, inner_islands_exp); - for (const PrintInstance& instance : object->instances()) - append_and_translate(islands_area_ex, islands_area_ex_support, instance, print, innerSupportBrimAreaMap); - - } - brimToWrite.at(object->id()).sup = false; - } - if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) - expolygons_append(islands_area_ex, innerSupportBrimAreaMap[object->id()]); - } - } - } - } - islands_area_ex = diff_ex(islands_area_ex, NobrimArea); - for (const PrintObject* object : print.objects()) { - if (innerbrimAreaMap.find(object->id()) != innerbrimAreaMap.end()) - innerbrimAreaMap[object->id()] = diff_ex(innerbrimAreaMap[object->id()], NobrimArea); - if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) - innerSupportBrimAreaMap[object->id()] = diff_ex(innerSupportBrimAreaMap[object->id()], NobrimArea); - } -} -static void make_inner_brim(const Print &print, - const ConstPrintObjectPtrs &top_level_objects_with_brim, - const std::vector &bottom_layers_expolygons, - ExtrusionEntityCollection &brim) -{ - assert(print.objects().size() == bottom_layers_expolygons.size()); - const auto scaled_resolution = scaled(print.config().resolution.value); - - //BBS: generate brim for inner island first - ExPolygons inner_islands_ex; - make_inner_island_brim(print, top_level_objects_with_brim, brim, inner_islands_ex); - -#ifdef INNER_ISLAND_BRIM_DEBUG_TO_SVG - static int irun = 0; - BoundingBox bbox_svg; - bbox_svg.merge(get_extents(inner_islands_ex)); - { - std::stringstream stri; - stri << "inner_island_and_brim_area_" << irun << ".svg"; - SVG svg(stri.str(), bbox_svg); - svg.draw(to_polylines(inner_islands_ex), "blue"); - svg.Close(); - } - ++ irun; -#endif - - Flow flow = print.brim_flow(); - ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing())); - //BBS: brim of hole must not overlap with inner island and inner island brim - if (!inner_islands_ex.empty()) { - islands_ex = diff_ex(islands_ex, inner_islands_ex); - } - - Polygons loops; - islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()));// jtSquare seems not working when expandign the holes - for (size_t i = 0; !islands_ex.empty(); ++i) { - for (ExPolygon &poly_ex : islands_ex) - poly_ex.douglas_peucker(scaled_resolution); - polygons_append(loops, to_polygons(islands_ex));// jtSquare seems not working when expandign the holes - islands_ex = offset_ex(islands_ex, -1.3f * float(flow.scaled_spacing())); - islands_ex = offset_ex(islands_ex, .3f * float(flow.scaled_spacing())); - } - - loops = union_pt_chained_outside_in(loops); - std::reverse(loops.begin(), loops.end()); - extrusion_entities_append_loops(brim.entities, std::move(loops), erBrim, float(flow.mm3_per_mm()), - float(flow.width()), float(print.skirt_first_layer_height())); -} - -// BBS: generate inner brim by objs -static void make_inner_brim(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, - std::map& brimAreaMap, std::map& supportBrimAreaMap, - std::vector>& objPrintVec) -{ - //BBS: generate brim for inner island first - - -#ifdef INNER_ISLAND_BRIM_DEBUG_TO_SVG - static int irun = 0; - BoundingBox bbox_svg; - bbox_svg.merge(get_extents(inner_islands_ex)); - { - std::stringstream stri; - stri << "inner_island_and_brim_area_" << irun << ".svg"; - SVG svg(stri.str(), bbox_svg); - svg.draw(to_polylines(inner_islands_ex), "blue"); - svg.Close(); - } - ++irun; -#endif - - Flow flow = print.brim_flow(); - ExPolygons NoBrim = inner_brim_area(print, top_level_objects_with_brim, - float(flow.scaled_spacing()), brimAreaMap, supportBrimAreaMap, objPrintVec); - - ExPolygons inner_islands_ex; - std::map innerBrimAreaMap; - std::map innerSupportBrimAreaMap; - /*make_inner_island_brim(print, top_level_objects_with_brim, innerBrimAreaMap, innerSupportBrimAreaMap, - inner_islands_ex, NoBrim, objPrintVec);*/ - - //BBS: brim of hole must not overlap with inner island and inner island brim - if (!inner_islands_ex.empty()) { - if (brimAreaMap.size() > 0) { - for (auto iter = brimAreaMap.begin(); iter != brimAreaMap.end(); ++iter) { - if (!iter->second.empty()) { - iter->second = diff_ex(iter->second, inner_islands_ex); - }; - } - } - if (supportBrimAreaMap.size() > 0) { - for (auto iter = supportBrimAreaMap.begin(); iter != supportBrimAreaMap.end(); ++iter) { - if (!iter->second.empty()) { - iter->second = diff_ex(iter->second, inner_islands_ex); - }; - } - } - for (const PrintObject* object : print.objects()) { - if (innerBrimAreaMap.find(object->id()) != innerBrimAreaMap.end()) { - append(brimAreaMap[object->id()], innerBrimAreaMap[object->id()]); - } - if (innerSupportBrimAreaMap.find(object->id()) != innerSupportBrimAreaMap.end()) { - append(supportBrimAreaMap[object->id()], innerSupportBrimAreaMap[object->id()]); - } - } - } -} - - //BBS: generate out brim by offseting ExPolygons 'islands_area_ex' -Polygons tryExPolygonOffset(const ExPolygons islandAreaEx, const Print& print) +Polygons tryExPolygonOffset(const ExPolygons& islandAreaEx, const Print& print) { const auto scaled_resolution = scaled(print.config().resolution.value); Polygons loops; @@ -1718,8 +881,6 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_ std::vector> &objPrintVec, std::vector& printExtruders) { - - double brim_width_max = 0; std::map brim_width_map; std::map brimAreaMap; std::map supportBrimAreaMap; @@ -1732,7 +893,10 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_ for (const ObjectID printObjID : print.print_object_ids()) { BoundingBox bbx; PrintObject* object = const_cast(print.get_object(printObjID)); - for (const ExPolygon& ex_poly : object->layers().front()->lslices) + //ORCA: Use EFC-compensated outline for brim bounding box when enabled. + const ExPolygons brim_slices = use_brim_efc_outline(*object) ? + get_print_object_bottom_layer_expolygons(*object) : object->layers().front()->lslices; + for (const ExPolygon& ex_poly : brim_slices) for (const PrintInstance& instance : object->instances()) { auto ex_poly_translated = ex_poly; ex_poly_translated.translate(instance.shift_without_plate_offset()); @@ -1774,9 +938,6 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_ supportBrimMap.insert(std::make_pair(iter->first, makeBrimInfill(iter->second, print, islands_area))); }; } - - size_t num_loops = size_t(floor(brim_width_max / flow.spacing())); - BOOST_LOG_TRIVIAL(debug) << "brim_width_max, num_loops: " << brim_width_max << ", " << num_loops; } } // namespace Slic3r diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 3ca75d28f3..4e78b31b46 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -904,7 +904,7 @@ static std::vector s_Preset_print_options { "top_surface_speed", "support_speed", "support_object_xy_distance", "support_object_first_layer_gap", "support_interface_speed", "bridge_speed", "internal_bridge_speed", "gap_infill_speed", "travel_speed", "travel_speed_z", "initial_layer_speed", "outer_wall_acceleration", "initial_layer_acceleration", "top_surface_acceleration", "default_acceleration", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_height","single_loop_draft_shield", "draft_shield", - "brim_width", "brim_object_gap", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", + "brim_width", "brim_object_gap", "brim_use_efc_outline", "brim_type", "brim_ears_max_angle", "brim_ears_detection_length", "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap","enforce_support_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style", // BBS diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 37fc895411..054a57f797 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1562,6 +1562,16 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.)); + def = this->add("brim_use_efc_outline", coBool); + def->label = L("Brim follows compensated outline"); + def->category = L("Support"); + def->tooltip = L("When enabled, the brim is aligned with the first-layer perimeter geometry after Elephant Foot Compensation is applied.\n" + "This option is intended for cases where Elephant Foot Compensation significantly alters the first-layer footprint.\n" + "\n" + "If your current setup already works well, enabling it may be unnecessary and can cause the brim to fuse with upper layers." ); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("brim_ears", coBool); def->label = L("Brim ears"); def->category = L("Support"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3e34a8362b..1dac4b7057 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -874,6 +874,7 @@ PRINT_CONFIG_CLASS_DEFINE( PrintObjectConfig, ((ConfigOptionFloat, brim_object_gap)) + ((ConfigOptionBool, brim_use_efc_outline)) ((ConfigOptionEnum, brim_type)) ((ConfigOptionFloat, brim_width)) ((ConfigOptionFloat, brim_ears_detection_length)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7cc98209cf..4b4237dca1 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1006,6 +1006,7 @@ bool PrintObject::invalidate_state_by_config_options( for (const t_config_option_key &opt_key : opt_keys) { if ( opt_key == "brim_width" || opt_key == "brim_object_gap" + || opt_key == "brim_use_efc_outline" || opt_key == "brim_type" || opt_key == "brim_ears_max_angle" || opt_key == "brim_ears_detection_length" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 6c5fa69534..90944e673e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -705,6 +705,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_brim = (config->opt_enum("brim_type") != btNoBrim); toggle_field("brim_object_gap", have_brim); + toggle_field("brim_use_efc_outline", have_brim); bool have_brim_width = (config->opt_enum("brim_type") != btNoBrim) && config->opt_enum("brim_type") != btAutoBrim && config->opt_enum("brim_type") != btPainted; toggle_field("brim_width", have_brim_width); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index e7520b5b51..44dd7b8f6e 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -87,14 +87,14 @@ std::map> SettingsFactory::OBJECT_C {"precise_z_height", "",10} }}, - { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3}, - {"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6}, {"support_threshold_overlap", "",6}, {"support_on_build_plate_only", "",7}, - {"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24},{"support_style", "",25}, - {"tree_support_brim_width", "",26}, {"tree_support_branch_angle", "",10},{"tree_support_branch_angle_organic","",10}, {"tree_support_wall_count", "",11},{"tree_support_branch_diameter_angle", "",11},//tree support - {"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15}, - {"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19}, - {"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23},{"support_remove_small_overhang","",27}, - {"support_object_first_layer_gap","",28} + { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3},{"brim_use_efc_outline", "",4}, + {"enable_support", "",5},{"support_type", "",6},{"support_threshold_angle", "",7}, {"support_threshold_overlap", "",8}, {"support_on_build_plate_only", "",9}, + {"support_filament", "",10},{"support_interface_filament", "",11},{"support_expansion", "",12},{"support_style", "",13}, + {"tree_support_brim_width", "",14}, {"tree_support_branch_angle", "",15},{"tree_support_branch_angle_organic","",16}, {"tree_support_wall_count", "",17},{"tree_support_branch_diameter_angle", "",18},//tree support + {"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22}, + {"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26}, + {"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31}, + {"support_object_first_layer_gap","",32} }}, { L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13} }} diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cc67ee11fd..059955a7cc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4670,7 +4670,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "nozzle_height", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle", - "brim_width", "brim_object_gap", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation", + "brim_width", "brim_object_gap", "brim_use_efc_outline", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation", "enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_tower_enable_framework", "prime_tower_infill_gap", "prime_volume", "extruder_colour", "filament_colour", "filament_type", "material_colour", "printable_height", "extruder_printable_height", "printer_model", "printer_technology", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fd8ede92d2..d4d31a3573 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2663,6 +2663,7 @@ void TabPrint::build() optgroup->append_single_option_line("brim_type", "others_settings_brim#type"); optgroup->append_single_option_line("brim_width", "others_settings_brim#width"); optgroup->append_single_option_line("brim_object_gap", "others_settings_brim#brim-object-gap"); + optgroup->append_single_option_line("brim_use_efc_outline", "others_settings_brim#brim-use-efc-outline"); optgroup->append_single_option_line("brim_ears_max_angle", "others_settings_brim#ear-max-angle"); optgroup->append_single_option_line("brim_ears_detection_length", "others_settings_brim#ear-detection-radius");