mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-08 08:11:14 +00:00
Belt brim: cut the leading-edge brim at the first contact layer
The leading-edge-only brim is the outer brim cut down to the part's first contact with the belt, and the cut was taken at layers().front(). Since the slicing frame starts at the belt below the footprint (#16236) that is an empty lead-in layer whose contact lies ahead of the part, so the cut removed the whole region and the brim type produced no brim at all. Take the cut at the first layer with geometry. The all-brim-types test now includes leading_edge_only, and a new test checks that the brim starts no later than the part and covers fewer layers than the outer brim. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
cfad587c2d
commit
ed8c1f92d7
@@ -488,11 +488,19 @@ void make_belt_brim(PrintObject &object)
|
||||
width, gap, leading, lateral, bc.frame),
|
||||
bc.frame);
|
||||
|
||||
if (bt == btLeadingEdgeOnly && ! bc.region.empty())
|
||||
// The cut is the uphill edge of the first layer's contact band: everything
|
||||
// past it belongs to later contacts.
|
||||
bc.region = belt_brim_clip_leading_edge(bc.region, bc.frame,
|
||||
bc.ctx.cutoff_u(object.layers().front()->print_z));
|
||||
if (bt == btLeadingEdgeOnly && ! bc.region.empty()) {
|
||||
// The cut is the uphill edge of the first contact's band: everything past it
|
||||
// belongs to later contacts. The first contact is the first layer with
|
||||
// geometry, not layers().front(): the slicing frame starts at the belt below
|
||||
// the footprint, so the leading layers are empty and their contact lies ahead
|
||||
// of the part.
|
||||
const Layer *first_contact = nullptr;
|
||||
for (const Layer *layer : object.layers())
|
||||
if (! layer->lslices.empty()) { first_contact = layer; break; }
|
||||
if (first_contact == nullptr)
|
||||
return;
|
||||
bc.region = belt_brim_clip_leading_edge(bc.region, bc.frame, bc.ctx.cutoff_u(first_contact->print_z));
|
||||
}
|
||||
|
||||
if (bc.region.empty())
|
||||
return;
|
||||
|
||||
@@ -1140,7 +1140,7 @@ TEST_CASE("Every brim type slices on a belt printer", "[SkirtBrim][belt]")
|
||||
// Auto / Mouse ear / Painted collapse to outer-only rather than crashing or
|
||||
// silently producing nothing.
|
||||
const char *brim_type = GENERATE("auto_brim", "brim_ears", "painted", "outer_only",
|
||||
"inner_only", "outer_and_inner", "no_brim");
|
||||
"inner_only", "outer_and_inner", "leading_edge_only", "no_brim");
|
||||
DYNAMIC_SECTION("brim_type " << brim_type) {
|
||||
DynamicPrintConfig config = belt_brim_config();
|
||||
config.set_deserialize_strict({
|
||||
@@ -1157,6 +1157,40 @@ TEST_CASE("Every brim type slices on a belt printer", "[SkirtBrim][belt]")
|
||||
}
|
||||
}
|
||||
|
||||
// The leading-edge-only brim is the outer brim cut down to the part's first contact
|
||||
// with the belt. The cut has to be taken at the first layer with geometry: the slicing
|
||||
// frame starts at the belt below the footprint, so layers().front() is an empty lead-in
|
||||
// layer whose contact lies ahead of the part, and a cut taken there left no brim at all.
|
||||
TEST_CASE("Leading-edge-only brim is laid at the first contact and nowhere else", "[SkirtBrim][belt][Regression]")
|
||||
{
|
||||
auto brim_gcode = [](const char *brim_type) {
|
||||
DynamicPrintConfig config = belt_brim_config();
|
||||
config.set_deserialize_strict({
|
||||
{ "brim_type", brim_type },
|
||||
{ "brim_width", 5 },
|
||||
{ "leading_brim_length", 10 },
|
||||
{ "extra_brim_width", 0 },
|
||||
{ "brim_object_gap", 0 },
|
||||
});
|
||||
return slice({ cube(20) }, config);
|
||||
};
|
||||
const std::string leading = brim_gcode("leading_edge_only");
|
||||
const std::string outer = brim_gcode("outer_only");
|
||||
|
||||
const double brim_z = first_role_z(leading, "brim");
|
||||
const double peri_z = first_role_z(leading, "perimeter");
|
||||
REQUIRE(brim_z < std::numeric_limits<double>::max());
|
||||
REQUIRE(peri_z < std::numeric_limits<double>::max());
|
||||
// At the first contact: the brim starts no later than the part does...
|
||||
CHECK(brim_z <= peri_z + EPSILON);
|
||||
// ...and stops there, while the outer brim keeps following the footprint.
|
||||
const int leading_layers = role_layers(leading, "brim");
|
||||
const int outer_layers = role_layers(outer, "brim");
|
||||
INFO("brim layers: leading-edge " << leading_layers << ", outer " << outer_layers);
|
||||
CHECK(leading_layers > 0);
|
||||
CHECK(leading_layers < outer_layers);
|
||||
}
|
||||
|
||||
TEST_CASE("An untilted belt printer gets no brim", "[SkirtBrim][belt]")
|
||||
{
|
||||
// Belt brim needs a tilt to have a belt plane to lie on, and the flat plate brim
|
||||
|
||||
Reference in New Issue
Block a user