mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-14 20:47:33 +00:00
Extract Layer::choose_ironing_extruder for unit-testable ironing routing (#13467)
* Extract Layer::choose_ironing_extruder for unit-testable ironing routing The ironing extruder selection in make_ironing() was a 5-line nested conditional inlined at the top of the loop, with no isolated test coverage. Pull the gating into a static helper so the routing decision is unit-testable without spinning up the slicing pipeline. Pure refactor: the helper preserves the original logic bit-for-bit (NoIroning -> -1; AllSolid always enabled; TopSurfaces and TopmostOnly require some top shells or, in spiral mode, more than one bottom shell; TopmostOnly additionally requires being on the topmost layer; enabled ironing routes to solid_infill_filament). Add tests/fff_print/test_choose_ironing_extruder.cpp covering: - AllSolid regardless of layer position - TopSurfaces with top_shell_layers > 0 - TopSurfaces with top_shell_layers=0 + spiral mode + bottom_shell_layers>1 - TopmostOnly + topmost layer - NoIroning short-circuit - TopSurfaces with top_shell_layers=0 (and not spiral) -> disabled - TopSurfaces, spiral, but bottom_shell_layers=1 -> disabled - TopmostOnly on a non-topmost layer -> disabled * Move ironing routing test into the Fill subsystem file Rename the test to tests/libslic3r/test_fill.cpp and tag it [Fill] to match the subsystem it covers, use flat behavioral test cases with GENERATE for the parameterized ones, and drop the history narration from the code comments. * tests: move ironing routing tests into fff_print/test_fill.cpp Keeps the Fill tests in one file, alongside the existing ironing rotation-template test.
This commit is contained in:
@@ -1595,6 +1595,25 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
|
||||
return sparse_infill_polylines;
|
||||
}
|
||||
|
||||
// Returns the filament id (1-based) the region is ironed with, or -1 when the
|
||||
// region is not ironed. AllSolid always irons. TopSurfaces and TopmostOnly need
|
||||
// either some top shells or, in spiral mode, more than one bottom shell, and
|
||||
// TopmostOnly additionally needs the layer to be the topmost one.
|
||||
int Layer::choose_ironing_extruder(const PrintRegionConfig &cfg,
|
||||
bool spiral_mode,
|
||||
bool is_topmost_layer)
|
||||
{
|
||||
if (cfg.ironing_type == IroningType::NoIroning)
|
||||
return -1;
|
||||
const bool gate = (cfg.ironing_type == IroningType::AllSolid)
|
||||
|| ((cfg.top_shell_layers > 0 || (spiral_mode && cfg.bottom_shell_layers > 1))
|
||||
&& (cfg.ironing_type == IroningType::TopSurfaces
|
||||
|| (cfg.ironing_type == IroningType::TopmostOnly && is_topmost_layer)));
|
||||
if (!gate)
|
||||
return -1;
|
||||
return cfg.top_surface_filament_id;
|
||||
}
|
||||
|
||||
// Create ironing extrusions over top surfaces.
|
||||
void Layer::make_ironing()
|
||||
{
|
||||
@@ -1664,19 +1683,10 @@ void Layer::make_ironing()
|
||||
if (! layerm->slices.empty()) {
|
||||
IroningParams ironing_params;
|
||||
const PrintRegionConfig &config = layerm->region().config();
|
||||
if (config.ironing_type != IroningType::NoIroning &&
|
||||
(config.ironing_type == IroningType::AllSolid ||
|
||||
((config.top_shell_layers > 0 || (this->object()->print()->config().spiral_mode && config.bottom_shell_layers > 1)) &&
|
||||
(config.ironing_type == IroningType::TopSurfaces ||
|
||||
(config.ironing_type == IroningType::TopmostOnly && layerm->layer()->upper_layer == nullptr))))) {
|
||||
if (config.outer_wall_filament_id == config.top_surface_filament_id || config.wall_loops == 0) {
|
||||
// Iron the whole face.
|
||||
ironing_params.extruder = config.top_surface_filament_id;
|
||||
} else {
|
||||
// Iron just the infill.
|
||||
ironing_params.extruder = config.top_surface_filament_id;
|
||||
}
|
||||
}
|
||||
ironing_params.extruder = Layer::choose_ironing_extruder(
|
||||
config,
|
||||
/*spiral_mode=*/this->object()->print()->config().spiral_mode,
|
||||
/*is_topmost_layer=*/layerm->layer()->upper_layer == nullptr);
|
||||
if (ironing_params.extruder != -1) {
|
||||
//TODO just_infill is currently not used.
|
||||
ironing_params.just_infill = false;
|
||||
|
||||
@@ -16,6 +16,7 @@ using LayerPtrs = std::vector<Layer*>;
|
||||
class LayerRegion;
|
||||
using LayerRegionPtrs = std::vector<LayerRegion*>;
|
||||
class PrintRegion;
|
||||
class PrintRegionConfig;
|
||||
class PrintObject;
|
||||
class Print;
|
||||
|
||||
@@ -200,6 +201,11 @@ public:
|
||||
FillAdaptive::Octree *support_fill_octree,
|
||||
FillLightning::Generator* lightning_generator) const;
|
||||
void make_ironing();
|
||||
// Returns the filament id (1-based) the region is ironed with, or -1 when the
|
||||
// region is not ironed.
|
||||
static int choose_ironing_extruder(const PrintRegionConfig &cfg,
|
||||
bool spiral_mode,
|
||||
bool is_topmost_layer);
|
||||
void make_contour_z(const sla::IndexedMesh &mesh);
|
||||
|
||||
void export_region_slices_to_svg(const char *path) const;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/SVG.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
@@ -676,6 +677,73 @@ TEST_CASE("Ironing follows the solid infill rotation template", "[Fill]")
|
||||
REQUIRE(compared > int(ironing.size()) / 2);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
PrintRegionConfig ironing_config(IroningType type,
|
||||
int top_surface_filament_id = 1,
|
||||
int top_shell_layers = 3,
|
||||
int bottom_shell_layers = 1)
|
||||
{
|
||||
PrintRegionConfig cfg;
|
||||
cfg.ironing_type.value = type;
|
||||
cfg.top_surface_filament_id.value = top_surface_filament_id;
|
||||
cfg.top_shell_layers.value = top_shell_layers;
|
||||
cfg.bottom_shell_layers.value = bottom_shell_layers;
|
||||
cfg.outer_wall_filament_id.value = 1;
|
||||
cfg.wall_loops.value = 2;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Ironing an all-solid region uses the top surface filament on every layer", "[Fill]")
|
||||
{
|
||||
const PrintRegionConfig cfg = ironing_config(IroningType::AllSolid, /*top_surface_filament_id=*/2);
|
||||
const bool is_topmost_layer = GENERATE(false, true);
|
||||
CAPTURE(is_topmost_layer);
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, is_topmost_layer) == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Ironing top surfaces uses the top surface filament when the region has top shells", "[Fill]")
|
||||
{
|
||||
const PrintRegionConfig cfg = ironing_config(IroningType::TopSurfaces,
|
||||
/*top_surface_filament_id=*/3,
|
||||
/*top_shell_layers=*/2);
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("Ironing top surfaces without top shells needs spiral mode and more than one bottom shell", "[Fill]")
|
||||
{
|
||||
const PrintRegionConfig one_bottom_shell = ironing_config(IroningType::TopSurfaces,
|
||||
/*top_surface_filament_id=*/1,
|
||||
/*top_shell_layers=*/0,
|
||||
/*bottom_shell_layers=*/1);
|
||||
const PrintRegionConfig two_bottom_shells = ironing_config(IroningType::TopSurfaces,
|
||||
/*top_surface_filament_id=*/1,
|
||||
/*top_shell_layers=*/0,
|
||||
/*bottom_shell_layers=*/2);
|
||||
|
||||
REQUIRE(Layer::choose_ironing_extruder(two_bottom_shells, /*spiral_mode=*/true, /*is_topmost_layer=*/false) == 1);
|
||||
REQUIRE(Layer::choose_ironing_extruder(one_bottom_shell, /*spiral_mode=*/true, /*is_topmost_layer=*/false) == -1);
|
||||
REQUIRE(Layer::choose_ironing_extruder(two_bottom_shells, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("Ironing the topmost surface only applies to the topmost layer", "[Fill]")
|
||||
{
|
||||
const PrintRegionConfig cfg = ironing_config(IroningType::TopmostOnly, /*top_surface_filament_id=*/4);
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/true) == 4);
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, /*spiral_mode=*/false, /*is_topmost_layer=*/false) == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
||||
{
|
||||
const PrintRegionConfig cfg = ironing_config(IroningType::NoIroning);
|
||||
const bool spiral_mode = GENERATE(false, true);
|
||||
CAPTURE(spiral_mode);
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
||||
}
|
||||
|
||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||
{
|
||||
auto angles_for = [](int direction) {
|
||||
|
||||
Reference in New Issue
Block a user