From ca0c83d914bb8cd654357f3f146ed582555c3b61 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Mon, 16 Jan 2023 14:39:48 +0100 Subject: [PATCH] The new ExtrusionRole implementation newly supports both "Bridging" and "External" attributes at the same time. PerimeterGenerator was updated to make use of it and set "External" attribute for overhang perimeters. --- src/libslic3r/ExtrusionRole.cpp | 7 ++++--- src/libslic3r/GCode.cpp | 4 ++-- src/libslic3r/PerimeterGenerator.cpp | 23 ++++++++++++----------- src/libslic3r/SupportSpotsGenerator.cpp | 4 +--- src/libslic3r/enum_bitmask.hpp | 6 ++++++ 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/ExtrusionRole.cpp b/src/libslic3r/ExtrusionRole.cpp index f43db4835..1e91df204 100644 --- a/src/libslic3r/ExtrusionRole.cpp +++ b/src/libslic3r/ExtrusionRole.cpp @@ -13,9 +13,10 @@ namespace Slic3r { GCodeExtrusionRole extrusion_role_to_gcode_extrusion_role(ExtrusionRole role) { if (role == ExtrusionRole::None) return GCodeExtrusionRole::None; - if (role == ExtrusionRole::Perimeter) return GCodeExtrusionRole::Perimeter; - if (role == ExtrusionRole::ExternalPerimeter) return GCodeExtrusionRole::ExternalPerimeter; - if (role == ExtrusionRole::OverhangPerimeter) return GCodeExtrusionRole::OverhangPerimeter; + if (role.is_perimeter()) { + return role.is_bridge() ? GCodeExtrusionRole::OverhangPerimeter : + role.is_external() ? GCodeExtrusionRole::ExternalPerimeter : GCodeExtrusionRole::Perimeter; + } if (role == ExtrusionRole::InternalInfill) return GCodeExtrusionRole::InternalInfill; if (role == ExtrusionRole::SolidInfill) return GCodeExtrusionRole::SolidInfill; if (role == ExtrusionRole::TopSolidInfill) return GCodeExtrusionRole::TopSolidInfill; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index e26e0b55e..ad0d3c43f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2631,7 +2631,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr } // make a little move inwards before leaving loop - if (paths.back().role() == ExtrusionRole::ExternalPerimeter && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { + if (paths.back().role().is_external_perimeter() && m_layer != NULL && m_config.perimeters.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { // detect angle between last and first segment // the side depends on the original winding order of the polygon (left for contours, right for holes) //FIXME improve the algorithm in case the loop is tiny. @@ -2877,7 +2877,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de } else if (path.role() == ExtrusionRole::ExternalPerimeter) { speed = m_config.get_abs_value("external_perimeter_speed"); } else if (path.role().is_bridge()) { - assert(path.role() == ExtrusionRole::OverhangPerimeter || path.role() == ExtrusionRole::BridgeInfill); + assert(path.role().is_perimeter() || path.role() == ExtrusionRole::BridgeInfill); speed = m_config.get_abs_value("bridge_speed"); } else if (path.role() == ExtrusionRole::InternalInfill) { speed = m_config.get_abs_value("infill_speed"); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index a9044367a..1f3066147 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -114,7 +114,7 @@ ExtrusionMultiPath PerimeterGenerator::thick_polyline_to_multi_path(const ThickP } const double w = fmax(line.a_width, line.b_width); - const Flow new_flow = (role == ExtrusionRole::OverhangPerimeter && flow.bridge()) ? flow : flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); + const Flow new_flow = (role.is_bridge() && flow.bridge()) ? flow : flow.with_width(unscale(w) + flow.height() * float(1. - 0.25 * PI)); if (path.polyline.points.empty()) { path.polyline.append(line.a); path.polyline.append(line.b); @@ -292,9 +292,9 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator for (const PerimeterGeneratorLoop &loop : loops) { bool is_external = loop.is_external(); - ExtrusionRole role = ExtrusionRole::None; ExtrusionLoopRole loop_role; - role = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; + ExtrusionRole role_normal = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; + ExtrusionRole role_overhang = role_normal | ExtrusionRoleModifier::Bridge; if (loop.is_internal_contour()) { // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. @@ -321,7 +321,7 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator extrusion_paths_append( paths, intersection_pl({ polygon }, lower_slices_polygons_clipped), - role, + role_normal, is_external ? params.ext_mm3_per_mm : params.mm3_per_mm, is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width(), float(params.layer_height)); @@ -332,7 +332,7 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator extrusion_paths_append( paths, diff_pl({ polygon }, lower_slices_polygons_clipped), - ExtrusionRole::OverhangPerimeter, + role_overhang, params.mm3_per_mm_overhang, params.overhang_flow.width(), params.overhang_flow.height()); @@ -341,7 +341,7 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator // We allow polyline reversal because Clipper may have randomly reversed polylines during clipping. chain_and_reorder_extrusion_paths(paths, &paths.front().first_point()); } else { - ExtrusionPath path(role); + ExtrusionPath path(role_normal); path.polyline = polygon.split_at_first_point(); path.mm3_per_mm = is_external ? params.ext_mm3_per_mm : params.mm3_per_mm; path.width = is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width(); @@ -503,7 +503,8 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P continue; const bool is_external = extrusion->inset_idx == 0; - ExtrusionRole role = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; + ExtrusionRole role_normal = is_external ? ExtrusionRole::ExternalPerimeter : ExtrusionRole::Perimeter; + ExtrusionRole role_overhang = role_normal | ExtrusionRoleModifier::Bridge; if (pg_extrusion.fuzzify) fuzzy_extrusion_line(*extrusion, scaled(params.config.fuzzy_skin_thickness.value), scaled(params.config.fuzzy_skin_point_dist.value)); @@ -541,13 +542,13 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P } // get non-overhang paths by intersecting this loop with the grown lower slices - extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role, + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); // get overhang paths by checking what parts of this loop fall // outside the grown lower slices (thus where the distance between // the loop centerline and original lower slices is >= half nozzle diameter - extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), ExtrusionRole::OverhangPerimeter, + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), role_overhang, params.overhang_flow); // Reapply the nearest point search for starting point. @@ -568,7 +569,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P for (const ExtrusionPath &path : paths) { ++point_occurrence[path.polyline.first_point()].occurrence; ++point_occurrence[path.polyline.last_point()].occurrence; - if (path.role() == ExtrusionRole::OverhangPerimeter) { + if (path.role().is_bridge()) { point_occurrence[path.polyline.first_point()].is_overhang = true; point_occurrence[path.polyline.last_point()].is_overhang = true; } @@ -588,7 +589,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P chain_and_reorder_extrusion_paths(paths, &start_point); } } else { - extrusion_paths_append(paths, *extrusion, role, is_external ? params.ext_perimeter_flow : params.perimeter_flow); + extrusion_paths_append(paths, *extrusion, role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); } // Append paths to collection. diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 43637d25f..eaf7dd57d 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -58,9 +58,7 @@ public: bool is_external_perimeter() const { assert(origin_entity != nullptr); - //FIXME origin_entity->role() == ExtrusionRole::OverhangPerimeter is not quite right. - // rather use origin_entity->role().is_external_perimeter() - return origin_entity->role() == ExtrusionRole::ExternalPerimeter || origin_entity->role() == ExtrusionRole::OverhangPerimeter; + return origin_entity->role().is_external_perimeter(); } Vec2f a; diff --git a/src/libslic3r/enum_bitmask.hpp b/src/libslic3r/enum_bitmask.hpp index 274952cb0..d5d247371 100644 --- a/src/libslic3r/enum_bitmask.hpp +++ b/src/libslic3r/enum_bitmask.hpp @@ -36,6 +36,12 @@ public: // Combine with another enum_bitmask of the same type. constexpr enum_bitmask operator|(enum_bitmask t) const { return enum_bitmask(m_bits | t.m_bits); } + // Set the bit corresponding to the given option. + constexpr void operator|=(option_type t) { m_bits = enum_bitmask(m_bits | mask_value(t)); } + + // Combine with another enum_bitmask of the same type. + constexpr void operator|=(enum_bitmask t) { m_bits = enum_bitmask(m_bits | t.m_bits); } + // Get the value of the bit corresponding to the given option. constexpr bool operator&(option_type t) const { return m_bits & mask_value(t); } constexpr bool has(option_type t) const { return m_bits & mask_value(t); }