Belt: check object height against the gantry clearance again

validate() skipped the build-volume height check whenever the machine-frame
transform was active, which is every shipped belt profile, so a 400 mm
object passed on a 300 mm printable_height. The transform only changes how
the height is written to G-code; the clearance check from f682ab5cd3
applies regardless.

Raised in Hanif Koh's review of #14394.
This commit is contained in:
harrierpigeon
2026-10-02 01:07:42 -05:00
parent 97034b22f6
commit 2aa4122aae
2 changed files with 37 additions and 10 deletions
+3 -10
View File
@@ -20,7 +20,6 @@
#include "GCode.hpp"
#include "BeltGCode.hpp"
#include "BeltTransform.hpp"
#include "GCode/MachineFrameTransform.hpp"
#include "GCode/WipeTower.hpp"
#include "GCode/WipeTower2.hpp"
#include "GCode/WipeTowerEstimate.hpp"
@@ -1621,17 +1620,11 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
// is not comparable to printable_height (which is gantry clearance in the
// build-volume frame). Compare against the model's pre-shear Z instead,
// mirroring the bbox computed in PrintObject::update_slicing_parameters.
// When the post-gcode MachineFrameTransform is active the printer's
// physical Z mapping is non-trivial — skip the check entirely.
// The machine-frame transform only changes how that height is written to
// G-code, not how much room there is under the gantry.
const bool belt_printer = this->config().belt_printer.value;
bool skip_max_height_check = false;
if (belt_printer) {
MachineFrameTransform machine_frame;
machine_frame.init_from_config(this->config());
skip_max_height_check = machine_frame.is_active();
}
const double shrinkage_compensation_z = this->shrinkage_compensation().z();
for (size_t print_object_idx = 0; !skip_max_height_check && print_object_idx < m_objects.size(); ++ print_object_idx) {
for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx) {
const PrintObject &print_object = *m_objects[print_object_idx];
double effective_max_z = 0;
+34
View File
@@ -562,3 +562,37 @@ TEST_CASE("Belt printers never start a scarf seam below the layer", "[Print][bel
});
CHECK(worst_backstep < 0.2);
}
// printable_height on a belt printer is the clearance under the gantry, so an object taller
// than that is refused whatever the machine-frame transform does to the emitted coordinates.
TEST_CASE("Belt printers refuse an object taller than the gantry clearance", "[Print][belt]")
{
auto belt_config = [](double printable_height) {
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "belt_printer", 1 },
{ "belt_slice_rotation", "x" },
{ "belt_slice_rotation_angle", 45 },
{ "belt_slice_rotation_global", 1 },
{ "gcode_remap_x", "rev_x" },
{ "gcode_remap_y", "pos_z" },
{ "gcode_remap_z", "pos_y" },
{ "printable_height", printable_height },
{ "skirt_loops", 0 },
});
return config;
};
SECTION("a 20 mm cube fits under 50 mm of clearance") {
Print print;
Model model;
init_print({ cube(20) }, print, model, belt_config(50));
CHECK(print.validate().string.empty());
}
SECTION("a 60 mm cube does not") {
Print print;
Model model;
init_print({ cube(60) }, print, model, belt_config(50));
CHECK_FALSE(print.validate().string.empty());
}
}