mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-03 08:12:07 +00:00
Add belt-printer regression test for start-of-print gantry move
Locks in the fix from the previous commit. A fresh BeltGCodeWriter has an unestablished planar position (is_current_position_clear() == false) and its m_pos.xy is the origin (0,0). With a pending NormalLift z-hop, travel_to_xyz used to lift in place via _travel_to_z(), which in belt mode shears the origin into a machine Y ~= the layer Z — a move far up the gantry. The test configures an X-tilt 45 deg belt transform, defers a z-hop via lazy_lift, travels to a near-belt first point (transformed gantry Y ~= 1mm), and asserts no emitted move has Y anywhere near the layer Z. Verified to fail without the fix (max emitted Y = 100.0 vs the destination's ~1.0) and pass with it.
This commit is contained in:
@@ -15,6 +15,11 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include "libslic3r/BeltGCodeWriter.hpp"
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::Test;
|
||||
@@ -847,3 +852,71 @@ TEST_CASE("Custom G-code motion limits are restored before generated moves", "[G
|
||||
REQUIRE(gcode.find("M204 S6000 ; adjust acceleration", custom_gcode_pos) != std::string::npos);
|
||||
REQUIRE(gcode.find("M205 X8 Y8 ; adjust jerk", custom_gcode_pos) != std::string::npos);
|
||||
}
|
||||
|
||||
// Regression test for the belt-printer "illegal gantry move at print start" bug.
|
||||
//
|
||||
// On a belt printer the layer-change z-hop is deferred (lazy_lift) and consumed
|
||||
// by the first travel_to_xyz, whose NormalLift branch lifts in place via
|
||||
// _travel_to_z(). On a normal printer _travel_to_z emits a Z-only move, but in
|
||||
// belt mode Z is coupled to Y/X, so _travel_to_z re-emits the current m_pos
|
||||
// through the belt shear. At print start (and after custom gcode)
|
||||
// is_current_position_clear() is false and m_pos.xy is still the uninitialised
|
||||
// origin (0,0), which shears into machine (X=bed_max, Y=layer_z) — a move far up
|
||||
// the gantry, e.g. "G1 X95 Y168.19 Z237.857". The fix guards that lift on
|
||||
// is_current_position_clear(), mirroring the SlopeLift branch.
|
||||
SCENARIO("Belt: the first travel does not lift through the uninitialised origin", "[GCodeWriter][belt]")
|
||||
{
|
||||
GIVEN("A fresh BeltGCodeWriter configured for an X-tilt 45 degree belt") {
|
||||
// Machine-frame + slicer->world back-transform config (X tilt, 45 deg).
|
||||
PrintConfig belt_config;
|
||||
belt_config.belt_printer.value = true;
|
||||
belt_config.gcode_back_transform.value = true;
|
||||
belt_config.belt_slice_rotation.value = BeltRotationAxis::X;
|
||||
belt_config.belt_slice_rotation_angle.value = 45.0;
|
||||
belt_config.belt_slice_rotation_global.value = true;
|
||||
belt_config.belt_preslice_global.value = true;
|
||||
belt_config.belt_frame_tilt_decouple.value = false;
|
||||
belt_config.belt_frame_tilt_angle.value = 45.0;
|
||||
|
||||
BeltGCodeWriter writer;
|
||||
writer.set_machine_frame_transform(belt_config);
|
||||
writer.set_belt_back_transform(belt_config);
|
||||
|
||||
std::vector<unsigned int> extruder_ids { 0 };
|
||||
writer.set_extruders(extruder_ids);
|
||||
writer.set_extruder(0);
|
||||
writer.config.travel_speed.value = 100.0;
|
||||
writer.config.z_hop.values = { 0.4 };
|
||||
writer.config.retract_lift_above.values = { 0.0 };
|
||||
writer.config.retract_lift_below.values = { 0.0 };
|
||||
|
||||
// A fresh writer has not established its planar position yet — this is the
|
||||
// precondition that made the origin leak into the first move.
|
||||
REQUIRE_FALSE(writer.is_current_position_clear());
|
||||
|
||||
WHEN("a layer-change z-hop is pending and we travel to the first object point") {
|
||||
// Defer a z-hop, exactly as a retract on layer change leaves it.
|
||||
writer.lazy_lift(LiftType::NormalLift);
|
||||
|
||||
// First object point in slicing coordinates: a near-belt point (y ~= -z)
|
||||
// so its transformed gantry Y is small (~1mm). The bogus origin lift, in
|
||||
// contrast, would shear to machine Y ~= nominal_z.
|
||||
const double nominal_z = 100.0;
|
||||
std::string gcode = writer.travel_to_xyz(Vec3d(10.0, -(nominal_z - 1.0), nominal_z));
|
||||
|
||||
THEN("no emitted move flies up the gantry; machine Y stays near the part") {
|
||||
double max_y = std::numeric_limits<double>::lowest();
|
||||
GCodeReader reader;
|
||||
reader.parse_buffer(gcode, [&max_y](GCodeReader &, const GCodeReader::GCodeLine &line) {
|
||||
if (line.cmd_is("G1") && line.has(Y))
|
||||
max_y = std::max(max_y, double(line.y()));
|
||||
});
|
||||
// The destination shears to machine Y ~= 1mm. The old origin-lift bug
|
||||
// produced a separate move at machine Y ~= nominal_z (100mm), so any
|
||||
// Y well above the part means the origin leaked into a move.
|
||||
REQUIRE(max_y > 0.0); // the destination move was emitted and parsed
|
||||
REQUIRE(max_y < 10.0); // ... and nothing flew up the gantry
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user