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.
This commit is contained in:
Martin Šach 2023-11-22 14:40:10 +01:00 committed by Lukas Matena
parent 4d0bae1d3f
commit bb2186cbcf
3 changed files with 89 additions and 41 deletions

View File

@ -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<ExpansionZone>& 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<RegionExpansion> expansions = propagate_waves(src, shells, expansion_params_into_solid_infill);
bool expanded_into_shells = !expansions.empty();
bool expanded_into_sparse = false;
{
std::vector<RegionExpansion> 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<RegionExpansion> expansions;
for (ExpansionZone& expansion_zone : expansion_zones) {
std::vector<RegionExpansion> 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<ExPolygon> 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;

View File

@ -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<ExpansionZone>& expansion_zones,
const float closing_radius,
const double bridge_angle = -1
);
}
#endif // slic3r_LayerRegion_hpp_

View File

@ -1,10 +1,12 @@
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/SVG.hpp"
#include <catch2/catch.hpp>
#include <libslic3r/LayerRegion.hpp>
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,