From 8039d4d2acae4ca22894db268da066a8d7548657 Mon Sep 17 00:00:00 2001 From: harrierpigeon Date: Tue, 6 Oct 2026 18:14:34 -0500 Subject: [PATCH] Belt printer: retire the redundant and unused options Removed, with the keys added to handle_legacy()'s ignore list so saved profiles and 3MFs keep loading: - belt_slice_rotation_global and preslice_remap_global. Both were only consulted when belt_preslice_global ("Global mesh transforms") was off, which no profile does; belt_preslice_global is now the single global mode and is presumed on everywhere the old flags were ORed in (PrintObjectSlice, BeltBackTransform, BeltGCode, Print::process, PrintApply). The Belt tilt row is axis + angle only. - preslice_remap_x/y/z. No profile used the pre-slice axis remap; the belt tilt axis plus the G-code axis remap cover the machines that exist, and its implementation only agreed with itself for a plain swap (matrix columns vs remap_bbox rows). BeltTransformPipeline::build_preslice_remap, remap_bbox and has_preslice_remap are gone, the forward transform is the rotation, and the G-code header no longer carries the remap. - belt_support_z_offset_mode. Saved and invalidated steps, but no support generator read it. - first_layer_plane and first_layer_plane_offset, with FirstLayerPlane.cpp. On every shipped configuration the band is measured from the belt surface (GCode::belt_height_above_floor) and the evaluator was only reached for an explicit XY/YZ/XZ choice or a non-zero offset, which nobody set. first_layer_plane_thickness stays as the band unit, relabelled "First layer band thickness". UI: the Machine frame transforms group is five single-option rows (G-code remap X / Y / Z, Decouple machine-frame tilt, Machine-frame tilt angle; the angle row is shown only when decoupled) instead of two multi-column lines, and the remap fields carry full labels. Also carries the phong.fs struct fix from #16226 so the worktree build links its shaders. libslic3r_tests and fff_print_tests pass; clang-tidy diff check clean; orca_profile_tool.py check clean. Co-Authored-By: Claude Fable 5.1 --- .../Custom/machine/fdm_belt_common.json | 1 - .../IdeaFormer/machine/fdm_belt_common.json | 1 - .../Printcepts/machine/fdm_belt_common.json | 1 - resources/shaders/110/phong.fs | 1 + resources/shaders/140/phong.fs | 1 + src/libslic3r/BeltGCode.cpp | 31 +-- src/libslic3r/BeltSliceStrategy.cpp | 11 +- src/libslic3r/BeltTransform.cpp | 97 +------- src/libslic3r/BeltTransform.hpp | 58 +---- src/libslic3r/CMakeLists.txt | 2 - src/libslic3r/FirstLayerPlane.cpp | 229 ------------------ src/libslic3r/FirstLayerPlane.hpp | 76 ------ src/libslic3r/GCode.cpp | 72 +----- src/libslic3r/GCode.hpp | 43 +--- src/libslic3r/GCode/BeltBackTransform.cpp | 12 +- src/libslic3r/GCode/BeltBackTransform.hpp | 16 +- src/libslic3r/GCode/GCodeProcessor.cpp | 36 +-- src/libslic3r/GCode/GCodeProcessor.hpp | 6 - src/libslic3r/Preset.cpp | 7 +- src/libslic3r/Print.cpp | 22 +- src/libslic3r/Print.hpp | 7 +- src/libslic3r/PrintApply.cpp | 13 +- src/libslic3r/PrintConfig.cpp | 136 ++--------- src/libslic3r/PrintConfig.hpp | 38 --- src/libslic3r/PrintObject.cpp | 7 +- src/libslic3r/PrintObjectSlice.cpp | 47 +--- src/slic3r/GUI/GCodeViewer.cpp | 7 +- src/slic3r/GUI/Tab.cpp | 87 ++----- tests/fff_print/test_gcodewriter.cpp | 2 - tests/fff_print/test_precise_seam.cpp | 1 - tests/fff_print/test_print.cpp | 17 +- tests/fff_print/test_skirt_brim.cpp | 4 - 32 files changed, 125 insertions(+), 964 deletions(-) delete mode 100644 src/libslic3r/FirstLayerPlane.cpp delete mode 100644 src/libslic3r/FirstLayerPlane.hpp diff --git a/resources/profiles/Custom/machine/fdm_belt_common.json b/resources/profiles/Custom/machine/fdm_belt_common.json index 19765b8d4e..96b3138832 100644 --- a/resources/profiles/Custom/machine/fdm_belt_common.json +++ b/resources/profiles/Custom/machine/fdm_belt_common.json @@ -88,7 +88,6 @@ "belt_printer": "1", "belt_slice_rotation": "x", "belt_slice_rotation_angle": "45", - "belt_slice_rotation_global": "1", "build_plate_tilt_x": "45", "purge_in_prime_tower": "0", "scan_first_layer": "0", diff --git a/resources/profiles/IdeaFormer/machine/fdm_belt_common.json b/resources/profiles/IdeaFormer/machine/fdm_belt_common.json index 60ef096de0..aacd36e118 100644 --- a/resources/profiles/IdeaFormer/machine/fdm_belt_common.json +++ b/resources/profiles/IdeaFormer/machine/fdm_belt_common.json @@ -91,7 +91,6 @@ "belt_printer": "1", "belt_slice_rotation": "x", "belt_slice_rotation_angle": "45", - "belt_slice_rotation_global": "1", "build_plate_tilt_x": "45", "purge_in_prime_tower": "0", "scan_first_layer": "0", diff --git a/resources/profiles/Printcepts/machine/fdm_belt_common.json b/resources/profiles/Printcepts/machine/fdm_belt_common.json index 2a392b4f60..96d38ac31a 100644 --- a/resources/profiles/Printcepts/machine/fdm_belt_common.json +++ b/resources/profiles/Printcepts/machine/fdm_belt_common.json @@ -91,7 +91,6 @@ "belt_printer": "1", "belt_slice_rotation": "x", "belt_slice_rotation_angle": "45", - "belt_slice_rotation_global": "1", "build_plate_tilt_x": "45", "purge_in_prime_tower": "0", "scan_first_layer": "0", diff --git a/resources/shaders/110/phong.fs b/resources/shaders/110/phong.fs index a47a24fdea..7d1e7bfe8c 100644 --- a/resources/shaders/110/phong.fs +++ b/resources/shaders/110/phong.fs @@ -41,6 +41,7 @@ struct SlopeDetection bool actived; float normal_z; mat3 volume_world_normal_matrix; + vec3 up_direction; }; uniform vec4 uniform_color; diff --git a/resources/shaders/140/phong.fs b/resources/shaders/140/phong.fs index 809621b76d..4cfae1e03e 100644 --- a/resources/shaders/140/phong.fs +++ b/resources/shaders/140/phong.fs @@ -44,6 +44,7 @@ struct SlopeDetection bool actived; float normal_z; mat3 volume_world_normal_matrix; + vec3 up_direction; }; uniform vec4 uniform_color; diff --git a/src/libslic3r/BeltGCode.cpp b/src/libslic3r/BeltGCode.cpp index a78c0cbfa6..45b0728810 100644 --- a/src/libslic3r/BeltGCode.cpp +++ b/src/libslic3r/BeltGCode.cpp @@ -25,12 +25,6 @@ void BeltGCode::write_belt_header(GCodeOutputStream &file, const Print &print) // for the physical tilt the G-code viewer uses to enable belt view. file.write_format("; belt_slice_rotation = %s\n", full_cfg.opt_serialize("belt_slice_rotation").c_str()); file.write_format("; belt_slice_rotation_angle = %.1f\n", print.config().belt_slice_rotation_angle.value); - file.write_format("; belt_slice_rotation_global = %d\n", print.config().belt_slice_rotation_global.value ? 1 : 0); - // Pre-slice remap configs - file.write_format("; preslice_remap_x = %s\n", full_cfg.opt_serialize("preslice_remap_x").c_str()); - file.write_format("; preslice_remap_y = %s\n", full_cfg.opt_serialize("preslice_remap_y").c_str()); - file.write_format("; preslice_remap_z = %s\n", full_cfg.opt_serialize("preslice_remap_z").c_str()); - file.write_format("; preslice_remap_global = %d\n", print.config().preslice_remap_global.value ? 1 : 0); file.write_format("; belt_preslice_global = %d\n", print.config().belt_preslice_global.value ? 1 : 0); // Machine-frame transform: shear (tan) + scale (1/cos) derived from the belt // tilt angle (or belt_frame_tilt_angle when decoupled). @@ -40,25 +34,12 @@ void BeltGCode::write_belt_header(GCodeOutputStream &file, const Print &print) void BeltGCode::on_set_origin(const PrintObject * /*obj*/, const Point & /*inst_shift*/) { - // Global pre-slice mode: adjust origin using computed correction. - // Transform the origin through the belt pipeline so that - // back_transform(T * origin) = origin (correct machine position). - // - // Flags that trigger this path: - // belt_preslice_global — full pipeline (rotation * remap) is global - // preslice_remap_global — only the pre-slice remap is global - // belt_slice_rotation_global — slicing rotation treated as global (matches - // the per-instance Z-offset added in PrintObjectSlice.cpp) - // The XY origin adjustment uses the FULL forward transform, because the - // back_transform applied during G-code emission is always the inverse of - // the full pipeline. - bool use_global = m_config.belt_preslice_global.value - || (m_config.preslice_remap_global.value - && BeltTransformPipeline::has_preslice_remap(m_config)) - || (m_config.belt_slice_rotation_global.value - && m_config.belt_slice_rotation.value != BeltRotationAxis::None - && std::abs(m_config.belt_slice_rotation_angle.value) > EPSILON); - if (!use_global) + // Global pre-slice mode (matches the per-instance Z-offset added in + // PrintObjectSlice.cpp): transform the origin through the belt pipeline so + // that back_transform(T * origin) = origin (correct machine position). The + // back_transform applied during G-code emission is the inverse of the + // forward transform. + if (!m_config.belt_preslice_global.value) return; // Adjust origin: transform through belt forward pipeline so that diff --git a/src/libslic3r/BeltSliceStrategy.cpp b/src/libslic3r/BeltSliceStrategy.cpp index 8892b4e5de..aa01c3ca9e 100644 --- a/src/libslic3r/BeltSliceStrategy.cpp +++ b/src/libslic3r/BeltSliceStrategy.cpp @@ -14,12 +14,7 @@ void BeltSliceStrategy::apply_preslice_transforms(Transform3d &trafo, const ModelVolumePtrs &model_volumes, double *out_belt_min_z) { - // 1. Standalone pre-slice axis remap (works without belt mode). - const bool has_remap = BeltTransformPipeline::has_preslice_remap(config); - if (has_remap) - trafo = BeltTransformPipeline::build_preslice_remap(config) * trafo; - - // 2. Belt rotation — the sole mesh-side belt transform (matching + // 1. Belt rotation — the sole mesh-side belt transform (matching // BeltTransformPipeline::build_forward_transform). Only active in // belt-printer mode. bool has_rotation = false; @@ -32,10 +27,10 @@ void BeltSliceStrategy::apply_preslice_transforms(Transform3d &trafo, } } - if (!has_remap && !has_rotation) + if (!has_rotation) return; - // 3. Z-shift — detect if the mesh clips below the build plate after the + // 2. Z-shift — detect if the mesh clips below the build plate after the // transforms and lift it. Each mesh vertex must be brought into object space // via mv->get_matrix() before applying the full trafo (which is in object // space). Missing this on assemblies (where per-volume get_matrix() positions diff --git a/src/libslic3r/BeltTransform.cpp b/src/libslic3r/BeltTransform.cpp index d1ea31d33c..168d9cde1c 100644 --- a/src/libslic3r/BeltTransform.cpp +++ b/src/libslic3r/BeltTransform.cpp @@ -16,50 +16,6 @@ namespace Slic3r { // ---- Matrix builders ------------------------------------------------------ -Transform3d BeltTransformPipeline::build_preslice_remap(const PrintConfig &config) -{ - Transform3d pre_remap = Transform3d::Identity(); - if (!has_preslice_remap(config)) - return pre_remap; - - int pre_rx = int(config.preslice_remap_x.value); - int pre_ry = int(config.preslice_remap_y.value); - int pre_rz = int(config.preslice_remap_z.value); - - // Each remap value selects a source axis and sign. - auto remap_column = [](int r) -> Vec3d { - int axis = r % 3; - Vec3d col = Vec3d::Zero(); - if (r < 3) col[axis] = 1.0; // +axis - else if (r < 6) col[axis] = -1.0; // -axis - else col[axis] = -1.0; // Rev: max - pos = -(pos - max) - return col; - }; - - Matrix3d remap_lin; - remap_lin.col(0) = remap_column(pre_rx); - remap_lin.col(1) = remap_column(pre_ry); - remap_lin.col(2) = remap_column(pre_rz); - pre_remap.linear() = remap_lin; - - // Translation for Rev modes (needs build volume extents). - if (pre_rx >= 6 || pre_ry >= 6 || pre_rz >= 6) { - BoundingBoxf bbox_bed(config.printable_area.values); - Vec3d vol_max(bbox_bed.max.x(), bbox_bed.max.y(), - config.printable_height.value); - Vec3d remap_trans = Vec3d::Zero(); - auto add_rev = [&](int r, int out) { - if (r >= 6) remap_trans[out] = vol_max[r % 3]; - }; - add_rev(pre_rx, 0); - add_rev(pre_ry, 1); - add_rev(pre_rz, 2); - pre_remap.translation() = remap_trans; - } - - return pre_remap; -} - Matrix3d BeltTransformPipeline::build_rotation_matrix(const PrintConfig &config, bool *has_rot_out) { BeltRotationAxis axis = config.belt_slice_rotation.value; @@ -81,52 +37,13 @@ Matrix3d BeltTransformPipeline::build_rotation_matrix(const PrintConfig &config, Transform3d BeltTransformPipeline::build_forward_transform(const PrintConfig &config) { - // Mesh-side belt transform: rotation applied after the pre-slice axis remap. - // (Shear & scale are a g-code-side stage, not part of the mesh transform.) - Transform3d pre_remap = build_preslice_remap(config); - Matrix3d rot = build_rotation_matrix(config); - + // Mesh-side belt transform: the rotation. (Shear & scale are a g-code-side + // stage, not part of the mesh transform.) Transform3d combined = Transform3d::Identity(); - combined.linear() = rot; - combined = combined * pre_remap; + combined.linear() = build_rotation_matrix(config); return combined; } -// ---- Bounding box remap --------------------------------------------------- - -BoundingBoxf3 BeltTransformPipeline::remap_bbox(const BoundingBoxf3 &bb, const PrintConfig &config) -{ - if (!has_preslice_remap(config)) - return bb; // Identity remap, or belt mode off. - - int pre_rx = int(config.preslice_remap_x.value); - int pre_ry = int(config.preslice_remap_y.value); - int pre_rz = int(config.preslice_remap_z.value); - - auto remap_coord = [](int r, const Vec3d &v) -> double { - int axis = r % 3; - if (r < 3) return v[axis]; - return -v[axis]; - }; - - Vec3d mn = bb.min.cast(), mx = bb.max.cast(); - BoundingBoxf3 rbb; - for (int i = 0; i < 8; ++i) { - Vec3d c((i & 1) ? mx.x() : mn.x(), - (i & 2) ? mx.y() : mn.y(), - (i & 4) ? mx.z() : mn.z()); - Vec3d rc(remap_coord(pre_rx, c), remap_coord(pre_ry, c), remap_coord(pre_rz, c)); - if (i == 0) rbb = BoundingBoxf3(rc, rc); - else rbb.merge(rc); - } - return rbb; -} - -BoundingBoxf3 BeltTransformPipeline::remap_bbox(const ModelObject &model_object, const PrintConfig &config) -{ - return remap_bbox(model_object.raw_bounding_box(), config); -} - // ---- Belt floor parameters ------------------------------------------------ // Shared implementation for both PrintConfig and DynamicPrintConfig. @@ -216,15 +133,15 @@ BeltTransformPipeline::BeltHeightResult compute_belt_height_and_floor_impl( } // anonymous namespace BeltTransformPipeline::BeltHeightResult BeltTransformPipeline::compute_belt_height_and_floor( - const PrintConfig &config, const BoundingBoxf3 &remapped_bbox, double original_height) + const PrintConfig &config, const BoundingBoxf3 &bbox, double original_height) { - return compute_belt_height_and_floor_impl(config, remapped_bbox, original_height); + return compute_belt_height_and_floor_impl(config, bbox, original_height); } BeltTransformPipeline::BeltHeightResult BeltTransformPipeline::compute_belt_height_and_floor( - const DynamicPrintConfig &config, const BoundingBoxf3 &remapped_bbox, double original_height) + const DynamicPrintConfig &config, const BoundingBoxf3 &bbox, double original_height) { - return compute_belt_height_and_floor_impl(config, remapped_bbox, original_height); + return compute_belt_height_and_floor_impl(config, bbox, original_height); } } // namespace Slic3r diff --git a/src/libslic3r/BeltTransform.hpp b/src/libslic3r/BeltTransform.hpp index 59669fe36a..01346464ae 100644 --- a/src/libslic3r/BeltTransform.hpp +++ b/src/libslic3r/BeltTransform.hpp @@ -16,7 +16,7 @@ class ModelObject; // Shared belt-printer transform math. // // The pre-slice pipeline applied in PrintObjectSlice.cpp is: -// trafo_out = z_shift * rotation * pre_remap * trafo_in +// trafo_out = z_shift * rotation * trafo_in // // Rotation is the sole mesh-side belt transform; shear & scale are applied // to the g-code instead (see MachineFrameTransform). This class provides the @@ -47,39 +47,11 @@ class BeltTransformPipeline public: // ---- Identity checks -------------------------------------------------- - // Whether the axis remaps (preslice_remap_* and gcode_remap_*) apply at all. - // The remap fields are only offered in the belt printer group, so a value - // left in a profile must not change a non-belt print: with belt mode off every - // belt-only key is a no-op. This is the one place to widen if a non-belt use - // ever needs them. + // Whether the G-code axis remap applies at all. The remap fields are only + // offered in the belt printer group, so a value left in a profile must not + // change a non-belt print: with belt mode off every belt-only key is a no-op. + // This is the one place to widen if a non-belt use ever needs them. static bool axis_remap_enabled(const PrintConfig &config) { return config.belt_printer.value; } - static bool axis_remap_enabled(const DynamicPrintConfig &config) - { - auto *opt = config.option("belt_printer"); - return opt != nullptr && opt->value; - } - - static bool has_preslice_remap(const PrintConfig &config) - { - return axis_remap_enabled(config) && - (int(config.preslice_remap_x.value) != int(RemapAxis::PosX) || - int(config.preslice_remap_y.value) != int(RemapAxis::PosY) || - int(config.preslice_remap_z.value) != int(RemapAxis::PosZ)); - } - - // Overload accepting DynamicPrintConfig (used in static slicing_parameters). - static bool has_preslice_remap(const DynamicPrintConfig &config) - { - if (! axis_remap_enabled(config)) - return false; - auto get_int = [&](const char *key) -> int { - auto *opt = config.option>(key); - return opt ? int(opt->value) : 0; - }; - return get_int("preslice_remap_x") != int(RemapAxis::PosX) || - get_int("preslice_remap_y") != int(RemapAxis::PosY) || - get_int("preslice_remap_z") != int(RemapAxis::PosZ); - } static bool has_rotation(const PrintConfig &config) { @@ -118,26 +90,16 @@ public: // ---- Matrix builders -------------------------------------------------- - // Build the pre-slice axis remap transform (includes Rev-mode translation). - static Transform3d build_preslice_remap(const PrintConfig &config); - // Build the 3x3 rotation matrix from belt_slice_rotation* config. // Returns Identity if rotation axis is None or angle is ~0. // Also sets has_rot_out if non-null. static Matrix3d build_rotation_matrix(const PrintConfig &config, bool *has_rot_out = nullptr); - // Combined forward transform (rotation * pre_remap) — the mesh-side belt - // transform that BeltSliceStrategy applies and BeltBackTransform inverts. + // Forward transform (the rotation) — the mesh-side belt transform that + // BeltSliceStrategy applies and BeltBackTransform inverts. // Does NOT include the per-object Z-shift. static Transform3d build_forward_transform(const PrintConfig &config); - // ---- Bounding box remap ----------------------------------------------- - - // Remap a bounding box through the pre-slice axis remap. - // Returns the original bbox if remap is identity. - static BoundingBoxf3 remap_bbox(const BoundingBoxf3 &bb, const PrintConfig &config); - static BoundingBoxf3 remap_bbox(const ModelObject &model_object, const PrintConfig &config); - // ---- Belt floor parameters -------------------------------------------- struct BeltFloorParams { @@ -153,15 +115,15 @@ public: }; // Compute effective object height and belt floor parameters from config - // and pre-remapped bounding box. original_height is the input height + // and the object's bounding box. original_height is the input height // (bb.size().z() or model_object.max_z()). static BeltHeightResult compute_belt_height_and_floor( - const PrintConfig &config, const BoundingBoxf3 &remapped_bbox, + const PrintConfig &config, const BoundingBoxf3 &bbox, double original_height); // Overload for DynamicPrintConfig (used by static slicing_parameters). static BeltHeightResult compute_belt_height_and_floor( - const DynamicPrintConfig &config, const BoundingBoxf3 &remapped_bbox, + const DynamicPrintConfig &config, const BoundingBoxf3 &bbox, double original_height); }; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 68a1434699..a108588f84 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -94,8 +94,6 @@ set(lisbslic3r_sources BeltSliceStrategy.hpp BeltTransform.cpp BeltTransform.hpp - FirstLayerPlane.cpp - FirstLayerPlane.hpp Brim.cpp BrimEarsPoint.hpp Brim.hpp diff --git a/src/libslic3r/FirstLayerPlane.cpp b/src/libslic3r/FirstLayerPlane.cpp deleted file mode 100644 index 7642d42267..0000000000 --- a/src/libslic3r/FirstLayerPlane.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "FirstLayerPlane.hpp" -#include "BeltTransform.hpp" -#include "BoundingBox.hpp" -#include "Point.hpp" -#include "PrintConfig.hpp" -#include "libslic3r.h" - -#include -#include -#include - -namespace Slic3r { - -namespace { - -// Build the row of the gcode-axis-remap matrix R that produces machine_Z, -// AS A FUNCTION OF a slicing-frame point in the GCode generator's coordinate -// space. Without back-transform this is just R.row(2). With back-transform -// the writer applies F^-1 before R, so the effective row is (R * F^-1).row(2). -// -// Returns a pair (gradient, constant) such that: -// machine_Z(p_slicing) = gradient.dot(p_slicing) + constant -struct MachineZAffine { - Vec3d gradient = Vec3d::UnitZ(); - double constant = 0.0; -}; - -MachineZAffine compute_machine_z_affine(const PrintConfig &config) -{ - MachineZAffine out; - - // R is the matrix form of GCodeWriter::apply_axis_remap. Each output axis - // i picks one slicing-frame component (with sign + optional Rev mode - // translation) based on m_remap_{x,y,z}. We only need row 2 (the z output) - // since machine_Z is what defines the first-layer plane. - int rz = int(config.gcode_remap_z.value); - int axis = rz % 3; - double sign; - double trans; - if (rz < int(RemapAxis::NegX)) { // 0..2 = PosX/Y/Z - sign = 1.0; - trans = 0.0; - } else if (rz < int(RemapAxis::RevX)) { // 3..5 = NegX/Y/Z - sign = -1.0; - trans = 0.0; - } else { // 6..8 = RevX/Y/Z - sign = -1.0; - BoundingBoxf bbox_bed(config.printable_area.values); - Vec3d vol_max(bbox_bed.max.x(), - bbox_bed.max.y(), - config.printable_height.value); - trans = vol_max[axis]; - } - - Vec3d r_row = Vec3d::Zero(); - r_row[axis] = sign; - - // Without back-transform, machine_Z(slicing) = r_row · slicing + trans. - out.gradient = r_row; - out.constant = trans; - - if (config.gcode_back_transform.value && config.belt_printer.value) { - // BeltKinematics applies F^-1 before R when back-transform is on. - // So machine_Z(slicing) = r_row · (F^-1 · slicing) + trans - // = (r_row^T · F^-1) · slicing + trans - // We need to compose r_row with F^-1 from the LEFT (treating r_row as - // a row vector). Eigen makes this easy: it's just F^-1.transpose() * r_row. - Transform3d forward = BeltTransformPipeline::build_forward_transform(config); - Transform3d inverse = forward.inverse(); - // Note: forward.translation() is normally zero (per-print transforms - // don't add a translation; the per-object z_shift is added separately - // in PrintObjectSlice). We still incorporate inverse.translation() in - // case a Rev-mode preslice_remap puts a translation in F. - Vec3d composed_grad = inverse.linear().transpose() * r_row; - double composed_trans = - r_row.dot(inverse.translation()) + trans; - out.gradient = composed_grad; - out.constant = composed_trans; - } - - return out; -} - -} // namespace - -FirstLayerPlane::FirstLayerPlane(const PrintConfig &config) -{ - // -------- Resolve Auto ------------------------------------------------- - FirstLayerPlaneMode mode = config.first_layer_plane.value; - if (mode == FirstLayerPlaneMode::Auto) { - bool belt_affine_active = config.belt_printer.value && - config.belt_slice_rotation.value != BeltRotationAxis::None && - std::abs(config.belt_slice_rotation_angle.value) > EPSILON; - mode = belt_affine_active ? FirstLayerPlaneMode::BeltAffine - : FirstLayerPlaneMode::XY; - } - m_mode = mode; - - // -------- Band thickness ---------------------------------------------- - // Note: layer_height lives in PrintObjectConfig, not PrintConfig, so we - // can't fall back to it from here. initial_layer_print_height is in - // PrintConfig and is the right default anyway (the legacy first-layer - // semantics used initial_layer_print_height, not the regular one). - double thickness = config.first_layer_plane_thickness.value; - if (thickness <= 0.0) - thickness = config.initial_layer_print_height.value; - if (thickness <= 0.0) - thickness = 0.2; - m_thickness_mm = thickness; - - const double user_offset = config.first_layer_plane_offset.value; - - // -------- Build the plane --------------------------------------------- - auto set_axis_aligned = [&](const Vec3d &n_unit, double offset_along_n) { - m_normal = n_unit; - m_offset = offset_along_n; - }; - - switch (mode) { - case FirstLayerPlaneMode::XY: - // Legacy XY plane. Inactive: short-circuit to layer-index path. - set_axis_aligned(Vec3d::UnitZ(), user_offset); - m_active = false; - return; - - case FirstLayerPlaneMode::YZ: - set_axis_aligned(Vec3d::UnitX(), user_offset); - m_active = true; - return; - - case FirstLayerPlaneMode::XZ: - set_axis_aligned(Vec3d::UnitY(), user_offset); - m_active = true; - return; - - case FirstLayerPlaneMode::BeltAffine: { - // Compute the slicing-frame plane that maps to machine_Z = user_offset - // under the gcode axis remap (and optional back-transform). - MachineZAffine mz = compute_machine_z_affine(config); - double cmag = mz.gradient.norm(); - if (cmag < EPSILON) { - // Degenerate: slicing point doesn't affect machine_Z. Fall back. - set_axis_aligned(Vec3d::UnitZ(), user_offset); - m_active = false; - return; - } - // Plane equation: gradient · slicing = user_offset - constant - const double K = user_offset - mz.constant; - m_normal = mz.gradient / cmag; - m_offset = K / cmag; - m_active = true; - return; - } - - case FirstLayerPlaneMode::Auto: - // Should have been resolved above. - m_active = false; - return; - } - - m_active = false; -} - -double FirstLayerPlane::distance_from_plane(const Vec3d &point_slicing_mm) const -{ - return m_normal.dot(point_slicing_mm) - m_offset; -} - -bool FirstLayerPlane::is_first_layer(const Vec3d &point_slicing_mm, - double first_layer_height_mm) const -{ - if (!m_active) - return false; - return distance_from_plane(point_slicing_mm) < first_layer_height_mm; -} - -int FirstLayerPlane::effective_layer_index(const Vec3d &point_slicing_mm) const -{ - if (!m_active) - return INT_MAX / 2; // Effectively "way past first layer". - double d = distance_from_plane(point_slicing_mm); - if (d <= 0.0) - return 0; - return int(std::floor(d / m_thickness_mm)); -} - -int FirstLayerPlane::min_effective_index_for_xy_bbox( - const BoundingBoxf &xy_bbox_mm, double slicing_z_mm) const -{ - if (!m_active) - return INT_MAX / 2; - // For the rectangular bbox in (x, y) at fixed z, the smallest value of - // (n.x*x + n.y*y + n.z*z - offset) is achieved at one of the four - // corners, with the smaller component picked when the corresponding - // normal coefficient is positive. - const double x_for_min = (m_normal.x() >= 0.0) - ? xy_bbox_mm.min.x() : xy_bbox_mm.max.x(); - const double y_for_min = (m_normal.y() >= 0.0) - ? xy_bbox_mm.min.y() : xy_bbox_mm.max.y(); - const double dmin = m_normal.x() * x_for_min - + m_normal.y() * y_for_min - + m_normal.z() * slicing_z_mm - - m_offset; - if (dmin <= 0.0) - return 0; - return int(std::floor(dmin / m_thickness_mm)); -} - -int FirstLayerPlane::min_effective_index_for_bbox3( - const BoundingBoxf3 &bbox_mm) const -{ - if (!m_active) - return INT_MAX / 2; - const double x_for_min = (m_normal.x() >= 0.0) - ? bbox_mm.min.x() : bbox_mm.max.x(); - const double y_for_min = (m_normal.y() >= 0.0) - ? bbox_mm.min.y() : bbox_mm.max.y(); - const double z_for_min = (m_normal.z() >= 0.0) - ? bbox_mm.min.z() : bbox_mm.max.z(); - const double dmin = m_normal.x() * x_for_min - + m_normal.y() * y_for_min - + m_normal.z() * z_for_min - - m_offset; - if (dmin <= 0.0) - return 0; - return int(std::floor(dmin / m_thickness_mm)); -} - -} // namespace Slic3r diff --git a/src/libslic3r/FirstLayerPlane.hpp b/src/libslic3r/FirstLayerPlane.hpp deleted file mode 100644 index 35b8346c82..0000000000 --- a/src/libslic3r/FirstLayerPlane.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef slic3r_FirstLayerPlane_hpp_ -#define slic3r_FirstLayerPlane_hpp_ - -#include "libslic3r.h" -#include "Point.hpp" -#include "BoundingBox.hpp" -#include "PrintConfig.hpp" - -namespace Slic3r { - -// Decides which extrusions get "first layer" treatment (no fan, slow speed, -// initial-layer accel/jerk, deferred temperature drop) by reference to a -// configurable plane in slicing-frame coordinates rather than the slicing -// layer index. -// -// On a normal flat-bed printer the plane is XY at slicing_Z = 0 and the -// evaluator is INACTIVE — every call site short-circuits back to the legacy -// `Layer::id() == 0` test. On a belt printer with a Z-from-Y shear the -// belt surface (machine_Z = 0) maps to a plane in slicing-frame coordinates -// derived from the gcode axis remap, so layer-index-based detection no -// longer matches the physical first printed surface. -// -// Plane representation: unit normal `n` (slicing frame) and offset along -// the normal such that the plane equation is `n · p == offset`. Signed -// perpendicular distance is `d(p) = n · p - offset`. Positive distance -// means "away from the belt surface", negative means "below the plane". -class FirstLayerPlane -{ -public: - explicit FirstLayerPlane(const PrintConfig &config); - - // Inactive when the legacy XY layer-index path should be used. This - // covers all non-belt printers and any belt printer where the user - // explicitly picked XY mode. - bool is_active() const { return m_active; } - FirstLayerPlaneMode effective_mode() const{ return m_mode; } - double band_thickness_mm() const { return m_thickness_mm; } - const Vec3d & normal() const { return m_normal; } - double plane_offset() const { return m_offset; } - - // Signed perpendicular distance from a slicing-frame point to the plane. - double distance_from_plane(const Vec3d &point_slicing_mm) const; - - // True if perpendicular distance < first_layer_height_mm. When the - // evaluator is inactive this returns false (call sites should fall back - // to the legacy per-layer path before reaching this function). - bool is_first_layer(const Vec3d &point_slicing_mm, - double first_layer_height_mm) const; - - // floor((distance - 0) / band_thickness), clamped to [0, +inf). Used - // for "first N layers" thresholds (fan, slow_down_layers). Returns 0 - // for points within the band. Returns INT_MAX/2 when inactive. - int effective_layer_index(const Vec3d &point_slicing_mm) const; - - // Min effective index over a 2D bbox at a fixed slicing_Z. Used for - // layer-level decisions (e.g. temperature transition gate) where we - // don't want to walk every extrusion in the layer. For axis-aligned - // planes this is exact; for tilted planes it's a tight lower bound - // (the plane projection of the bbox's extreme corner). - int min_effective_index_for_xy_bbox(const BoundingBoxf &xy_bbox_mm, - double slicing_z_mm) const; - - // Same as above but the bbox spans a Z range too. - int min_effective_index_for_bbox3(const BoundingBoxf3 &bbox_mm) const; - -private: - bool m_active = false; - FirstLayerPlaneMode m_mode = FirstLayerPlaneMode::XY; - Vec3d m_normal = Vec3d::UnitZ(); // unit, slicing frame - double m_offset = 0.0; // n·p == m_offset - double m_thickness_mm = 0.0; -}; - -} // namespace Slic3r - -#endif // slic3r_FirstLayerPlane_hpp_ diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 46c1458c8b..8ad30a611a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -107,7 +107,6 @@ #include "calib.hpp" #include "libslic3r_version.h" #include "GCode/BeltKinematics.hpp" -#include "FirstLayerPlane.hpp" // Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332. // We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB. #if ! defined(TBB_VERSION_MAJOR) @@ -3153,19 +3152,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato print.config().printable_height.value)); } - // Build the FirstLayerPlane evaluator. When inactive (non-belt printers - // and belt printers without Z shear), all per-path call sites short- - // circuit to the legacy Layer::id() == 0 path so g-code stays bit- - // identical to the pre-feature behavior. - m_first_layer_plane = std::make_unique(print.config()); // Belt writers only: travel-speed selection becomes per-point (see // GCodeWriter::uses_pointwise_travel_speed()), which must not change for // non-belt printers. The writer gets the same test the extrusions use, so a // travel is judged against the belt surface (belt_height_above_floor) exactly - // like the path it leads to, and not against the FirstLayerPlane, which - // misreports the height under a non-identity gcode_remap_*. Writer points - // carry the G-code origin and extruder offset that point_to_gcode() added; - // the belt surface is described in the object's own frame. + // like the path it leads to. Writer points carry the G-code origin and + // extruder offset that point_to_gcode() added; the belt surface is described + // in the object's own frame. if (print.config().belt_printer.value) { m_writer.set_first_layer_point_test([this](const Vec3d &point_logical) { const Vec2d extruder_offset = m_writer.filament() != nullptr ? EXTRUDER_CONFIG(extruder_offset) : Vec2d::Zero(); @@ -5540,7 +5533,7 @@ std::string GCode::generate_object_brim(const Print &print, const PrintObject &o // apron band has no Layer, and giving it a synthetic one would feed a fabricated // Layer::id() into initial-layer temperature selection, the spiral vase probe, // gradual interpolation and cooling. Correct first-layer treatment comes from -// FirstLayerPlane in BeltAffine mode, which is evaluated per point. +// the height above the belt, which is evaluated per point. LayerResult GCode::process_belt_brim_layer( const Print &print, const std::vector &layers, @@ -6302,40 +6295,13 @@ LayerResult GCode::process_layer( } } - // First-layer plane: defer the temperature/PLR transition until the - // entire layer is past the first-layer band. When the evaluator is - // inactive (non-belt printers and belt printers without Z shear) we - // fall back to the legacy `!first_layer` predicate so behavior is - // bit-identical to the pre-feature path. + // Belt printers: defer the temperature/PLR transition until the entire layer + // is past the first-layer band above the belt. Elsewhere (non-belt printers, + // support-only layers) the legacy `!first_layer` predicate applies, so + // behavior is bit-identical to the pre-feature path. bool past_first_layer_band = !first_layer; - if (int past = this->belt_layer_past_first_layer_band(object_layer); past >= 0) { - // Belt surface known for this object: measured from the belt itself, as the - // extrusions and travels are, rather than through FirstLayerPlane. + if (int past = this->belt_layer_past_first_layer_band(object_layer); past >= 0) past_first_layer_band = past > 0; - } else if (m_first_layer_plane && m_first_layer_plane->is_active()) { - past_first_layer_band = false; - if (object_layer != nullptr) { - // Conservatively walk the layer's lslice bboxes; if every bbox's - // most-belt-side corner is outside the first-layer band, the - // layer is fully past it. - const Layer *ol = object_layer; - int min_eff = INT_MAX; - for (const BoundingBox &bb : ol->lslices_bboxes) { - BoundingBoxf bbf( - Vec2d(unscale(bb.min.x()), unscale(bb.min.y())), - Vec2d(unscale(bb.max.x()), unscale(bb.max.y()))); - int eff = m_first_layer_plane->min_effective_index_for_xy_bbox( - bbf, ol->print_z); - if (eff < min_eff) min_eff = eff; - if (min_eff <= 0) break; - } - past_first_layer_band = (min_eff > 0 && min_eff != INT_MAX); - } else if (support_layer != nullptr) { - // Support-only layers: gate on the support layer's bottom_z - // proximity to the plane. Conservative. - past_first_layer_band = !first_layer; - } - } if (past_first_layer_band && !m_second_layer_things_done) { // Orca: set power loss recovery @@ -8812,7 +8778,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &path_d if (speed == 0) speed = filament_max_volumetric_speed / _mm3_per_mm; - // Use the FirstLayerPlane-aware effective layer index when active so + // Use the belt-aware effective layer index when on a belt printer so // the speed fade tracks perpendicular distance from the plane on // belt printers; otherwise this falls back to the slicing layer id. const int _layer = this->effective_layer_index_for_point(path_point_mm); @@ -10637,8 +10603,8 @@ std::string GCode::set_object_info(Print *print) { // Whether an object layer lies entirely past the first-layer band above the belt: // 1 when its lowest point is at least one band thickness above the belt, 0 when // any of it is inside the band, -1 when the belt surface is not known for this -// layer (not a belt print, an explicit first-layer plane, or no object layer), in -// which case the caller falls back to FirstLayerPlane / the slicing layer index. +// layer (not a belt print, or no object layer), in which case the caller falls +// back to the slicing layer index. int GCode::belt_layer_past_first_layer_band(const Layer *object_layer) const { if (object_layer == nullptr) @@ -10674,20 +10640,6 @@ bool GCode::belt_height_above_floor(const Vec3d &point_slicing_mm, double &heigh : (m_layer != nullptr ? m_layer->object() : nullptr); if (object == nullptr) return false; - // Respect an explicit first-layer-plane choice: only Auto and BeltAffine mean - // "use the belt". A user who selected XY, YZ or XZ has asked for the - // FirstLayerPlane evaluator and must keep it. - const FirstLayerPlaneMode mode = m_config.first_layer_plane.value; - if (mode != FirstLayerPlaneMode::Auto && mode != FirstLayerPlaneMode::BeltAffine) - return false; - // Likewise for a dialled-in plane offset. It is expressed as a machine-Z - // shift that FirstLayerPlane converts into a perpendicular distance in the - // slicing frame; this evaluator measures along slicing Z instead, so there is - // no faithful translation of it here. Honour the user's setting by deferring - // to the evaluator that implements it rather than silently dropping it. - if (std::abs(m_config.first_layer_plane_offset.value) > EPSILON) - return false; - const SlicingParameters &sp = object->slicing_parameters(); // Deliberately NOT BeltFloorContext: its init() folds in // belt_support_floor_offset, a support-generator diagnostic. Letting that diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index c5268705c3..ccfd14dd39 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -8,7 +8,6 @@ #include "libslic3r.h" #include "GCodeWriter.hpp" #include "GCode/BeltKinematics.hpp" -#include "FirstLayerPlane.hpp" #include "Layer.hpp" #include "Point.hpp" #include "PlaceholderParser.hpp" @@ -400,7 +399,6 @@ public: // first-layer-plane access points (on_first_layer overload, effective // index helper) are in the protected section since they're called from // GCode internals only. - const FirstLayerPlane *first_layer_plane() const { return m_first_layer_plane.get(); } protected: class GCodeOutputStream { @@ -845,7 +843,6 @@ protected: // PrintConfig. is_active() == false on non-belt printers and on belt // printers without a Z-axis shear; in that case all per-path plane // checks short-circuit to the legacy Layer::id() == 0 path. - std::unique_ptr m_first_layer_plane; // Plate origin, kept so a writer replaced during export can be given it again. std::unique_ptr m_pressure_equalizer; @@ -938,42 +935,33 @@ protected: // On the first printing layer. This flag triggers first layer speeds. //BBS bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0 && abs(m_layer->bottom_z()) < EPSILON; } - // Per-point first-layer test. When the FirstLayerPlane evaluator is - // active, the result depends on the supplied slicing-frame point; - // otherwise we delegate to the legacy per-layer test. This is the - // entry point used by per-path call sites in _extrude. + // Per-point first-layer test. On a belt printer the result depends on the + // supplied slicing-frame point (its height above the belt); otherwise we + // delegate to the legacy per-layer test. This is the entry point used by + // per-path call sites in _extrude. bool on_first_layer(const Vec3d &point_slicing_mm) const { - // Belt printers: measure height above the belt surface itself, in the - // slicing frame. See belt_height_above_floor() for why this does not go - // through FirstLayerPlane. double h; if (this->belt_height_above_floor(point_slicing_mm, h)) return h <= m_config.initial_layer_print_height.value + EPSILON; - if (m_first_layer_plane && m_first_layer_plane->is_active()) - return m_first_layer_plane->is_first_layer( - point_slicing_mm, m_config.initial_layer_print_height.value); return on_first_layer(); } // "Effective layer index" used to drive layer-count thresholds like - // slow_down_layers. When the evaluator is active this returns the - // perpendicular distance to the plane in band_thickness_mm units; - // otherwise it returns the legacy slicing layer index. + // slow_down_layers. On a belt printer this is the height above the belt in + // first_layer_band_mm() units; otherwise it is the legacy slicing layer index. int effective_layer_index_for_point(const Vec3d &point_slicing_mm) const { double h; if (this->belt_height_above_floor(point_slicing_mm, h)) { const double lh = this->first_layer_band_mm(); return h <= 0. ? 0 : int(std::floor(h / lh)); } - if (m_first_layer_plane && m_first_layer_plane->is_active()) - return m_first_layer_plane->effective_layer_index(point_slicing_mm); return on_first_layer() ? 0 : layer_id(); } - // Band thickness for the *effective layer index* only. FirstLayerPlane keeps - // two separate thresholds and so must this path: is_first_layer() tests - // against initial_layer_print_height, while effective_layer_index() counts - // bands of first_layer_plane_thickness. Conflating them would apply - // first-layer treatment through a whole 1mm band on a 0.2mm first layer. + // Band thickness for the *effective layer index* only. Two separate + // thresholds: on_first_layer(point) tests against initial_layer_print_height, + // while effective_layer_index_for_point() counts bands of + // first_layer_plane_thickness. Conflating them would apply first-layer + // treatment through a whole 1mm band on a 0.2mm first layer. double first_layer_band_mm() const { double band = m_config.first_layer_plane_thickness.value; if (band <= 0.) band = m_config.initial_layer_print_height.value; @@ -985,13 +973,8 @@ protected: // // The belt surface is known exactly in the slicing frame from the slicing // parameters (belt_floor_shear_factor / _from_axis / _z_shift) -- the same - // description the support generator uses. FirstLayerPlane instead derives its - // plane by composing gcode_remap_* with the g-code back-transform, so its - // answer changes with the machine's *output* axis convention: on a printer - // with a non-identity remap it reported ~86mm of clearance for geometry - // sitting directly on the belt, and no extrusion was ever classified as - // first-layer. Measuring against the belt itself is independent of every - // remap and back-transform. + // description the support generator uses, independent of every remap and + // back-transform. bool belt_height_above_floor(const Vec3d &point_slicing_mm, double &height_mm) const; // 1 / 0 / -1: the object layer is entirely past the first-layer band above the // belt / reaches into it / the belt surface is not known for it. diff --git a/src/libslic3r/GCode/BeltBackTransform.cpp b/src/libslic3r/GCode/BeltBackTransform.cpp index 4b247323cd..e7257cf90e 100644 --- a/src/libslic3r/GCode/BeltBackTransform.cpp +++ b/src/libslic3r/GCode/BeltBackTransform.cpp @@ -13,16 +13,12 @@ bool BeltBackTransform::init_from_config(const PrintConfig &config) if (!config.belt_printer.value || !config.gcode_back_transform.value) return false; - // Require at least one active transform to proceed. - bool has_global_rotation = config.belt_slice_rotation_global.value - && config.belt_slice_rotation.value != BeltRotationAxis::None; - bool has_preslice_global = config.belt_preslice_global.value - || config.preslice_remap_global.value; - if (!has_global_rotation && !has_preslice_global - && !BeltTransformPipeline::has_preslice_remap(config)) + // The back-transform undoes the global pre-slice rotation; without global + // mode the slicing frame is not a common frame to undo. + if (!config.belt_preslice_global.value) return false; - // Build the forward pipeline (rotation * pre_remap) and store its inverse. + // Build the forward pipeline (the rotation) and store its inverse. Transform3d forward = BeltTransformPipeline::build_forward_transform(config); if (forward.isApprox(Transform3d::Identity())) return false; diff --git a/src/libslic3r/GCode/BeltBackTransform.hpp b/src/libslic3r/GCode/BeltBackTransform.hpp index 878ae12b5a..69e32a4b2c 100644 --- a/src/libslic3r/GCode/BeltBackTransform.hpp +++ b/src/libslic3r/GCode/BeltBackTransform.hpp @@ -7,25 +7,21 @@ namespace Slic3r { -// Reverses the pre-slice remap + shear + scale transforms that -// PrintObjectSlice.cpp applies to belt printer geometry, converting G-code -// coordinates from the sliced (remapped/sheared/scaled) frame back to the -// machine's real coordinate space. +// Reverses the pre-slice rotation that PrintObjectSlice.cpp applies to belt +// printer geometry, converting G-code coordinates from the sliced (rotated) +// frame back to the machine's real coordinate space. // // Initialized once from PrintConfig, then applied per-point in // BeltKinematics::to_machine() before axis remapping. // -// Active when gcode_back_transform is true AND at least one of: -// - a shear axis has global mode enabled, or -// - a pre-slice axis remap is non-identity. +// Active when gcode_back_transform and belt_preslice_global are both set. class BeltBackTransform { public: BeltBackTransform() = default; - // Initialize from belt printer config. Rebuilds the same pre-slice remap, - // shear, and scale matrices as PrintObjectSlice.cpp and precomputes the - // affine inverse. Returns true if a non-identity back-transform was computed. + // Initialize from belt printer config. Rebuilds the same pre-slice rotation + // as PrintObjectSlice.cpp and precomputes the affine inverse. Returns true if a non-identity back-transform was computed. bool init_from_config(const PrintConfig &config); // Apply the inverse transform to a point. Returns pos unchanged if diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index fa418e1b62..1899e2358b 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2641,9 +2641,6 @@ void GCodeProcessorResult::reset() { machine_frame_transform_active = false; belt_tilt_angle = 0.f; belt_z_origin = 0.f; - preslice_remap_x = RemapAxis::PosX; - preslice_remap_y = RemapAxis::PosY; - preslice_remap_z = RemapAxis::PosZ; settings_ids.reset(); filaments_count = 0; backtrace_enabled = false; @@ -3223,8 +3220,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) const auto *belt = config.option("belt_printer"); if (belt != nullptr) { static const char *belt_keys[] = { - "belt_printer", "belt_slice_rotation", "belt_slice_rotation_angle", "belt_slice_rotation_global", - "belt_preslice_global", "preslice_remap_x", "preslice_remap_y", "preslice_remap_z", "preslice_remap_global", + "belt_printer", "belt_slice_rotation", "belt_slice_rotation_angle", "belt_preslice_global", "gcode_remap_x", "gcode_remap_y", "gcode_remap_z", "gcode_back_transform", "belt_frame_tilt_decouple", "belt_frame_tilt_angle", }; @@ -4350,36 +4346,6 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers } catch (...) {} return; } - // Belt printer: parse pre-slice axis remap from header comments. - { - auto trim = [](const std::string &s) -> std::string { - size_t start = s.find_first_not_of(" \t\r\n"); - size_t end = s.find_last_not_of(" \t\r\n"); - return (start == std::string::npos) ? "" : s.substr(start, end - start + 1); - }; - // Pre-slice axis remap - auto parse_remap_axis = [](const std::string &s) -> RemapAxis { - if (s == "pos_x") return RemapAxis::PosX; - if (s == "pos_y") return RemapAxis::PosY; - if (s == "pos_z") return RemapAxis::PosZ; - if (s == "neg_x") return RemapAxis::NegX; - if (s == "neg_y") return RemapAxis::NegY; - if (s == "neg_z") return RemapAxis::NegZ; - if (s == "rev_x") return RemapAxis::RevX; - if (s == "rev_y") return RemapAxis::RevY; - if (s == "rev_z") return RemapAxis::RevZ; - return RemapAxis::PosX; - }; - if (boost::starts_with(comment, " preslice_remap_x = ")) { - m_result.preslice_remap_x = parse_remap_axis(trim(std::string(comment.substr(20)))); return; - } - if (boost::starts_with(comment, " preslice_remap_y = ")) { - m_result.preslice_remap_y = parse_remap_axis(trim(std::string(comment.substr(20)))); return; - } - if (boost::starts_with(comment, " preslice_remap_z = ")) { - m_result.preslice_remap_z = parse_remap_axis(trim(std::string(comment.substr(20)))); return; - } - } // wipe start tag if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) { m_wiping = true; diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index a5c5ce7914..cb8178d113 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -304,9 +304,6 @@ class Print; // machine frame and should not be compared against `printable_height` // (which lives in the build-volume frame). bool machine_frame_transform_active{ false }; - RemapAxis preslice_remap_x{ RemapAxis::PosX }; - RemapAxis preslice_remap_y{ RemapAxis::PosY }; - RemapAxis preslice_remap_z{ RemapAxis::PosZ }; SettingsIds settings_ids; size_t filaments_count; bool backtrace_enabled; @@ -405,9 +402,6 @@ class Print; belt_tilt_angle = std::forward(other).belt_tilt_angle; belt_z_origin = std::forward(other).belt_z_origin; machine_frame_transform_active = std::forward(other).machine_frame_transform_active; - preslice_remap_x = std::forward(other).preslice_remap_x; - preslice_remap_y = std::forward(other).preslice_remap_y; - preslice_remap_z = std::forward(other).preslice_remap_z; #if ENABLE_GCODE_VIEWER_STATISTICS time = std::forward(other).time; #endif diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index bc25c448dd..e1c1308076 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1560,13 +1560,12 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", "printable_area", "extruder_printable_area", "support_parallel_printheads", "parallel_printheads_count", "parallel_printheads_bed_exclude_areas", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "build_plate_tilt_x", "build_plate_tilt_y", "belt_printer", "belt_printer_infinite_y", - "belt_slice_rotation", "belt_slice_rotation_angle", "belt_slice_rotation_global", - "preslice_remap_x", "preslice_remap_y", "preslice_remap_z", "preslice_remap_global", + "belt_slice_rotation", "belt_slice_rotation_angle", "gcode_remap_x", "gcode_remap_y", "gcode_remap_z", "gcode_back_transform", "belt_frame_tilt_decouple", "belt_frame_tilt_angle", "belt_preslice_global", - "first_layer_plane", "first_layer_plane_offset", "first_layer_plane_thickness", - "belt_support_floor_offset", "belt_support_floor_mode", "belt_support_z_offset_mode", + "first_layer_plane_thickness", + "belt_support_floor_offset", "belt_support_floor_mode", "enable_belt_purge_tower", "gcode_flavor", "gcode_skip_config_block", "fan_kickstart", "part_cooling_fan_min_pwm", "fan_speedup_time", "fan_speedup_overhangs", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 9dc9ff3cd3..9aa9626e5e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -177,7 +177,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n // Machine-frame transform (derived from belt tilt; only affects G-code output). "belt_frame_tilt_decouple", "belt_frame_tilt_angle", "gcode_back_transform", - "first_layer_plane", "first_layer_plane_offset", "first_layer_plane_thickness", + "first_layer_plane_thickness", // Only inflates the GUI bed volume, like printable_area. "belt_printer_infinite_y", //BBS @@ -389,17 +389,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "belt_printer" || opt_key == "belt_slice_rotation" || opt_key == "belt_slice_rotation_angle" - || opt_key == "belt_slice_rotation_global" - || opt_key == "belt_preslice_global" - || opt_key == "preslice_remap_global" - || opt_key == "preslice_remap_x" - || opt_key == "preslice_remap_y" - || opt_key == "preslice_remap_z") { + || opt_key == "belt_preslice_global") { osteps.emplace_back(posSlice); } else if ( opt_key == "belt_support_floor_offset" - || opt_key == "belt_support_floor_mode" - || opt_key == "belt_support_z_offset_mode") { + || opt_key == "belt_support_floor_mode") { osteps.emplace_back(posSupportMaterial); } else if ( opt_key == "print_sequence" @@ -2107,9 +2101,7 @@ StringObjectException Print::validate(std::vector *warnin bool have_height = false; if (belt_printer) { - double raw_z = print_object.model_object()->max_z(); - if (BeltTransformPipeline::has_preslice_remap(this->config())) - raw_z = BeltTransformPipeline::remap_bbox(*print_object.model_object(), this->config()).size().z(); + const double raw_z = print_object.model_object()->max_z(); effective_max_z = raw_z; have_height = raw_z > 0; } else { @@ -3069,11 +3061,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) std::set re_slicing_objects; // Belt global modes couple each object's bed position into its layer Z values, // so sharing layers between "identical" objects is wrong. - bool belt_no_share = m_config.belt_printer.value && - ((m_config.belt_slice_rotation_global.value - && m_config.belt_slice_rotation.value != BeltRotationAxis::None) - || m_config.preslice_remap_global.value - || m_config.belt_preslice_global.value); + bool belt_no_share = m_config.belt_printer.value && m_config.belt_preslice_global.value; if (!use_cache) { for (int index = 0; index < object_count; index++) { diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 425912b9c2..5ee4815489 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -231,11 +231,10 @@ class ConstSupportLayerPtrsAdaptor : public ConstVectorOfPtrsAdaptor(data) {} }; -// Returns the model's raw bounding box with pre-slice axis remap applied. -// When no remap is active, returns the unmodified raw_bounding_box(). -inline BoundingBoxf3 belt_remapped_bbox(const ModelObject &model_object, const PrintConfig &config) +// The model's raw bounding box, in the frame the belt floor parameters refer to. +inline BoundingBoxf3 belt_remapped_bbox(const ModelObject &model_object, const PrintConfig & /*config*/) { - return BeltTransformPipeline::remap_bbox(model_object, config); + return model_object.raw_bounding_box(); } // Single instance of a PrintObject. diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 94725118c7..108e2cc796 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -1844,12 +1844,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // Orca: Updated for XYZ filament shrink compensation // Belt global mode: force each instance into its own PrintObject // so each gets independent layer Z values. - bool belt_force_separate = m_config.belt_printer.value && ( - (m_config.belt_slice_rotation_global.value - && m_config.belt_slice_rotation.value != BeltRotationAxis::None - && std::abs(m_config.belt_slice_rotation_angle.value) > EPSILON) - || m_config.belt_preslice_global.value - || (m_config.preslice_remap_global.value && BeltTransformPipeline::has_preslice_remap(m_config))); + bool belt_force_separate = m_config.belt_printer.value && m_config.belt_preslice_global.value; model_object_status.print_instances = print_objects_from_model_object(*model_object, this->shrinkage_compensation(), belt_force_separate); std::vector old; old.reserve(print_object_status_db.count(*model_object)); @@ -1940,11 +1935,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // min_shift across all objects, so one move affects everyone). if (belt_instances_shifted && m_config.belt_printer.value - && ((m_config.belt_slice_rotation_global.value - && m_config.belt_slice_rotation.value != BeltRotationAxis::None - && std::abs(m_config.belt_slice_rotation_angle.value) > EPSILON) - || m_config.belt_preslice_global.value - || (m_config.preslice_remap_global.value && BeltTransformPipeline::has_preslice_remap(m_config)))) { + && m_config.belt_preslice_global.value) { for (PrintObject *object : m_objects) update_apply_status(object->invalidate_step(posSlice)); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ee23a88940..708e942359 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -404,25 +404,6 @@ static t_config_enum_values s_keys_map_BeltSupportFloorMode { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltSupportFloorMode) -static t_config_enum_values s_keys_map_BeltSupportZOffsetMode { - { "none", int(BeltSupportZOffsetMode::None) }, - { "unconditional", int(BeltSupportZOffsetMode::Unconditional) }, - { "raft_only", int(BeltSupportZOffsetMode::RaftOnly) }, -}; -CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltSupportZOffsetMode) - -static t_config_enum_values s_keys_map_FirstLayerPlaneMode { - { "auto", int(FirstLayerPlaneMode::Auto) }, - { "xy", int(FirstLayerPlaneMode::XY) }, - { "yz", int(FirstLayerPlaneMode::YZ) }, - { "xz", int(FirstLayerPlaneMode::XZ) }, - { "belt_affine", int(FirstLayerPlaneMode::BeltAffine) }, - // Back-compat alias: pre-rotation builds serialised this mode as - // "belt_shear". Accept it on parse so old 3MFs / presets keep loading. - { "belt_shear", int(FirstLayerPlaneMode::BeltAffine) }, -}; -CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FirstLayerPlaneMode) - static t_config_enum_values s_keys_map_SupportMaterialPattern { { "rectilinear", smpRectilinear }, { "rectilinear-grid", smpRectilinearGrid }, @@ -7425,16 +7406,6 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(45.)); - def = this->add("belt_slice_rotation_global", coBool); - def->label = L("Global"); - def->category = L("Printable space"); - def->tooltip = L("Treat the slicing rotation as part of the global forward transform " - "that BeltBackTransform inverts before the machine-frame remap. " - "Required for rotation-mode belt printers. " - "Defaults to on because virtually all rotation-mode printers need it."); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionBool(true)); - def = this->add("belt_frame_tilt_decouple", coBool); def->label = L("Decouple machine-frame tilt"); def->category = L("Printable space"); @@ -7458,7 +7429,7 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(45.)); - // G-code axis remap with sign + // G-code axis remap with sign. Each field is its own row in the settings tab. auto add_belt_remap = [this](const char *key, const char *label, const char *tooltip, RemapAxis default_axis, ConfigOptionMode mode = comSimple) { auto def = this->add(key, coEnum); @@ -7472,39 +7443,9 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionEnum(default_axis)); }; - add_belt_remap("preslice_remap_x", "X", - "Before slicing, which model-space axis becomes the slicer's X axis. " - "Use this to re-orient the coordinate system so the slicer's XY plane matches " - "your belt printer's physical bed plane. For a printer whose bed is in the XZ plane, " - "set Y to +Z and Z to +Y (or -Y) to swap the vertical and belt-travel axes. " - "Default +X: no change.", - RemapAxis::PosX, comDevelop); - add_belt_remap("preslice_remap_y", "Y", - "Before slicing, which model-space axis becomes the slicer's Y axis. " - "The slicer treats Y as one of the two horizontal bed axes. If your physical " - "belt surface runs along the Z axis, map Y to +Z here so the slicer slices " - "along the correct plane. Default +Y: no change.", - RemapAxis::PosY, comDevelop); - add_belt_remap("preslice_remap_z", "Z", - "Before slicing, which model-space axis becomes the slicer's Z axis (layer stacking direction). " - "The slicer builds layers upward along this axis. If your printer's layer-stacking " - "direction is the physical Y axis, map Z to +Y (or -Y for inverted direction). " - "Rev mode mirrors relative to the build volume maximum. Default +Z: no change.", - RemapAxis::PosZ, comDevelop); - - def = this->add("preslice_remap_global", coBool); - def->label = L("Global"); - def->category = L("Printable space"); - def->tooltip = L("When enabled, the pre-slice axis remap accounts for each object's bed position. " - "Without this, the remap is applied locally around each object's center, so " - "objects at different positions don't get a position-dependent contribution. " - "Mirrors the 'Global' option on the belt slicing rotation, but for the remap."); - def->mode = comDevelop; - def->set_default_value(new ConfigOptionBool(false)); - - add_belt_remap("gcode_remap_x", "X", "Which slicing axis maps to machine X in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosX, comDevelop); - add_belt_remap("gcode_remap_y", "Y", "Which slicing axis maps to machine Y in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosY, comDevelop); - add_belt_remap("gcode_remap_z", "Z", "Which slicing axis maps to machine Z in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosZ, comDevelop); + add_belt_remap("gcode_remap_x", "G-code remap X", "Which slicing axis maps to machine X in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosX, comDevelop); + add_belt_remap("gcode_remap_y", "G-code remap Y", "Which slicing axis maps to machine Y in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosY, comDevelop); + add_belt_remap("gcode_remap_z", "G-code remap Z", "Which slicing axis maps to machine Z in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosZ, comDevelop); // The machine-frame G-code transform (shear + scale) is no longer configured // by per-axis keys: it is derived from the belt tilt (belt_slice_rotation axis @@ -7528,53 +7469,14 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(true)); - // First-layer plane: which surface defines "first layer" for fan / speed / - // accel decisions. On belt printers the slicing-frame layer 0 is a tilted - // slab that no longer corresponds to the physical first printed layer. - // Auto picks BeltAffine when any belt-side affine transform is active - // (Z shear or slicing rotation), otherwise XY (legacy). - def = this->add("first_layer_plane", coEnum); - def->label = L("First layer plane"); - def->category = L("Printable space"); - def->tooltip = L("Selects the reference plane used to decide which extrusions get " - "first-layer settings (no fan, slow speed, initial-layer accel/jerk, " - "deferred temperature drop). On belt printers a single slicing layer " - "contains paths at many machine-Z values, so layer-index based detection " - "fails. Auto resolves to Belt affine plane when any belt-side affine " - "transform (Z shear or slicing rotation) is active, otherwise XY (legacy). " - "Pick XY explicitly to opt out and force the legacy slicing-layer-0 " - "detection."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values = {"auto", "xy", "yz", "xz", "belt_affine"}; - def->enum_labels = {L("Auto"), L("XY (machine bed)"), L("YZ"), L("XZ"), L("Belt affine plane")}; - def->mode = comExpert; - // Auto, not BeltAffine: BeltAffine activates the plane evaluator unconditionally, so on a - // non-belt printer on_first_layer(point) stopped agreeing with the legacy slicing-layer-0 - // test and first-layer speeds were skipped (brim printed at the volumetric fallback rather - // than initial_layer_speed). Auto resolves to BeltAffine only when belt_printer is set with - // a non-zero slicing rotation, and to XY (evaluator inactive, legacy behaviour) otherwise -- - // which is what this option's own description promises. - def->set_default_value(new ConfigOptionEnum(FirstLayerPlaneMode::Auto)); - - def = this->add("first_layer_plane_offset", coFloat); - def->label = L("Belt plane offset"); - def->category = L("Printable space"); - def->tooltip = L("Shifts the first-layer plane along its normal (mm). For axis-aligned " - "planes this is just a coordinate shift. Positive values move the plane " - "away from the belt surface (deeper into the model)."); - def->sidetext = L("mm"); - def->min = -1000; - def->max = 1000; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(0.0)); - def = this->add("first_layer_plane_thickness", coFloat); - def->label = L("Plane band thickness"); + def->label = L("First layer band thickness"); def->category = L("Printable space"); - def->tooltip = L("Thickness of one 'band' relative to the first-layer plane, in mm. " - "Used as the unit by which 'No cooling for the first N layers' (and " - "similar layer-count thresholds) is multiplied when the first-layer " - "plane is active. -1 means use initial_layer_print_height."); + def->tooltip = L("Belt printers only. Every tilted layer touches the belt, so the first-layer " + "settings apply to a band above the belt surface rather than to the first " + "slicing layer. This is the thickness of one band, in mm: the unit by which " + "'No cooling for the first N layers' and similar layer-count thresholds are " + "multiplied. -1 means use the first layer height."); def->sidetext = L("mm"); def->min = -1; def->max = 100; @@ -7605,19 +7507,6 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionEnum(BeltSupportFloorMode::GeneratorOnly)); } - { - auto def = this->add("belt_support_z_offset_mode", coEnum); - def->label = L("Z offset mode"); - def->category = L("Printable space"); - def->tooltip = L("How global Z offset is applied to support layers for belt printers with global shear. " - "'None' = don't offset. 'Unconditional' = offset all layers. 'Raft only' = only offset raft layers."); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values = {"none", "unconditional", "raft_only"}; - def->enum_labels = {L("None"), L("Unconditional"), L("Raft only")}; - def->mode = comExpert; - def->set_default_value(new ConfigOptionEnum(BeltSupportZOffsetMode::Unconditional)); - } - def = this->add("enable_belt_purge_tower", coBool); def->label = L("Enable belt purge tower"); def->category = L("Multimaterial"); @@ -9793,6 +9682,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va "smooth_coefficient", "overhang_totally_speed", "silent_mode", "overhang_speed_classic", "anisotropic_surfaces", // superseded by top_surface_fill_order / bottom_surface_fill_order + // Belt printer keys retired before the first release: the global switches collapsed + // into belt_preslice_global, the pre-slice axis remap and the support Z offset mode + // were removed. + "belt_slice_rotation_global", "preslice_remap_x", "preslice_remap_y", "preslice_remap_z", "preslice_remap_global", + "belt_support_z_offset_mode", "first_layer_plane", "first_layer_plane_offset", }; if (ignore.find(opt_key) != ignore.end()) { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 1a9e3ea075..01ee8b4b0c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -300,34 +300,6 @@ enum class BeltSupportFloorMode GeneratorOnly, // Only in tree support drop_nodes/contact_points }; -enum class BeltSupportZOffsetMode -{ - None, // Don't apply global_z_offset to support layers - Unconditional, // Apply to all support layers - RaftOnly, // Only apply to raft layers -}; - -// Selects which plane the slicer treats as the "first layer plane" — the -// reference surface used to decide which extrusions get first-layer settings -// (no fan, slow speed, initial-layer accel/jerk, deferred temperature drop). -// -// Auto resolves to: -// - XY (inactive, legacy behavior) for non-belt printers and for belt -// printers with no active belt-side transform. -// - BeltAffine for belt printers with any active belt-side affine -// transform (Z shear, slicing rotation, or both). -// -// XY is also used as an explicit "opt out" mode that forces legacy -// per-layer first-layer detection even on belt printers. -enum class FirstLayerPlaneMode -{ - Auto = 0, - XY, - YZ, - XZ, - BeltAffine, // formerly BeltShear; renamed to reflect rotation support -}; - enum SupportMaterialPattern { smpDefault, smpRectilinear, smpRectilinearGrid, smpHoneycomb, @@ -775,8 +747,6 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltRotationAxis) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(RemapAxis) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportFloorMode) -CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportZOffsetMode) -CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FirstLayerPlaneMode) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern) @@ -1898,26 +1868,18 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( // g-code back-transform inverts the rotation before the machine-frame stage. ((ConfigOptionEnum, belt_slice_rotation)) ((ConfigOptionFloat, belt_slice_rotation_angle)) - ((ConfigOptionBool, belt_slice_rotation_global)) // Expert override: decouple the machine-frame tilt angle from the pre-slice // rotation angle. When disabled, the machine frame uses belt_slice_rotation_angle. ((ConfigOptionBool, belt_frame_tilt_decouple)) ((ConfigOptionFloat, belt_frame_tilt_angle)) - ((ConfigOptionEnum, preslice_remap_x)) - ((ConfigOptionEnum, preslice_remap_y)) - ((ConfigOptionEnum, preslice_remap_z)) - ((ConfigOptionBool, preslice_remap_global)) ((ConfigOptionEnum, gcode_remap_x)) ((ConfigOptionEnum, gcode_remap_y)) ((ConfigOptionEnum, gcode_remap_z)) ((ConfigOptionBool, gcode_back_transform)) ((ConfigOptionBool, belt_preslice_global)) - ((ConfigOptionEnum, first_layer_plane)) - ((ConfigOptionFloat, first_layer_plane_offset)) ((ConfigOptionFloat, first_layer_plane_thickness)) ((ConfigOptionFloat, belt_support_floor_offset)) ((ConfigOptionEnum, belt_support_floor_mode)) - ((ConfigOptionEnum, belt_support_z_offset_mode)) // Width (machine X, across the belt) of the auto-generated belt purge prism. ((ConfigOptionFloat, belt_purge_tower_width)) // Belt-printer-only "type" of purge tower: enables the auto-generated belt diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7a46f354fc..d11f0ec1a3 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -4154,9 +4154,7 @@ void PrintObject::update_slicing_parameters() BeltTransformPipeline::BeltFloorParams belt_floor; const auto &pcfg = this->print()->config(); if (pcfg.belt_printer.value) { - BoundingBoxf3 bb = BeltTransformPipeline::remap_bbox(*this->model_object(), pcfg); - if (BeltTransformPipeline::has_preslice_remap(pcfg)) - object_height = bb.size().z(); + const BoundingBoxf3 bb = this->model_object()->raw_bounding_box(); auto hr = BeltTransformPipeline::compute_belt_height_and_floor(pcfg, bb, object_height); object_height = hr.object_height; belt_floor = hr.floor_params; @@ -4217,9 +4215,6 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full BoundingBoxf3 bb = model_object.raw_bounding_box(); object_max_z = (float)bb.size().z(); if (print_config.belt_printer.value) { - bb = BeltTransformPipeline::remap_bbox(model_object, print_config); - if (BeltTransformPipeline::has_preslice_remap(print_config)) - object_max_z = (float)bb.size().z(); auto hr = BeltTransformPipeline::compute_belt_height_and_floor(print_config, bb, object_max_z); object_max_z = (float)hr.object_height; belt_floor = hr.floor_params; diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index b384a28ef3..46408fe886 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -343,8 +343,7 @@ static std::vector> slices_to_regions( // pushes those layers into the parallel_for path below, which handles multi-volume // clipping per layer without relying on the bbox Z range. const bool bbox_z_in_layer_frame = !(print_config.belt_printer.value && - (BeltTransformPipeline::has_rotation(print_config) - || BeltTransformPipeline::has_preslice_remap(print_config))); + BeltTransformPipeline::has_rotation(print_config)); // Belt-transform addendum: with bbox-Z untrusted, the simple path's // "first model_part wins" logic drops subsequent volumes' slices unless // they XY-overlap with the first. Assemblies whose volumes are stacked @@ -926,14 +925,9 @@ void PrintObject::slice() // So: belt_floor_z_shift = remapped_bb.min.z() + z_shift_val if (std::abs(m_slicing_params.belt_floor_shear_factor) > EPSILON) { double z_shift_val = (m_belt_min_z < 0.) ? -m_belt_min_z : 0.; - // With pre-remap, the belt surface (model_Y=0) may not be at Z=0 in - // centered slicer space — add the remapped bbox min Z to compensate. - // Without pre-remap, the belt surface IS at Z=0 and bb.min.z() is - // already folded into m_belt_min_z, so use 0. - const auto &pcfg = this->print()->config(); - double belt_surface_z = BeltTransformPipeline::has_preslice_remap(pcfg) - ? BeltTransformPipeline::remap_bbox(*this->model_object(), pcfg).min.z() : 0.; - m_slicing_params.belt_floor_z_shift = belt_surface_z + z_shift_val; + // The belt surface is at Z=0 in centered slicer space and bb.min.z() is + // already folded into m_belt_min_z. + m_slicing_params.belt_floor_z_shift = z_shift_val; } int firstLayerReplacedBy = 0; @@ -982,7 +976,6 @@ void PrintObject::slice() const auto &pcfg = this->print()->config(); BOOST_LOG_TRIVIAL(trace) << "Belt global check: belt_printer=" << pcfg.belt_printer.value << " belt_slice_rotation=" << int(pcfg.belt_slice_rotation.value) - << " belt_slice_rotation_global=" << pcfg.belt_slice_rotation_global.value << " belt_preslice_global=" << pcfg.belt_preslice_global.value << " object=" << this->model_object()->name; if (pcfg.belt_printer.value) { @@ -1003,8 +996,7 @@ void PrintObject::slice() // couples slicer_z back into both machine_y and machine_z. Compensating // layer.print_z by belt_z_shift here makes the back-transform produce // correct machine-frame coordinates whether or not a global mode is active. - double belt_surface_z = BeltTransformPipeline::has_preslice_remap(pcfg) - ? BeltTransformPipeline::remap_bbox(*this->model_object(), pcfg).min.z() : 0.; + const double belt_surface_z = 0.; // the belt surface is Z=0 in centered slicer space // The compensation must mirror the Z-shift actually applied, which // is max(0, -m_belt_min_z): when the transformed mesh starts ABOVE // slicer Z=0 (m_belt_min_z > 0 — possible for counter-rotated or @@ -1036,7 +1028,9 @@ void PrintObject::slice() if (pcfg.belt_preslice_global.value) { // Global pre-slice mode: compute full correction c = (T.linear() - I) * d - // where T is the belt forward transform and d is the bed position. + // where T is the belt forward transform and d is the bed position, so + // objects at different bed positions print at different machine Z values + // along the inclined belt. Transform3d T = BeltTransformPipeline::build_forward_transform(pcfg); Vec3d d(unscale(inst_shift.x()), unscale(inst_shift.y()), 0.); Vec3d c = T.linear() * d - d; @@ -1046,31 +1040,6 @@ void PrintObject::slice() BOOST_LOG_TRIVIAL(trace) << "Belt preslice_global: correction=(" << c.x() << ", " << c.y() << ", " << c.z() << ")" << " belt_z_shift=" << belt_z_shift << " (m_belt_min_z=" << m_belt_min_z << ")"; - } else { - // Slicing rotation in global mode: bed-position-dependent Z offset. - // For R(α, X): c.z = sin(α)*d.y so objects at different bed-Y - // values print at different machine Z values along the inclined belt. - if (pcfg.belt_slice_rotation_global.value - && pcfg.belt_slice_rotation.value != BeltRotationAxis::None - && std::abs(pcfg.belt_slice_rotation_angle.value) > EPSILON) { - Transform3d T = BeltTransformPipeline::build_forward_transform(pcfg); - Vec3d d(unscale(inst_shift.x()), unscale(inst_shift.y()), 0.); - Vec3d c = T.linear() * d - d; - global_z_offset += c.z(); - m_belt_global_xy_correction = Vec2d(c.x(), c.y()); - } - - // Pre-slice remap global mode: when on, the remap accounts for the - // instance bed position. The Z component of the correction - // (R - I) * d shifts layer print_z so e.g. a Y↔Z swap with an - // object at Y=50 prints at Z=50. - if (pcfg.preslice_remap_global.value - && BeltTransformPipeline::has_preslice_remap(pcfg)) { - Transform3d R = BeltTransformPipeline::build_preslice_remap(pcfg); - Vec3d d(unscale(inst_shift.x()), unscale(inst_shift.y()), 0.); - Vec3d remap_correction = R.linear() * d - d; - global_z_offset += remap_correction.z(); - } } BOOST_LOG_TRIVIAL(trace) << "Belt global: z_offset=" << global_z_offset diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index b03e6b5f03..49940229dc 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1339,10 +1339,9 @@ static Transform3d compute_belt_back_transform(const PrintConfig& cfg) // build-volume offset for Rev axes). This is the matrix form of the per-point // GCodeWriter::apply_axis_remap (row convention: each OUTPUT axis selects an input // axis + sign) and MUST stay in sync with it. The build-volume max matches what the - // writer is fed in GCode.cpp (printable_area max + printable_height). NB: this is the - // transpose of the column convention used by BeltTransformPipeline::build_preslice_remap - // — the two remaps are not interchangeable. (Follow-up: precompute this matrix once in - // GCodeWriter and share it with apply_axis_remap to remove the parallel encoding.) + // writer is fed in GCode.cpp (printable_area max + printable_height). (Follow-up: + // precompute this matrix once in GCodeWriter and share it with apply_axis_remap to + // remove the parallel encoding.) Transform3d ar = Transform3d::Identity(); const int rr[3] = { int(cfg.gcode_remap_x.value), int(cfg.gcode_remap_y.value), int(cfg.gcode_remap_z.value) }; if (rr[0] != 0 || rr[1] != 1 || rr[2] != 2) { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c64b4c8807..a2d0f3ea3e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5260,67 +5260,27 @@ void TabPrinter::build_fff() line.label_path = "printer_basic_information_belt_printer#belt-tilt"; line.append_option(belt_og->get_option("belt_slice_rotation")); line.append_option(belt_og->get_option("belt_slice_rotation_angle")); - line.append_option(belt_og->get_option("belt_slice_rotation_global")); - belt_og->append_line(line); - } - { - Line line = { L("Pre-slice axis remap"), - L("Remap model axes before slicing so the slicer's coordinate system matches " - "the physical bed orientation. For belt printers whose bed is NOT in the XY plane, " - "use this to swap axes so layers are stacked in the correct physical direction.") }; - line.label_path = "printer_basic_information_belt_printer#pre-slice-axis-remap"; - line.append_option(belt_og->get_option("preslice_remap_x")); - line.append_option(belt_og->get_option("preslice_remap_y")); - line.append_option(belt_og->get_option("preslice_remap_z")); - line.append_option(belt_og->get_option("preslice_remap_global")); belt_og->append_line(line); } belt_og->append_single_option_line("belt_preslice_global", "printer_basic_information_belt_printer#global-mesh-transforms"); belt_og->append_single_option_line("gcode_back_transform", "printer_basic_information_belt_printer#g-code-back-transform"); - { - Line line = { L("First layer plane"), - L("Reference plane used to decide which extrusions get first-layer " - "settings (no fan, slow speed, deferred temperature drop). On belt " - "printers, Auto resolves to the tilted belt-shear plane so that " - "first-layer treatment follows perpendicular distance from the belt " - "surface, not slicing layer index.") }; - line.label_path = "printer_basic_information_belt_printer#first-layer-plane"; - line.append_option(belt_og->get_option("first_layer_plane")); - line.append_option(belt_og->get_option("first_layer_plane_offset")); - line.append_option(belt_og->get_option("first_layer_plane_thickness")); - belt_og->append_line(line); - } + belt_og->append_single_option_line("first_layer_plane_thickness", "printer_basic_information_belt_printer#first-layer-band-thickness"); // Support floor: split across lines so each setting's own mode controls - // its visibility (floor_mode = Develop, floor_offset = Advanced, z_offset_mode = Expert). + // its visibility (floor_mode = Develop, floor_offset = Advanced). belt_og->append_single_option_line("belt_support_floor_offset", "printer_basic_information_belt_printer#support-floor-z-offset"); - belt_og->append_single_option_line("belt_support_z_offset_mode", "printer_basic_information_belt_printer#z-offset-mode"); belt_og->append_single_option_line("belt_support_floor_mode", "printer_basic_information_belt_printer#floor-mode"); - // Machine-frame transform: the shear (tan) + scale (1/cos) that map + // Machine-frame transform: the shear (cot) + scale (1/sin) that map // Cartesian G-code into the printer's physical machine frame are derived // from the belt tilt angle. Only the post-slice axis remap and the expert - // decouple override are exposed here. + // decouple override are exposed here, one option per row. { auto mf = page->new_optgroup(L("Machine frame transforms"), L"param_advanced"); - { - Line line = { L("G-code axis remap (post-slice)"), L("Remap slicing-frame axes to machine axes in G-code output. Applied AFTER slicing, during G-code generation.") }; - line.label_path = "printer_basic_information_machine_frame_transforms#g-code-axis-remap"; - line.append_option(mf->get_option("gcode_remap_x")); - line.append_option(mf->get_option("gcode_remap_y")); - line.append_option(mf->get_option("gcode_remap_z")); - mf->append_line(line); - } - { - Line line = { L("Machine-frame tilt"), - L("The machine-frame shear (tan) and scale (1/cos) are derived from " - "the belt tilt angle. Enable 'Decouple' to set an independent " - "machine-frame angle when the physical gantry tilt differs from " - "the slicing rotation.") }; - line.label_path = "printer_basic_information_machine_frame_transforms#machine-frame-tilt"; - line.append_option(mf->get_option("belt_frame_tilt_decouple")); - line.append_option(mf->get_option("belt_frame_tilt_angle")); - mf->append_line(line); - } + mf->append_single_option_line("gcode_remap_x", "printer_basic_information_machine_frame_transforms#g-code-axis-remap"); + mf->append_single_option_line("gcode_remap_y", "printer_basic_information_machine_frame_transforms#g-code-axis-remap"); + mf->append_single_option_line("gcode_remap_z", "printer_basic_information_machine_frame_transforms#g-code-axis-remap"); + mf->append_single_option_line("belt_frame_tilt_decouple", "printer_basic_information_machine_frame_transforms#machine-frame-tilt"); + mf->append_single_option_line("belt_frame_tilt_angle", "printer_basic_information_machine_frame_transforms#machine-frame-tilt"); } option = optgroup->get_option("thumbnails"); @@ -6370,36 +6330,27 @@ void TabPrinter::toggle_options() // Remap, back-transform, and global mesh-transforms toggles are gated by belt // mode here; finer mode-based visibility is handled by each option's - // ConfigOptionMode in PrintConfig.cpp. Both axis remaps are Develop-only: a - // printer profile sets them once for its kinematics, and a wrong value sends + // ConfigOptionMode in PrintConfig.cpp. The axis remap is Develop-only: a + // printer profile sets it once for its kinematics, and a wrong value sends // the gantry outside the machine. - for (auto el : {"preslice_remap_x", "gcode_remap_x", "gcode_back_transform"}) + for (auto el : {"gcode_remap_x", "gcode_remap_y", "gcode_remap_z", "gcode_back_transform"}) toggle_line(el, is_belt); toggle_line("belt_preslice_global", is_belt); - bool belt_global = is_belt && m_config->opt_bool("belt_preslice_global"); - - // preslice_remap_global: superseded by belt_preslice_global - toggle_option("preslice_remap_global", is_belt && !belt_global); - - // Rotation is the only mesh-side belt transform. Gray out its angle/global - // sub-options when no rotation axis is selected. + // Rotation is the only mesh-side belt transform. Gray out its angle when no + // rotation axis is selected. auto rot_axis = m_config->option>("belt_slice_rotation")->value; toggle_option("belt_slice_rotation_angle", is_belt && rot_axis != BeltRotationAxis::None); - toggle_option("belt_slice_rotation_global", is_belt && rot_axis != BeltRotationAxis::None); // Machine-frame transform: derived from the belt tilt. Only the expert - // decouple override is exposed; its angle is enabled only when decoupled. + // decouple override is exposed; its angle is shown only when decoupled. toggle_line("belt_frame_tilt_decouple", is_belt && expert_or_above); - toggle_option("belt_frame_tilt_angle", - is_belt && expert_or_above && m_config->opt_bool("belt_frame_tilt_decouple")); + toggle_line("belt_frame_tilt_angle", + is_belt && expert_or_above && m_config->opt_bool("belt_frame_tilt_decouple")); - // First-layer plane: visible alongside the rest of belt-printer settings. - toggle_line("first_layer_plane", is_belt); - toggle_option("first_layer_plane_offset", is_belt); - toggle_option("first_layer_plane_thickness", is_belt); + toggle_line("first_layer_plane_thickness", is_belt); - for (auto el : {"belt_support_floor_mode", "belt_support_floor_offset", "belt_support_z_offset_mode"}) + for (auto el : {"belt_support_floor_mode", "belt_support_floor_offset"}) toggle_line(el, is_belt); const bool support_parallel_printheads = printer_cfg.opt_bool("support_parallel_printheads"); toggle_line("parallel_printheads_count", support_parallel_printheads); diff --git a/tests/fff_print/test_gcodewriter.cpp b/tests/fff_print/test_gcodewriter.cpp index b0f36c33d9..9ef4a8f39d 100644 --- a/tests/fff_print/test_gcodewriter.cpp +++ b/tests/fff_print/test_gcodewriter.cpp @@ -56,7 +56,6 @@ TEST_CASE("Belt machine coordinates retain a non-45-degree slicing angle", "[GCo config.belt_printer.value = true; config.belt_slice_rotation.value = BeltRotationAxis::X; config.belt_slice_rotation_angle.value = 30.; - config.belt_slice_rotation_global.value = true; config.gcode_back_transform.value = true; config.gcode_remap_x.value = RemapAxis::PosX; config.gcode_remap_y.value = RemapAxis::PosZ; @@ -1030,7 +1029,6 @@ SCENARIO("Belt: the first travel does not lift through the uninitialised origin" 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; diff --git a/tests/fff_print/test_precise_seam.cpp b/tests/fff_print/test_precise_seam.cpp index d5e2709cdd..b5cb913904 100644 --- a/tests/fff_print/test_precise_seam.cpp +++ b/tests/fff_print/test_precise_seam.cpp @@ -1438,7 +1438,6 @@ TEST_CASE("Belt printers slice Precise Seam modifiers in the frame the object wa { "belt_printer", 1 }, { "belt_slice_rotation", "x" }, { "belt_slice_rotation_angle", 45 }, - { "belt_slice_rotation_global", 1 }, { "layer_height", 0.2 }, { "initial_layer_print_height", 0.2 }, { "skirt_loops", 0 }, diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index c0e5572b97..f16a0ce662 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -765,7 +765,6 @@ TEST_CASE("Belt printers never start a scarf seam below the layer", "[Print][bel { "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" }, @@ -815,7 +814,6 @@ TEST_CASE("Belt printers refuse an object taller than the gantry clearance", "[P { "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" }, @@ -851,7 +849,6 @@ TEST_CASE("Belt printers keep the part fan off within the band above the belt", { "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" }, @@ -930,7 +927,6 @@ TEST_CASE("Belt printers slice organic tree supports that reach the belt", "[Pri { "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" }, @@ -1003,7 +999,6 @@ static DynamicPrintConfig belt_test_config() { "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" }, @@ -1039,30 +1034,23 @@ TEST_CASE("Belt-only keys at non-default values leave non-belt G-code unchanged" // Every belt key a profile can carry, at a value that would change a belt print. // belt_printer stays off, so none of them may reach the G-code: the axis remaps are // gated on belt mode, the rest is only read on belt printers. build_plate_tilt_x/y - // and an explicit first_layer_plane are features of their own on a flat bed and are - // left alone here; "leading_edge_only" prints as an outer brim by design. + // is a feature of its own on a flat bed and is left alone here; "leading_edge_only" + // prints as an outer brim by design. config.set_deserialize_strict({ { "belt_printer", 0 }, { "belt_printer_infinite_y", 0 }, { "belt_slice_rotation", "y" }, { "belt_slice_rotation_angle", 30 }, - { "belt_slice_rotation_global", 0 }, { "belt_preslice_global", 0 }, - { "preslice_remap_x", "pos_x" }, - { "preslice_remap_y", "pos_z" }, - { "preslice_remap_z", "neg_y" }, - { "preslice_remap_global", 1 }, { "gcode_remap_x", "rev_x" }, { "gcode_remap_y", "pos_z" }, { "gcode_remap_z", "pos_y" }, { "gcode_back_transform", 0 }, { "belt_frame_tilt_decouple", 1 }, { "belt_frame_tilt_angle", 30 }, - { "first_layer_plane_offset", 1 }, { "first_layer_plane_thickness", 1 }, { "belt_support_floor_offset", -5 }, { "belt_support_floor_mode", "none" }, - { "belt_support_z_offset_mode", "raft_only" }, { "enable_belt_purge_tower", 1 }, { "belt_purge_tower_width", 10 }, { "leading_brim_length", 10 }, @@ -1136,7 +1124,6 @@ TEST_CASE("A support-only change on a belt purge print matches a fresh slice", " { "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" }, diff --git a/tests/fff_print/test_skirt_brim.cpp b/tests/fff_print/test_skirt_brim.cpp index 45086b9d2a..99e7860c3e 100644 --- a/tests/fff_print/test_skirt_brim.cpp +++ b/tests/fff_print/test_skirt_brim.cpp @@ -641,7 +641,6 @@ static DynamicPrintConfig belt_brim_config() { "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" }, @@ -667,7 +666,6 @@ static DynamicPrintConfig belt_brim_multifilament_config(unsigned int filaments, { "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" }, @@ -1246,9 +1244,7 @@ TEST_CASE("Belt brim allows instances placed across the belt", "[SkirtBrim][belt auto multi_instance_has_brim = [](double dx, double dy) { DynamicPrintConfig config = belt_brim_config(); config.set_deserialize_strict({ - { "belt_slice_rotation_global", 0 }, { "belt_preslice_global", 0 }, - { "preslice_remap_global", 0 }, { "brim_type", "outer_only" }, { "brim_width", 4 }, { "brim_object_gap", 0 },