From bb2186cbcfa6027ea2c216ccdee33edeba4aa4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 22 Nov 2023 14:40:10 +0100 Subject: [PATCH] Refactor: expand_merge_surfaces now uses expansion_zones. This enables addition of other expansion zones in the future. For example to make sure bridges are anchored properly even if there is top fill next to them. --- src/libslic3r/LayerRegion.cpp | 65 +++++++++++++-------------- src/libslic3r/LayerRegion.hpp | 12 +++++ tests/libslic3r/test_layer_region.cpp | 53 +++++++++++++++++++--- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 4d49dc7fdf..62bd329641 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -435,17 +435,13 @@ Surfaces expand_bridges_detect_orientations( return out; } -// Extract bridging surfaces from "surfaces", expand them into "shells" using expansion_params. -// Trim "shells" by the expanded bridges. Surfaces expand_merge_surfaces( - Surfaces &surfaces, - SurfaceType surface_type, - ExPolygons &shells, - const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill, - ExPolygons &sparse, - const Algorithm::RegionExpansionParameters &expansion_params_into_sparse_infill, - const float closing_radius, - const double bridge_angle = -1.) + Surfaces &surfaces, + SurfaceType surface_type, + std::vector& expansion_zones, + const float closing_radius, + const double bridge_angle +) { using namespace Slic3r::Algorithm; @@ -454,17 +450,17 @@ Surfaces expand_merge_surfaces( if (src.empty()) return {}; - std::vector expansions = propagate_waves(src, shells, expansion_params_into_solid_infill); - bool expanded_into_shells = !expansions.empty(); - bool expanded_into_sparse = false; - { - std::vector expansions2 = propagate_waves(src, sparse, expansion_params_into_sparse_infill); - if (! expansions2.empty()) { - expanded_into_sparse = true; - for (RegionExpansion &expansion : expansions2) - expansion.boundary_id += uint32_t(shells.size()); - append(expansions, std::move(expansions2)); - } + unsigned processed_expolygons_count = 0; + std::vector expansions; + for (ExpansionZone& expansion_zone : expansion_zones) { + std::vector zone_expansions = propagate_waves(src, expansion_zone.expolygons, expansion_zone.parameters); + expansion_zone.expanded_into = !zone_expansions.empty(); + + for (RegionExpansion &expansion : zone_expansions) + expansion.boundary_id += processed_expolygons_count; + + processed_expolygons_count += expansion_zone.expolygons.size(); + append(expansions, std::move(zone_expansions)); } std::vector expanded = merge_expansions_into_expolygons(std::move(src), std::move(expansions)); @@ -472,11 +468,10 @@ Surfaces expand_merge_surfaces( // without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface. // look for narrow_ensure_vertical_wall_thickness_region_radius filter. expanded = closing_ex(expanded, closing_radius); - // Trim the shells by the expanded expolygons. - if (expanded_into_shells) - shells = diff_ex(shells, expanded); - if (expanded_into_sparse) - sparse = diff_ex(sparse, expanded); + // Trim the zones by the expanded expolygons. + for (ExpansionZone& expansion_zone : expansion_zones) + if (expansion_zone.expanded_into) + expansion_zone.expolygons = diff_ex(expansion_zone.expolygons, expanded); Surface templ{ surface_type, {} }; templ.bridge_angle = bridge_angle; @@ -538,7 +533,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges. layer" << this->layer()->print_z; const double custom_angle = this->region().config().bridge_angle.value; bridges.surfaces = custom_angle > 0 ? - expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, expansion_zones[0].expolygons, expansion_params_into_solid_infill, expansion_zones[1].expolygons, expansion_params_into_sparse_infill, closing_radius, Geometry::deg2rad(custom_angle)) : + expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, expansion_zones, closing_radius, Geometry::deg2rad(custom_angle)) : expand_bridges_detect_orientations(m_fill_surfaces.surfaces, expansion_zones, closing_radius); BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done"; #if 0 @@ -549,16 +544,18 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly #endif } - Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, expansion_zones[0].expolygons, - RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps), - expansion_zones[1].expolygons, expansion_params_into_sparse_infill, closing_radius); - Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, expansion_zones[0].expolygons, - RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps), - expansion_zones[1].expolygons, expansion_params_into_sparse_infill, closing_radius); + expansion_zones.at(0).parameters = RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps); + Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, expansion_zones, closing_radius); + + expansion_zones.at(0).parameters = RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps); + Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, expansion_zones, closing_radius); // m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid }); m_fill_surfaces.clear(); - reserve_more(m_fill_surfaces.surfaces, expansion_zones[0].expolygons.size() + expansion_zones[1].expolygons.size() + bridges.size() + bottoms.size() + tops.size()); + unsigned zones_expolygons_count = 0; + for (const ExpansionZone& zone : expansion_zones) + zones_expolygons_count += zone.expolygons.size(); + reserve_more(m_fill_surfaces.surfaces, zones_expolygons_count + bridges.size() + bottoms.size() + tops.size()); { Surface solid_templ(stInternalSolid, {}); solid_templ.thickness = layer_thickness; diff --git a/src/libslic3r/LayerRegion.hpp b/src/libslic3r/LayerRegion.hpp index 80ad7ff734..6b6b89e565 100644 --- a/src/libslic3r/LayerRegion.hpp +++ b/src/libslic3r/LayerRegion.hpp @@ -173,6 +173,18 @@ Surfaces expand_bridges_detect_orientations( const float closing_radius ); +/** +* Extract bridging surfaces from "surfaces", expand them into "shells" using expansion_params. +* Trim "shells" by the expanded bridges. +*/ +Surfaces expand_merge_surfaces( + Surfaces &surfaces, + SurfaceType surface_type, + std::vector& expansion_zones, + const float closing_radius, + const double bridge_angle = -1 +); + } #endif // slic3r_LayerRegion_hpp_ diff --git a/tests/libslic3r/test_layer_region.cpp b/tests/libslic3r/test_layer_region.cpp index 604510aec7..9652a54324 100644 --- a/tests/libslic3r/test_layer_region.cpp +++ b/tests/libslic3r/test_layer_region.cpp @@ -1,10 +1,12 @@ #include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/Geometry.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/SVG.hpp" #include #include using namespace Slic3r; +using namespace Slic3r::Algorithm; constexpr bool export_svgs = true; @@ -17,11 +19,7 @@ ExPolygon rectangle(const Point& origin, const int width, const int height) { }; } -TEST_CASE("test the surface expansion", "[LayerRegion]") { -} - -TEST_CASE("test the bridge expansion with the bridge angle detection", "[LayerRegion]") { - using namespace Slic3r::Algorithm; +struct LayerRegionFixture { Surfaces surfaces{ Surface{ stBottomBridge, @@ -50,13 +48,13 @@ TEST_CASE("test the bridge expansion with the bridge angle detection", "[LayerRe static constexpr const size_t max_nr_expansion_steps = 5; const float closing_radius = 0.55f * 0.65f * 1.05f * scaled_spacing; const int shells_expansion_depth = scaled(0.6); - const auto expansion_params_into_solid_infill = RegionExpansionParameters::build( + const RegionExpansionParameters expansion_params_into_solid_infill = RegionExpansionParameters::build( shells_expansion_depth, expansion_step, max_nr_expansion_steps ); const int sparse_expansion_depth = scaled(0.3); - const auto expansion_params_into_sparse_infill = RegionExpansionParameters::build( + const RegionExpansionParameters expansion_params_into_sparse_infill = RegionExpansionParameters::build( sparse_expansion_depth, expansion_step, max_nr_expansion_steps @@ -72,7 +70,48 @@ TEST_CASE("test the bridge expansion with the bridge angle detection", "[LayerRe expansion_params_into_sparse_infill, } }; +}; +TEST_CASE_METHOD(LayerRegionFixture, "test the surface expansion", "[LayerRegion]") { + float custom_angle = 1.234; + + Surfaces result{expand_merge_surfaces( + surfaces, stBottomBridge, + expansion_zones, + closing_radius, + custom_angle + )}; + + if constexpr (export_svgs) { + SVG svg("general_expansion.svg", BoundingBox{ + Point{scaled(-3.0), scaled(-1.0)}, + Point{scaled(2.0), scaled(2.0)} + }); + + svg.draw(surfaces, "blue"); + svg.draw(expansion_zones[0].expolygons, "green"); + svg.draw(expansion_zones[1].expolygons, "red"); + svg.draw_outline(result, "black", "", scale_(0.01)); + } + + REQUIRE(result.size() == 2); + CHECK(result.at(0).bridge_angle == Approx(custom_angle)); + CHECK(result.at(1).bridge_angle == Approx(custom_angle)); + CHECK(result.at(0).expolygon.contour.size() == 22); + CHECK(result.at(1).expolygon.contour.size() == 14); + + // These lines in the polygons should correspond to the expansion depth. + CHECK(result.at(0).expolygon.contour.lines().at(2).length() == shells_expansion_depth); + CHECK(result.at(1).expolygon.contour.lines().at(7).length() == sparse_expansion_depth); + CHECK(result.at(1).expolygon.contour.lines().at(11).length() == sparse_expansion_depth); + + CHECK(intersection_ex({result.at(0).expolygon}, expansion_zones[0].expolygons).size() == 0); + CHECK(intersection_ex({result.at(0).expolygon}, expansion_zones[1].expolygons).size() == 0); + CHECK(intersection_ex({result.at(1).expolygon}, expansion_zones[0].expolygons).size() == 0); + CHECK(intersection_ex({result.at(1).expolygon}, expansion_zones[1].expolygons).size() == 0); +} + +TEST_CASE_METHOD(LayerRegionFixture, "test the bridge expansion with the bridge angle detection", "[LayerRegion]") { Surfaces result{expand_bridges_detect_orientations( surfaces, expansion_zones,