mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 22:31:02 +00:00
Belt brim: lattice lines closer to the belt than the band fraction move uphill
With a first layer of about 0.28 mm or more at 45 degrees (or a shallower belt) the brim band is wider than one bead and its lines go on the nominal lattice. A lattice line could land where the belt is almost at the band's print_z; its flow was clamped to half a layer while the nozzle sat nearly on the belt. Such a line now moves uphill to the 0.75 fraction the single-line case uses, and a line that lands on the previous one is skipped. Ported from the Unlayered fork (patch 0007 of its belt port series, found there by fuzzing first layer heights). The fork's companion fix, restricting the brim filament to those the writer was handed (0008), is not needed here: ToolOrdering registers the brim filament on every band's layer, so the writer always has it. A test pins that with every object a flush target.
This commit is contained in:
+28
-12
@@ -1,3 +1,4 @@
|
||||
#include <limits>
|
||||
#include "BeltBrim.hpp"
|
||||
|
||||
#include "ClipperUtils.hpp"
|
||||
@@ -284,7 +285,33 @@ static void belt_brim_band_paths(const BeltBrimContext &bc,
|
||||
// must not be pooled before the flow is resolved.
|
||||
// Overshoot the region so the clip, not the line's ends, decides the extent.
|
||||
const coord_t margin = coord_t(SCALED_EPSILON) + 1;
|
||||
for (const coord_t u : us) {
|
||||
coord_t u_prev = std::numeric_limits<coord_t>::min();
|
||||
for (coord_t u : us) {
|
||||
// Nozzle-to-belt clearance for this line. Constant along the line, because the
|
||||
// belt height depends only on the shear-axis coordinate. Band-anchored lines
|
||||
// share one clearance by construction; lattice lines (shallow belts, or a first
|
||||
// layer thick enough that the band is wider than a bead) each get their own.
|
||||
//
|
||||
// A lattice line can fall where the belt is only a hair below the band's print_z.
|
||||
// The bead there would be laid scraping the belt while its flow is sized for a
|
||||
// taller cell, so it is moved uphill to the same fraction of the band the
|
||||
// single-line case uses. (The clearance is along slice Z; the real gap under the
|
||||
// nozzle is clearance x cos(tilt), 0.53 h at 45 degrees for the 0.75 fraction.)
|
||||
double clearance = uniform_clearance;
|
||||
if (clearance <= 0.) {
|
||||
const Point probe = bc.frame.from_axis == 0 ? Point(u, 0) : Point(0, u);
|
||||
clearance = print_z - bc.ctx.floor_print_z(probe);
|
||||
if (clearance < BAND_CLEARANCE_FRACTION * height) {
|
||||
clearance = BAND_CLEARANCE_FRACTION * height;
|
||||
u = scale_(bc.ctx.cutoff_u(print_z - clearance));
|
||||
}
|
||||
clearance = std::min(clearance, height);
|
||||
}
|
||||
// Two lattice lines moved to the same place are one line.
|
||||
if (u == u_prev)
|
||||
continue;
|
||||
u_prev = u;
|
||||
|
||||
Polyline line;
|
||||
if (bc.frame.from_axis == 0)
|
||||
line.points = { Point(u, coord_t(bc.region_bbox.min.y() - margin)),
|
||||
@@ -299,17 +326,6 @@ static void belt_brim_band_paths(const BeltBrimContext &bc,
|
||||
if (pieces.empty())
|
||||
continue;
|
||||
|
||||
// Nozzle-to-belt clearance for this line. Constant along the line, because the
|
||||
// belt height depends only on the shear-axis coordinate. Band-anchored lines
|
||||
// share one clearance by construction; lattice lines (shallow belts) each get
|
||||
// their own, clamped so neither end of a band yields an unprintable bead.
|
||||
double clearance = uniform_clearance;
|
||||
if (clearance <= 0.) {
|
||||
const Point probe = bc.frame.from_axis == 0 ? Point(u, 0) : Point(0, u);
|
||||
clearance = print_z - bc.ctx.floor_print_z(probe);
|
||||
clearance = std::min(std::max(clearance, 0.5 * height), height);
|
||||
}
|
||||
|
||||
// with_cross_section, not with_height: it reaches the prescribed volume while
|
||||
// KEEPING the extrusion spacing, so the bead is sized to fill exactly one
|
||||
// pitch x clearance cell of the sheet.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "test_helpers.hpp" // get access to init_print, etc
|
||||
@@ -1195,3 +1196,60 @@ TEST_CASE("Belt brim coexists with support material", "[SkirtBrim][belt]")
|
||||
REQUIRE(! gc.empty());
|
||||
CHECK(role_passes(gc, "brim") > 0);
|
||||
}
|
||||
|
||||
// With a 0.3 mm first layer at 45 degrees the brim band on the belt is wider than one bead,
|
||||
// so its lines go on the nominal lattice instead of at a fixed fraction of the band. A
|
||||
// lattice line can then land where the belt is almost at the band's print_z; it must be
|
||||
// moved uphill to the same 0.75 fraction the single-line case uses, not laid scraping the
|
||||
// belt with its flow clamped to half a layer.
|
||||
TEST_CASE("Belt brim lattice lines keep their clearance above the belt", "[SkirtBrim][belt]")
|
||||
{
|
||||
DynamicPrintConfig config = belt_brim_config();
|
||||
config.set_deserialize_strict({
|
||||
{ "layer_height", 0.3 },
|
||||
{ "initial_layer_print_height", 0.3 },
|
||||
{ "brim_type", "outer_only" },
|
||||
{ "brim_width", 4 },
|
||||
{ "brim_object_gap", 0 },
|
||||
});
|
||||
const std::string gcode = slice({ cube(20) }, config);
|
||||
|
||||
// Heights of the brim extrusions, from the ;HEIGHT: tags inside ;TYPE:Brim sections.
|
||||
std::vector<double> brim_heights;
|
||||
bool in_brim = false;
|
||||
std::istringstream lines(gcode);
|
||||
for (std::string line; std::getline(lines, line); ) {
|
||||
if (boost::starts_with(line, ";TYPE:"))
|
||||
in_brim = boost::starts_with(line, ";TYPE:Brim");
|
||||
else if (in_brim && boost::starts_with(line, ";HEIGHT:"))
|
||||
brim_heights.push_back(std::stod(line.substr(8)));
|
||||
}
|
||||
REQUIRE(! brim_heights.empty());
|
||||
for (const double h : brim_heights) {
|
||||
CHECK(h >= 0.75 * 0.3 - 1e-3);
|
||||
CHECK(h <= 0.3 + 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
// The brim prints in the object's outer wall filament even when every extrusion of the object
|
||||
// is offered to purging (flush_into_objects): the tool ordering registers the brim filament
|
||||
// itself, so the writer always knows it.
|
||||
TEST_CASE("Belt brim slices when every object is a flush target", "[SkirtBrim][belt]")
|
||||
{
|
||||
DynamicPrintConfig config = belt_brim_multifilament_config(2, {
|
||||
{ "brim_type", "outer_only" },
|
||||
{ "brim_width", 4 },
|
||||
{ "brim_object_gap", 0 },
|
||||
{ "flush_into_objects", 1 },
|
||||
{ "flush_into_infill", 1 },
|
||||
});
|
||||
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> overrides {
|
||||
{ { "extruder", 1 } }, { { "extruder", 2 } },
|
||||
};
|
||||
Print print;
|
||||
Model model;
|
||||
init_print({ cube(20), cube(20) }, print, model, config, &overrides);
|
||||
REQUIRE(print.validate().string.empty());
|
||||
const std::string out = gcode(print);
|
||||
CHECK(out.find(";TYPE:Brim") != std::string::npos);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user