mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-08 08:11:14 +00:00
Belt G-code: count only the layers that are written
collect_layers_to_print() drops the belt layers that print nothing (an object's empty lead-in), but m_layer_count still counted every object and support layer, so "total layers count", the total_layer_count placeholder and the M73 progress disagreed with the layer changes in the file. Count with the same predicate, shared through belt_object_layer_prints_something(). The by-object overload of collect_layers_to_print() now drops those layers as well, so both print sequences write the same layer changes. Dropping the empty entries per object has one more effect on multi- filament belt prints: a layer no longer selects a filament that it then prints nothing with. On belt_project.3mf (two filaments, belt purge tower) the T commands go from 472 to 106 while the extruded length per filament is unchanged; each of the removed tool changes was followed by no extrusion. The empty-layers test now runs for both print sequences and also checks "total layers count" against the layer changes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
fba8b8b029
commit
febd82f6df
+41
-11
@@ -2222,6 +2222,22 @@ void GCode::PlaceholderParserIntegration::validate_output_vector_variables()
|
||||
|
||||
// Collect pairs of object_layer + support_layer sorted by print_z.
|
||||
// object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON.
|
||||
// Belt printers: whether an object layer writes anything, its own extrusions or a belt
|
||||
// brim band riding on it. Shared by collect_layers_to_print() (which drops the layers
|
||||
// that do not) and the layer count.
|
||||
static bool belt_object_layer_prints_something(const PrintObject &object, const Layer &layer)
|
||||
{
|
||||
if (layer.has_extrusions())
|
||||
return true;
|
||||
if (object.has_belt_brim()) {
|
||||
const auto &by_layer = object.belt_brim_by_layer();
|
||||
const size_t id = layer.id();
|
||||
if (id < by_layer.size() && ! by_layer[id].empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObject& object, bool skip_empty_first_layer)
|
||||
{
|
||||
std::vector<GCode::LayerToPrint> layers_to_print;
|
||||
@@ -2378,6 +2394,17 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
||||
PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingEmptyGcodeLayers);
|
||||
}
|
||||
|
||||
// Belt printers: drop the layers that print nothing (see the by-layer overload), so
|
||||
// the by-object export writes the same layer changes as the by-layer one.
|
||||
if (object.print()->config().belt_printer.value)
|
||||
layers_to_print.erase(
|
||||
std::remove_if(layers_to_print.begin(), layers_to_print.end(), [&object](const LayerToPrint <p) {
|
||||
return ! ((ltp.object_layer != nullptr && belt_object_layer_prints_something(object, *ltp.object_layer)) ||
|
||||
(ltp.support_layer != nullptr && ltp.support_layer->has_extrusions()) ||
|
||||
(ltp.belt_brim_band != nullptr && ! ltp.belt_brim_band->fills.empty()));
|
||||
}),
|
||||
layers_to_print.end());
|
||||
|
||||
return layers_to_print;
|
||||
}
|
||||
|
||||
@@ -2448,18 +2475,13 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
||||
// moves it sees, so a gap folds every later layer into the one before it.
|
||||
if (print.config().belt_printer.value) {
|
||||
auto prints_something = [](const LayerToPrint <p) {
|
||||
if (ltp.object_layer != nullptr && ltp.object_layer->has_extrusions())
|
||||
if (ltp.object_layer != nullptr && ltp.original_object != nullptr &&
|
||||
belt_object_layer_prints_something(*ltp.original_object, *ltp.object_layer))
|
||||
return true;
|
||||
if (ltp.support_layer != nullptr && ltp.support_layer->has_extrusions())
|
||||
return true;
|
||||
if (ltp.belt_brim_band != nullptr && ! ltp.belt_brim_band->fills.empty())
|
||||
return true;
|
||||
if (ltp.object_layer != nullptr && ltp.original_object != nullptr && ltp.original_object->has_belt_brim()) {
|
||||
const auto &by_layer = ltp.original_object->belt_brim_by_layer();
|
||||
const size_t id = ltp.object_layer->id();
|
||||
if (id < by_layer.size() && ! by_layer[id].empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
layers_to_print.erase(
|
||||
@@ -3204,15 +3226,21 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
m_layer_count = 0;
|
||||
// On a belt, collect_layers_to_print() drops the layers that print nothing (an
|
||||
// object's empty lead-in), so they must not be counted here either or the layer
|
||||
// count in the file disagrees with its layer changes.
|
||||
const bool belt = print.config().belt_printer.value;
|
||||
if (print.config().print_sequence == PrintSequence::ByObject) {
|
||||
// Add each of the object's layers separately.
|
||||
for (auto object : print.objects()) {
|
||||
std::vector<coordf_t> zs;
|
||||
zs.reserve(object->layers().size() + object->support_layers().size());
|
||||
for (auto layer : object->layers())
|
||||
zs.push_back(layer->print_z);
|
||||
if (! belt || belt_object_layer_prints_something(*object, *layer))
|
||||
zs.push_back(layer->print_z);
|
||||
for (auto layer : object->support_layers())
|
||||
zs.push_back(layer->print_z);
|
||||
if (! belt || layer->has_extrusions())
|
||||
zs.push_back(layer->print_z);
|
||||
// Belt brim apron bands each get their own change_layer() call.
|
||||
for (const BeltBrimBand &band : object->belt_brim_prologue())
|
||||
zs.push_back(band.print_z);
|
||||
@@ -3232,9 +3260,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
for (auto object : print.objects()) {
|
||||
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
|
||||
for (auto layer : object->layers())
|
||||
zs.push_back(layer->print_z);
|
||||
if (! belt || belt_object_layer_prints_something(*object, *layer))
|
||||
zs.push_back(layer->print_z);
|
||||
for (auto layer : object->support_layers())
|
||||
zs.push_back(layer->print_z);
|
||||
if (! belt || layer->has_extrusions())
|
||||
zs.push_back(layer->print_z);
|
||||
// See the ByObject branch: apron bands are real printed layers.
|
||||
for (const BeltBrimBand &band : object->belt_brim_prologue())
|
||||
zs.push_back(band.print_z);
|
||||
|
||||
@@ -1362,6 +1362,9 @@ TEST_CASE("Belt G-code has no layer that prints nothing", "[Print][belt][GCode][
|
||||
{ "machine_start_gcode", "T[initial_tool]\n" },
|
||||
{ "layer_change_gcode", "G92 E0\n" },
|
||||
});
|
||||
// Both export paths drop the empty layers and count the layers the same way.
|
||||
SECTION("by layer") { config.set_deserialize_strict({{ "print_sequence", "by layer" }}); }
|
||||
SECTION("by object") { config.set_deserialize_strict({{ "print_sequence", "by object" }}); }
|
||||
Print print;
|
||||
Model model;
|
||||
TriangleMesh cube_a(its_make_cube(20., 20., 20.));
|
||||
@@ -1376,7 +1379,7 @@ TEST_CASE("Belt G-code has no layer that prints nothing", "[Print][belt][GCode][
|
||||
const std::string gc = gcode(print);
|
||||
REQUIRE(! gc.empty());
|
||||
|
||||
size_t layers = 0, empty = 0, total_header = 0;
|
||||
size_t layers = 0, empty = 0, total_header = 0, total_count = 0;
|
||||
bool extruded = true; // before the first layer change
|
||||
std::istringstream in(gc);
|
||||
std::string line;
|
||||
@@ -1387,17 +1390,24 @@ TEST_CASE("Belt G-code has no layer that prints nothing", "[Print][belt][GCode][
|
||||
++ layers;
|
||||
extruded = false;
|
||||
} else if (line.rfind("; total layer number: ", 0) == 0) {
|
||||
// Counted by the G-code processor from the layer changes it saw.
|
||||
total_header = size_t(std::atoi(line.c_str() + 22));
|
||||
} else if (line.rfind("; total layers count = ", 0) == 0) {
|
||||
// GCode::m_layer_count, counted up front from the objects' layers; it also
|
||||
// drives the M73 progress and the total_layer_count placeholder.
|
||||
total_count = size_t(std::atoi(line.c_str() + 23));
|
||||
} 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);
|
||||
INFO("layers " << layers << ", header " << total_header << ", count " << total_count
|
||||
<< ", layers without extrusion " << empty);
|
||||
CHECK(layers > 150); // both cubes, 141 layers each, overlapping along the belt
|
||||
CHECK(empty == 0);
|
||||
CHECK(total_header == layers);
|
||||
CHECK(total_count == layers);
|
||||
}
|
||||
|
||||
// A part with an overhang on its LEADING side (the end that prints first) needs
|
||||
|
||||
Reference in New Issue
Block a user