mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
Belt printer: no layer changes that print nothing, and a preview that survives them
Since the slicing frame of a belt object starts at the belt below its leading end, its first layers are empty. On a single part they carry the brim bands; with several parts along the belt the later parts' empty layers fall between the earlier parts' printing layers and were written to the G-code as layer changes with no moves at all. The preview numbers its layers (libvgcode::Layers) from the vertices it is given and expects consecutive ids, so at the first such gap it stopped creating layers and folded everything after it into the last one: the top slider layer held nearly the whole print, the slider jumped every other layer through the single-colour stretch before a second part on another filament, and with the belt purge tower the whole print greyed out while dragging. Drop the belt layers that print nothing (no object, support or brim content) in GCode::collect_layers_to_print, and renumber the layers consecutively over the moves that exist when converting a result for libvgcode, so a file with empty layers from any source still previews correctly. The layer slider labels a belt layer with its print Z (the slicer's layer Z, which increases along the belt) instead of libvgcode's toolpath height, which on a tilted layer is wherever its last extrusion ended; the slider assumes that list increases and showed "0 / max" on alternate layers. The processor reads that print Z from the ";Z:" tag non-BBL printers write (it only knew "; Z_HEIGHT:"), on belt printers only, so nothing changes elsewhere. Regression test: two cubes 60 mm apart along the belt produce no layer without an extrusion and the header's layer count matches. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
6927475499
commit
f64b49ab52
@@ -1244,6 +1244,68 @@ TEST_CASE("Organic tree supports place a support blocker at its own height above
|
||||
CHECK(collides(last + num_raft));
|
||||
}
|
||||
|
||||
// Two parts along the belt: the second part's slicing frame starts at the belt
|
||||
// below its leading end, so its first layers are empty and interleave with the
|
||||
// first part's printing layers. Those must not reach the G-code as layer changes
|
||||
// that print nothing: the preview numbers its layers from the moves it sees, and
|
||||
// a gap folded every later layer into the one before it.
|
||||
TEST_CASE("Belt G-code has no layer that prints nothing", "[Print][belt][GCode][Regression]")
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({
|
||||
{ "belt_printer", 1 },
|
||||
{ "belt_slice_rotation", "x" },
|
||||
{ "belt_slice_rotation_angle", 45 },
|
||||
{ "gcode_remap_x", "rev_x" },
|
||||
{ "gcode_remap_y", "pos_z" },
|
||||
{ "gcode_remap_z", "pos_y" },
|
||||
{ "layer_height", 0.2 },
|
||||
{ "initial_layer_print_height", 0.2 },
|
||||
{ "skirt_loops", 0 },
|
||||
{ "z_hop", 0 },
|
||||
{ "brim_type", "outer_only" },
|
||||
{ "brim_width", 4 },
|
||||
{ "machine_start_gcode", "T[initial_tool]\n" },
|
||||
{ "layer_change_gcode", "G92 E0\n" },
|
||||
});
|
||||
Print print;
|
||||
Model model;
|
||||
TriangleMesh cube_a(its_make_cube(20., 20., 20.));
|
||||
TriangleMesh cube_b(its_make_cube(20., 20., 20.));
|
||||
init_print({ cube_a, cube_b }, print, model, config);
|
||||
// 60 mm apart along the belt: the second cube's lead-in layers fall among the
|
||||
// first cube's layers.
|
||||
model.objects[0]->instances.front()->set_offset(Vec3d(50., 40., 0.));
|
||||
model.objects[1]->instances.front()->set_offset(Vec3d(50., 100., 0.));
|
||||
print.apply(model, config);
|
||||
print.set_status_silent();
|
||||
const std::string gc = gcode(print);
|
||||
REQUIRE(! gc.empty());
|
||||
|
||||
size_t layers = 0, empty = 0, total_header = 0;
|
||||
bool extruded = true; // before the first layer change
|
||||
std::istringstream in(gc);
|
||||
std::string line;
|
||||
auto close_layer = [&]() { if (! extruded) ++ empty; };
|
||||
while (std::getline(in, line)) {
|
||||
if (line.rfind(";LAYER_CHANGE", 0) == 0) {
|
||||
close_layer();
|
||||
++ layers;
|
||||
extruded = false;
|
||||
} else if (line.rfind("; total layer number: ", 0) == 0) {
|
||||
total_header = size_t(std::atoi(line.c_str() + 22));
|
||||
} else if (! extruded && line.rfind("G1 ", 0) == 0 && line.find('E') != std::string::npos
|
||||
&& (line.find('X') != std::string::npos || line.find('Y') != std::string::npos)) {
|
||||
extruded = true;
|
||||
}
|
||||
}
|
||||
close_layer();
|
||||
INFO("layers " << layers << ", header " << total_header << ", layers without extrusion " << empty);
|
||||
CHECK(layers > 150); // both cubes, 141 layers each, overlapping along the belt
|
||||
CHECK(empty == 0);
|
||||
CHECK(total_header == layers);
|
||||
}
|
||||
|
||||
// A part with an overhang on its LEADING side (the end that prints first) needs
|
||||
// supports below the object's own lowest slicing layer: the belt under that overhang
|
||||
// is reached before the object's first contact with it, so the support layers sit at
|
||||
|
||||
Reference in New Issue
Block a user