FuzzySkin hole + Fix: Painted artifacts and with Sacrificial layer issues (#12479)

This commit is contained in:
Ian Bassi
2026-05-08 19:22:49 +08:00
committed by GitHub
parent 8876c0b0df
commit c9413bb4ef
27 changed files with 242 additions and 44 deletions
+3
View File
@@ -13121,6 +13121,9 @@ msgstr ""
msgid "Contour" msgid "Contour"
msgstr "" msgstr ""
msgid "Hole"
msgstr ""
msgid "Contour and hole" msgid "Contour and hole"
msgstr "" msgstr ""
+3
View File
@@ -15232,6 +15232,9 @@ msgstr "Només pintat"
msgid "Contour" msgid "Contour"
msgstr "Contorn" msgstr "Contorn"
msgid "Hole"
msgstr "Forat"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contorn i forat" msgstr "Contorn i forat"
+3
View File
@@ -14821,6 +14821,9 @@ msgstr "Painted only"
msgid "Contour" msgid "Contour"
msgstr "Obrys" msgstr "Obrys"
msgid "Hole"
msgstr "Otvor"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Obrys a otvor" msgstr "Obrys a otvor"
+3
View File
@@ -15357,6 +15357,9 @@ msgstr "Nur lackiert"
msgid "Contour" msgid "Contour"
msgstr "Kontur" msgstr "Kontur"
msgid "Hole"
msgstr "Loch"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontur und Loch" msgstr "Kontur und Loch"
+3
View File
@@ -13403,6 +13403,9 @@ msgstr ""
msgid "Contour" msgid "Contour"
msgstr "" msgstr ""
msgid "Hole"
msgstr ""
msgid "Contour and hole" msgid "Contour and hole"
msgstr "" msgstr ""
+3
View File
@@ -15294,6 +15294,9 @@ msgstr "Solo pintado"
msgid "Contour" msgid "Contour"
msgstr "Contorno" msgstr "Contorno"
msgid "Hole"
msgstr "Orificio"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contorno y orificio" msgstr "Contorno y orificio"
+3
View File
@@ -15433,6 +15433,9 @@ msgstr "Peint uniquement"
msgid "Contour" msgid "Contour"
msgstr "Contour" msgstr "Contour"
msgid "Hole"
msgstr "Trou"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contour et trou" msgstr "Contour et trou"
+3
View File
@@ -15122,6 +15122,9 @@ msgstr "Csak festett"
msgid "Contour" msgid "Contour"
msgstr "Kontúr" msgstr "Kontúr"
msgid "Hole"
msgstr "Lyuk"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontúr és lyuk" msgstr "Kontúr és lyuk"
+3
View File
@@ -15319,6 +15319,9 @@ msgstr "Solo verniciato"
msgid "Contour" msgid "Contour"
msgstr "Contorno" msgstr "Contorno"
msgid "Hole"
msgstr "Foro"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contorno e foro" msgstr "Contorno e foro"
+3
View File
@@ -14093,6 +14093,9 @@ msgstr "塗装のみ"
msgid "Contour" msgid "Contour"
msgstr "輪郭" msgstr "輪郭"
msgid "Hole"
msgstr "穴"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "輪郭と穴" msgstr "輪郭と穴"
+3
View File
@@ -14240,6 +14240,9 @@ msgstr "도색만"
msgid "Contour" msgid "Contour"
msgstr "윤곽" msgstr "윤곽"
msgid "Hole"
msgstr "구멍"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "윤곽 및 구멍" msgstr "윤곽 및 구멍"
+3
View File
@@ -15043,6 +15043,9 @@ msgstr "Tik dažytas"
msgid "Contour" msgid "Contour"
msgstr "Kontūras" msgstr "Kontūras"
msgid "Hole"
msgstr "Skylė"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontūras ir skylė" msgstr "Kontūras ir skylė"
+3
View File
@@ -15043,6 +15043,9 @@ msgstr "Alleen geverfd"
msgid "Contour" msgid "Contour"
msgstr "Contour" msgstr "Contour"
msgid "Hole"
msgstr "Gat"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contour en gat" msgstr "Contour en gat"
+3
View File
@@ -14539,6 +14539,9 @@ msgstr "Tylko malowane"
msgid "Contour" msgid "Contour"
msgstr "Kontur" msgstr "Kontur"
msgid "Hole"
msgstr "Otwory"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontur i otwory" msgstr "Kontur i otwory"
@@ -15186,6 +15186,9 @@ msgstr "Somente pintado"
msgid "Contour" msgid "Contour"
msgstr "Contorno" msgstr "Contorno"
msgid "Hole"
msgstr "Furo"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Contorno e furo" msgstr "Contorno e furo"
+3
View File
@@ -15501,6 +15501,9 @@ msgstr "Вручную"
msgid "Contour" msgid "Contour"
msgstr "Контур" msgstr "Контур"
msgid "Hole"
msgstr "Отверстия"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Контур и отверстия" msgstr "Контур и отверстия"
+3
View File
@@ -14883,6 +14883,9 @@ msgstr "Endast målad"
msgid "Contour" msgid "Contour"
msgstr "Kontur" msgstr "Kontur"
msgid "Hole"
msgstr "Hål"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontur och hål" msgstr "Kontur och hål"
+3
View File
@@ -13339,6 +13339,9 @@ msgstr "Sadece boyalı"
msgid "Contour" msgid "Contour"
msgstr "Kontur" msgstr "Kontur"
msgid "Hole"
msgstr "Delik"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Kontur ve delik" msgstr "Kontur ve delik"
+3
View File
@@ -14536,6 +14536,9 @@ msgstr "Тільки пофарбовані"
msgid "Contour" msgid "Contour"
msgstr "Контур" msgstr "Контур"
msgid "Hole"
msgstr "Отвір"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Контур та отвір" msgstr "Контур та отвір"
+3
View File
@@ -14730,6 +14730,9 @@ msgstr "Chỉ được sơn"
msgid "Contour" msgid "Contour"
msgstr "Đường viền" msgstr "Đường viền"
msgid "Hole"
msgstr "Lỗ"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "Đường viền và lỗ" msgstr "Đường viền và lỗ"
@@ -13894,6 +13894,9 @@ msgstr "仅涂漆"
msgid "Contour" msgid "Contour"
msgstr "轮廓" msgstr "轮廓"
msgid "Hole"
msgstr "孔"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "轮廓和孔" msgstr "轮廓和孔"
@@ -14006,6 +14006,9 @@ msgstr "僅塗漆"
msgid "Contour" msgid "Contour"
msgstr "輪廓" msgstr "輪廓"
msgid "Hole"
msgstr "孔洞"
msgid "Contour and hole" msgid "Contour and hole"
msgstr "輪廓和孔" msgstr "輪廓和孔"
+152 -42
View File
@@ -418,7 +418,13 @@ void group_region_by_fuzzify(PerimeterGenerator& g)
g.has_fuzzy_skin = false; g.has_fuzzy_skin = false;
g.has_fuzzy_hole = false; g.has_fuzzy_hole = false;
std::unordered_map<FuzzySkinConfig, SurfacesPtr> regions; struct ConfigSurfaces {
FuzzySkinConfig config;
SurfacesPtr surfaces;
};
std::vector<ConfigSurfaces> regions;
regions.reserve(g.compatible_regions->size());
for (auto region : *g.compatible_regions) { for (auto region : *g.compatible_regions) {
const auto& region_config = region->region().config(); const auto& region_config = region->region().config();
const FuzzySkinConfig cfg{region_config.fuzzy_skin, const FuzzySkinConfig cfg{region_config.fuzzy_skin,
@@ -434,26 +440,36 @@ void group_region_by_fuzzify(PerimeterGenerator& g)
region_config.fuzzy_skin_ripple_offset, region_config.fuzzy_skin_ripple_offset,
region_config.fuzzy_skin_layers_between_ripple_offset, region_config.fuzzy_skin_layers_between_ripple_offset,
g.layer_id}; g.layer_id};
auto& surfaces = regions[cfg];
auto it = std::find_if(regions.begin(), regions.end(), [&cfg](const ConfigSurfaces& item) {
return item.config == cfg;
});
if (it == regions.end()) {
regions.push_back({cfg, {}});
it = regions.end() - 1;
}
auto& surfaces = it->surfaces;
for (const auto& surface : region->slices.surfaces) { for (const auto& surface : region->slices.surfaces) {
surfaces.push_back(&surface); surfaces.push_back(&surface);
} }
if (cfg.type != FuzzySkinType::None && cfg.type != FuzzySkinType::Disabled_fuzzy) { if (should_fuzzify(cfg, g.layer_id, 0, true)) {
g.has_fuzzy_skin = true; g.has_fuzzy_skin = true;
if (cfg.type != FuzzySkinType::External) { }
g.has_fuzzy_hole = true; if (should_fuzzify(cfg, g.layer_id, 0, false)) {
} g.has_fuzzy_hole = true;
} }
} }
if (regions.size() == 1) { // optimization if (regions.size() == 1) { // optimization
g.regions_by_fuzzify[regions.begin()->first] = {}; g.regions_by_fuzzify.push_back({regions.front().config, {}});
return; return;
} }
for (auto& it : regions) { g.regions_by_fuzzify.reserve(regions.size());
g.regions_by_fuzzify[it.first] = offset_ex(it.second, ClipperSafetyOffset); for (const auto& region : regions) {
g.regions_by_fuzzify.push_back({region.config, offset_ex(region.surfaces, ClipperSafetyOffset)});
} }
} }
@@ -469,12 +485,79 @@ bool should_fuzzify(const FuzzySkinConfig& config, const int layer_id, const siz
return false; return false;
} }
const bool fuzzify_contours = loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls; const bool fuzzify_contours = (loop_idx == 0 && fuzziy_type != FuzzySkinType::Hole) || fuzziy_type == FuzzySkinType::AllWalls;
const bool fuzzify_holes = fuzzify_contours && (fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls); const bool fuzzify_holes = (fuzziy_type == FuzzySkinType::Hole || fuzziy_type == FuzzySkinType::All || fuzziy_type == FuzzySkinType::AllWalls)
&& (loop_idx == 0 || fuzziy_type == FuzzySkinType::AllWalls);
return is_contour ? fuzzify_contours : fuzzify_holes; return is_contour ? fuzzify_contours : fuzzify_holes;
} }
struct MergedFuzzyRegion {
const FuzzySkinConfig *config;
ExPolygons expolygons;
};
// Compare whether two configs produce the same fuzzy effect (ignoring type/first_layer
// which only control which loops get fuzzified, not the noise itself).
static bool same_fuzzy_effect(const FuzzySkinConfig& a, const FuzzySkinConfig& b)
{
return a.thickness == b.thickness
&& a.point_distance == b.point_distance
&& a.noise_type == b.noise_type
&& a.noise_scale == b.noise_scale
&& a.noise_octaves == b.noise_octaves
&& a.noise_persistence == b.noise_persistence
&& a.mode == b.mode
&& a.ripples_per_layer == b.ripples_per_layer
&& a.ripple_offset == b.ripple_offset
&& a.layers_between_ripple_offset == b.layers_between_ripple_offset;
}
static std::vector<MergedFuzzyRegion> collect_merged_fuzzy_regions(const std::vector<std::pair<FuzzySkinConfig, ExPolygons>>& regions,
const int layer_id,
const size_t loop_idx,
const bool is_contour)
{
// Merge regions that produce identical fuzzy effects (differ only in type).
// When the style (e.g. External) and a painted region (All) both fuzzify this loop
// with the same noise parameters, merging their ExPolygons avoids splitting the
// perimeter at the painted boundary — eliminating discontinuity artifacts.
std::vector<MergedFuzzyRegion> merged_regions;
merged_regions.reserve(regions.size());
for (const auto& region : regions) {
if (!should_fuzzify(region.first, layer_id, loop_idx, is_contour)) {
continue;
}
bool merged = false;
for (auto& merged_region : merged_regions) {
if (same_fuzzy_effect(*merged_region.config, region.first)) {
if (merged_region.expolygons.empty()) {
// Already full coverage, nothing to add.
} else if (region.second.empty()) {
merged_region.expolygons.clear();
} else {
append(merged_region.expolygons, region.second);
}
merged = true;
break;
}
}
if (!merged) {
merged_regions.push_back({&region.first, region.second});
}
}
for (auto& merged_region : merged_regions) {
if (!merged_region.expolygons.empty()) {
merged_region.expolygons = union_ex(merged_region.expolygons);
}
}
return merged_regions;
}
Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perimeter_generator, const size_t loop_idx, const bool is_contour) Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perimeter_generator, const size_t loop_idx, const bool is_contour)
{ {
Polygon fuzzified; Polygon fuzzified;
@@ -493,22 +576,30 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
return fuzzified; return fuzzified;
} }
// Find all affective regions // Merge regions that produce identical fuzzy effects (differ only in type).
std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions; // When the style (e.g. External) and a painted region (All) both fuzzify this loop
fuzzified_regions.reserve(regions.size()); // with the same noise parameters, merging their ExPolygons avoids splitting the
for (const auto& region : regions) { // perimeter at the painted boundary — eliminating discontinuity artifacts.
if (should_fuzzify(region.first, perimeter_generator.layer_id, loop_idx, is_contour)) { auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, loop_idx, is_contour);
fuzzified_regions.emplace_back(region.first, region.second); if (merged_regions.empty()) {
}
}
if (fuzzified_regions.empty()) {
return polygon; return polygon;
} }
// Fast path: single merged region — apply directly without splitting
if (merged_regions.size() == 1) {
const auto& mr = merged_regions.front();
if (mr.expolygons.empty()) {
fuzzified = polygon;
fuzzy_polyline(fuzzified.points, true, slice_z, *mr.config);
return fuzzified;
}
// Fall through to split_line with a single region below
}
#ifdef DEBUG_FUZZY #ifdef DEBUG_FUZZY
{ {
int i = 0; int i = 0;
for (const auto& r : fuzzified_regions) { for (const auto& r : merged_regions) {
BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces); BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
bbox.offset(scale_(1.)); bbox.offset(scale_(1.));
::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id, ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
@@ -517,18 +608,26 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
bbox); bbox);
svg.draw_outline(perimeter_generator.slices->surfaces); svg.draw_outline(perimeter_generator.slices->surfaces);
svg.draw_outline(polygon, "green"); svg.draw_outline(polygon, "green");
svg.draw(r.second, "red", 0.5); svg.draw(r.expolygons, "red", 0.5);
svg.draw_outline(r.second, "red"); svg.draw_outline(r.expolygons, "red");
svg.Close(); svg.Close();
i++; i++;
} }
} }
#endif #endif
// Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz
// the same perimeter section. Later regions in the list take priority over earlier ones
// in overlapping areas (matching modifier precedence order).
for (size_t i = 0; i < merged_regions.size(); ++i)
for (size_t j = i + 1; j < merged_regions.size(); ++j)
if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty())
merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons);
// Split the loops into lines with different config, and fuzzy them separately // Split the loops into lines with different config, and fuzzy them separately
fuzzified = polygon; fuzzified = polygon;
for (const auto& r : fuzzified_regions) { for (const auto& r : merged_regions) {
auto splitted = Algorithm::split_line(fuzzified, r.second, true); auto splitted = Algorithm::split_line(fuzzified, r.expolygons, true);
if (splitted.empty()) { if (splitted.empty()) {
// No intersection, skip // No intersection, skip
continue; continue;
@@ -537,7 +636,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
// Fuzzy splitted polygon // Fuzzy splitted polygon
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
// The entire polygon is fuzzified // The entire polygon is fuzzified
fuzzy_polyline(fuzzified.points, true, slice_z, r.first); fuzzy_polyline(fuzzified.points, true, slice_z, *r.config);
} else { } else {
// Start from a non-clipped junction so wrapped clipped segments do // Start from a non-clipped junction so wrapped clipped segments do
// not need an artificial reconnection across the seam. // not need an artificial reconnection across the seam.
@@ -554,7 +653,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() { const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() {
fuzzified.points.push_back(segment.front()); fuzzified.points.push_back(segment.front());
const auto back = segment.back(); const auto back = segment.back();
fuzzy_polyline(segment, false, slice_z, r.first); fuzzy_polyline(segment, false, slice_z, *r.config);
fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end()); fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end());
fuzzified.points.push_back(back); fuzzified.points.push_back(back);
segment.clear(); segment.clear();
@@ -593,20 +692,23 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
if (fuzzify) if (fuzzify)
fuzzy_extrusion_line(extrusion->junctions, slice_z, config); fuzzy_extrusion_line(extrusion->junctions, slice_z, config);
} else { } else {
// Find all affective regions // Merge regions that produce identical fuzzy effects (differ only in type).
std::vector<std::pair<const FuzzySkinConfig&, const ExPolygons&>> fuzzified_regions; // When the style (e.g. External) and a painted region (All) both fuzzify this loop
fuzzified_regions.reserve(regions.size()); // with the same noise parameters, merging avoids splitting the perimeter at the
for (const auto& region : regions) { // painted boundary — eliminating discontinuity artifacts.
if (should_fuzzify(region.first, perimeter_generator.layer_id, extrusion->inset_idx, is_contour)) { auto merged_regions = collect_merged_fuzzy_regions(regions, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
fuzzified_regions.emplace_back(region.first, region.second); if (!merged_regions.empty()) {
// Fast path: single merged region — apply directly without splitting
if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty()) {
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config);
return;
} }
}
if (!fuzzified_regions.empty()) {
#ifdef DEBUG_FUZZY #ifdef DEBUG_FUZZY
{ {
int i = 0; int i = 0;
for (const auto& r : fuzzified_regions) { for (const auto& r : merged_regions) {
BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces); BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
bbox.offset(scale_(1.)); bbox.offset(scale_(1.));
::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id, ::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
@@ -623,17 +725,25 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
svg.draw_outline(perimeter_generator.slices->surfaces); svg.draw_outline(perimeter_generator.slices->surfaces);
svg.draw_outline(extrusion_polygon, "green"); svg.draw_outline(extrusion_polygon, "green");
svg.draw(r.second, "red", 0.5); svg.draw(r.expolygons, "red", 0.5);
svg.draw_outline(r.second, "red"); svg.draw_outline(r.expolygons, "red");
svg.Close(); svg.Close();
i++; i++;
} }
} }
#endif #endif
// Make each region's ExPolygons exclusive so overlapping regions don't double-fuzz
// the same perimeter section. Later regions in the list take priority over earlier ones
// in overlapping areas.
for (size_t i = 0; i < merged_regions.size(); ++i)
for (size_t j = i + 1; j < merged_regions.size(); ++j)
if (!merged_regions[i].expolygons.empty() && !merged_regions[j].expolygons.empty())
merged_regions[i].expolygons = diff_ex(merged_regions[i].expolygons, merged_regions[j].expolygons);
// Split the loops into lines with different config, and fuzzy them separately // Split the loops into lines with different config, and fuzzy them separately
for (const auto& r : fuzzified_regions) { for (const auto& r : merged_regions) {
const auto splitted = Algorithm::split_line(*extrusion, r.second, false); const auto splitted = Algorithm::split_line(*extrusion, r.expolygons, false);
if (splitted.empty()) { if (splitted.empty()) {
// No intersection, skip // No intersection, skip
continue; continue;
@@ -642,7 +752,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
// Fuzzy splitted extrusion // Fuzzy splitted extrusion
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
// The entire polygon is fuzzified // The entire polygon is fuzzified
fuzzy_extrusion_line(extrusion->junctions, slice_z, r.first); fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config);
continue; continue;
} else { } else {
const auto current_ext = extrusion->junctions; const auto current_ext = extrusion->junctions;
@@ -655,7 +765,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
const auto front = segment.front(); const auto front = segment.front();
const auto back = segment.back(); const auto back = segment.back();
fuzzy_extrusion_line(segment, slice_z, r.first, false); fuzzy_extrusion_line(segment, slice_z, *r.config, false);
// Orca: only add non fuzzy point if it's not in the extrusion closing point. // Orca: only add non fuzzy point if it's not in the extrusion closing point.
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) { if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) {
extrusion->junctions.push_back(front); extrusion->junctions.push_back(front);
+17
View File
@@ -250,6 +250,23 @@ void Layer::make_perimeters()
//BBS: Separate fill_no_overlap //BBS: Separate fill_no_overlap
(*l)->fill_no_overlap_expolygons = intersection_ex((*l)->slices.surfaces, fill_no_overlap); (*l)->fill_no_overlap_expolygons = intersection_ex((*l)->slices.surfaces, fill_no_overlap);
} }
// When counterbore hole bridging (chbFilled) is active, process_no_bridge may
// create fill surfaces that extend beyond all region slices (e.g. by clearing
// holes in the bridge expolygon). These "extra" fills are lost during the
// intersection-based splitting above. Recover them and assign to the first
// merged region so the sacrificial bridge layer is not broken.
if (layerm_config->region().config().counterbore_hole_bridging.value != chbNone) {
Polygons all_region_slices_p;
for (LayerRegion *l : layerms)
polygons_append(all_region_slices_p, to_polygons(l->slices.surfaces));
ExPolygons extra_fill = diff_ex(fill_surfaces.surfaces, all_region_slices_p, ApplySafetyOffset::Yes);
if (!extra_fill.empty()) {
append(layerms.front()->fill_expolygons, extra_fill);
layerms.front()->fill_expolygons = union_ex(layerms.front()->fill_expolygons);
layerms.front()->fill_surfaces.append(std::move(extra_fill), fill_surfaces.surfaces.front());
}
}
} }
} }
} }
+2 -1
View File
@@ -103,7 +103,8 @@ public:
bool has_fuzzy_skin = false; bool has_fuzzy_skin = false;
bool has_fuzzy_hole = false; bool has_fuzzy_hole = false;
std::unordered_map<FuzzySkinConfig, ExPolygons> regions_by_fuzzify; // Preserve construction order so overlap precedence remains deterministic.
std::vector<std::pair<FuzzySkinConfig, ExPolygons>> regions_by_fuzzify;
PerimeterGenerator( PerimeterGenerator(
// Input: // Input:
+3
View File
@@ -172,6 +172,7 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PowerLossRecoveryMode)
static t_config_enum_values s_keys_map_FuzzySkinType { static t_config_enum_values s_keys_map_FuzzySkinType {
{ "none", int(FuzzySkinType::None) }, { "none", int(FuzzySkinType::None) },
{ "external", int(FuzzySkinType::External) }, { "external", int(FuzzySkinType::External) },
{ "hole", int(FuzzySkinType::Hole) },
{ "all", int(FuzzySkinType::All) }, { "all", int(FuzzySkinType::All) },
{ "allwalls", int(FuzzySkinType::AllWalls)}, { "allwalls", int(FuzzySkinType::AllWalls)},
{ "disabled_fuzzy", int(FuzzySkinType::Disabled_fuzzy)} { "disabled_fuzzy", int(FuzzySkinType::Disabled_fuzzy)}
@@ -3354,11 +3355,13 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<FuzzySkinType>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<FuzzySkinType>::get_enum_values();
def->enum_values.push_back("none"); def->enum_values.push_back("none");
def->enum_values.push_back("external"); def->enum_values.push_back("external");
def->enum_values.push_back("hole");
def->enum_values.push_back("all"); def->enum_values.push_back("all");
def->enum_values.push_back("allwalls"); def->enum_values.push_back("allwalls");
def->enum_values.push_back("disabled_fuzzy"); def->enum_values.push_back("disabled_fuzzy");
def->enum_labels.push_back(L("Painted only")); def->enum_labels.push_back(L("Painted only"));
def->enum_labels.push_back(L("Contour")); def->enum_labels.push_back(L("Contour"));
def->enum_labels.push_back(L("Hole"));
def->enum_labels.push_back(L("Contour and hole")); def->enum_labels.push_back(L("Contour and hole"));
def->enum_labels.push_back(L("All walls")); def->enum_labels.push_back(L("All walls"));
def->enum_labels.push_back(L("Disabled")); def->enum_labels.push_back(L("Disabled"));
+1
View File
@@ -39,6 +39,7 @@ enum GCodeFlavor : unsigned char {
enum class FuzzySkinType { enum class FuzzySkinType {
None, None,
External, External,
Hole,
All, All,
AllWalls, AllWalls,
Disabled_fuzzy, Disabled_fuzzy,