mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 01:41:03 +00:00
Belt printer: retire the redundant and unused options (#16236)
Follow-up to #16195 and the review discussion on #14394 (yw4z's note about the third column on the *Belt tilt* row). Removes the belt options that are redundant or unused before the branch ships, so they never need compatibility handling after a release, and fixes supports under a leading overhang. Every removed key is on `handle_legacy()`'s ignore list, so existing profiles and 3MFs load silently. ## Removed - **`belt_slice_rotation_global`**, **`preslice_remap_global`**, **`belt_preslice_global`** (*Global mesh transforms*) and **`gcode_back_transform`** — the global mode and the back-transform are what belt printing is; they are presumed on wherever the flags were consulted (`PrintObjectSlice`, `BeltBackTransform`, `BeltGCode`, `Print::process`, `PrintApply`, `GCodeViewer`). The *Belt tilt* row is axis + angle only; the three `fdm_belt_common.json` drop the keys. - **`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. The forward transform is the rotation. - **`belt_support_z_offset_mode`** and **`belt_support_floor_mode`** — the first was never read by a generator; the second's only shipped value (*Generator only*) is now the behaviour. - **`first_layer_plane`**, **`first_layer_plane_offset`**, **`first_layer_plane_thickness`** and `FirstLayerPlane.{cpp,hpp}` — the first-layer band is measured from the belt surface and is one first layer height thick. - `belt_brim_instances_compatible()` and its validation warning: instances along the belt get their brim. ## Supports under a leading overhang (the clipping at the object's local Z = 0) The slicing frame of a belt object started at its lowest vertex, but the belt under the leading end of an overhang lies below that, so no generator could reach it: normal supports stopped at the object's lowest layer, and both tree generators carried extension hacks sized from the pre-rotation bbox and capped at global Z = 0 (right only for the trailing half of the belt). The frame now starts at the lowest belt-floor point under the footprint, less a 10 mm margin along the belt for the base of a support column, and the extensions are gone: - **Normal supports** run in the object frame and get the global belt Z offset shifted onto the result (as organic already did). With the offset on the object layers, a top contact at negative Z turned the intermediate-layer count negative and the generator allocated layers until the kernel killed it — any overhang in the leading half of the belt did this. The first-layer flange expansion is skipped on a belt (the first support layer is the leading tip, not a flange). - **Classic tree** nodes keep dropping until their whole circle is in the belt, so a branch tapers to a tip on the belt instead of stopping a radius above it. - **Organic**: the belt is no longer a support blocker. A blocker is a collision, and a branch descending onto one slides off it, down the belt and ahead of the part; the belt is where branches end, which the per-layer floor clipping already does. Regression test *Belt supports reach the belt under a leading overhang*: a cube with a fin whose underside is parallel to the layers, 20 mm ahead of the cube and up to 41 mm of slicing Z above the belt, for normal, organic and classic tree supports; the lowest support layer must sit on the belt beneath its own lines. The belt object height (the layer range) is now estimated from the box of the mesh as placed on the bed. `raw_bounding_box()` has the instance's Z offset removed, which was harmless for the old rotated-extent estimate but not for one anchored at the belt floor (a point's rotated z and the floor under it move in opposite directions under a Z shift): with the first version of this change every part came out as a wedge, sliced only up to its diagonal, in the GUI and CLI alike. Caught by a GUI test pass; the leading-overhang test now also checks that the whole part is sliced. ## Belt brim after the parallel support step `belt_brim_obstacles()` reads every object's layers and support layers, which another object's support step rebuilds (and now shifts) at the same time. The brim is generated sequentially once the parallel step is over (`PrintObject::generate_belt_brim()`). This is the race behind the Windows arm64 segfault in *Belt brim of each object precedes its perimeters on its own filament*. ## UI - *Belt tilt* is two rows: the angle (Advanced) and the axis (Developer; a profile-level kinematics choice). A shared line is shown by its first option's mode, so they cannot share one. - *Machine frame transforms* is five single-option rows (G-code remap X / Y / Z, Decouple machine-frame tilt, Machine-frame tilt angle — the angle row only appears when decoupled) instead of two multi-column lines; the remap fields got full labels since they stand alone now. - The gravity indicator on the bed is a plain line along the up direction (no cone, 60 % of the axes' length), per yw4z. - The *Show raw G-code (belt only)* legend/canvas toggle and its `B` shortcut are gone; the preview is the designed view. Also carries the two-line `phong.fs` fix from #16226 (merges as a no-op). ## Verification - `libslic3r_tests` 1116 passed (92 648 assertions); `fff_print_tests` 351 passed (561 696 assertions). - `scripts/clang_tidy_diff.py --base upstream/belt-printer`: no findings. - `scripts/orca_profile_tool.py check`: no profile references a removed key. - GUI target builds; a scripted GUI pass (xdotool) checked the settings groups in every mode, slicing, export, instances, the purge tower, calibration dialogs, the wizard, printer switching and 3MF round-trip. The wiki pages (OrcaSlicer/OrcaSlicer_WIKI#374) get a follow-up dropping the removed sections once this is in.
This commit is contained in:
+14
-13
@@ -36,6 +36,7 @@
|
||||
#include <tuple>
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#if BOOST_VERSION >= 107800
|
||||
#include <boost/timer/timer.hpp>
|
||||
@@ -766,25 +767,25 @@ void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform
|
||||
m_gravity_arrow.reset();
|
||||
return;
|
||||
}
|
||||
const Vec3d gravity_dir = -up_dir;
|
||||
|
||||
// Build the arrow model (same dimensions as the axis arrows)
|
||||
if (!m_gravity_arrow.is_initialized()) {
|
||||
const float stem_length = Axes::DefaultStemLength;
|
||||
const float tip_radius = Axes::DefaultTipRadius;
|
||||
const float tip_length = Axes::DefaultTipLength;
|
||||
const float stem_radius = stem_length / 75.f; // same ratio as axis cylinders
|
||||
m_gravity_arrow.init_from(stilized_arrow(16, tip_radius, tip_length, stem_radius, stem_length));
|
||||
// A plain line along the tilted "up" direction -- the way the layers lean, i.e.
|
||||
// the gantry -- drawn like the bed axes (no tip: the other direction is not
|
||||
// possible) and shorter than them, so it reads as a hint inside the YZ corner.
|
||||
const float length = 0.6f * m_axes.get_total_length();
|
||||
if (!m_gravity_arrow.is_initialized() || m_gravity_arrow_length != length) {
|
||||
m_gravity_arrow.reset();
|
||||
m_gravity_arrow.init_from(smooth_cylinder(16, /*Radius*/ length / 75.f, length));
|
||||
m_gravity_arrow_length = length;
|
||||
}
|
||||
|
||||
// The arrow model points along +Z by default. Compute rotation to align with gravity_dir.
|
||||
// Rotation axis = cross(+Z, gravity_dir), angle = acos(dot(+Z, gravity_dir))
|
||||
// The cylinder model points along +Z. Compute the rotation that aligns it with
|
||||
// up_dir: rotation axis = cross(+Z, up_dir), angle = acos(dot(+Z, up_dir)).
|
||||
Vec3d from = Vec3d::UnitZ();
|
||||
Vec3d to = gravity_dir;
|
||||
Vec3d to = up_dir;
|
||||
double dot = from.dot(to);
|
||||
Transform3d rot = Transform3d::Identity();
|
||||
if (dot < -0.9999) {
|
||||
// Nearly opposite — rotate 180° around X
|
||||
// Nearly opposite -- rotate 180 degrees around X
|
||||
rot = Eigen::AngleAxisd(M_PI, Vec3d::UnitX()) * rot;
|
||||
} else if (dot < 0.9999) {
|
||||
Vec3d axis = from.cross(to).normalized();
|
||||
@@ -800,7 +801,7 @@ void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform
|
||||
shader->start_using();
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
Transform3d model_matrix = rot;
|
||||
Transform3d model_matrix = Eigen::Translation3d(m_axes.get_origin()) * rot;
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ private:
|
||||
GLModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
GLModel m_gravity_arrow;
|
||||
float m_gravity_arrow_length{ 0.f };
|
||||
Axes m_axes;
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
@@ -1318,13 +1318,11 @@ std::vector<int> GCodeViewer::get_plater_extruder()
|
||||
// Belt printers: compute the full machine->model back-transform from the print
|
||||
// config, so the "designed" (upright) G-code preview maps each toolpath vertex
|
||||
// back to Cartesian space. The G-code forward pipeline is (BeltKinematics::
|
||||
// to_machine_coords): gcode = MachineFrame( AxisRemap( X ) ), with X = model if
|
||||
// gcode_back_transform (write already un-rotated to Cartesian) else BeltForward(
|
||||
// model). So the inverse is:
|
||||
// model = [BeltForward^-1 if !gcode_back_transform] . AxisRemap^-1 . MachineFrame^-1
|
||||
// All parts are config-driven affines -> handles any rotation/shear/scale/axis-
|
||||
// remap combination. (origin-snap is a per-instance translation that only shifts
|
||||
// position, not orientation, so it is intentionally omitted.)
|
||||
// to_machine_coords): gcode = MachineFrame( AxisRemap( X ) ), with X the model
|
||||
// already un-rotated to Cartesian by the back-transform. So the inverse is:
|
||||
// model = AxisRemap^-1 . MachineFrame^-1
|
||||
// (origin-snap is a per-instance translation that only shifts position, not
|
||||
// orientation, so it is intentionally omitted.)
|
||||
static Transform3d compute_belt_back_transform(const PrintConfig& cfg)
|
||||
{
|
||||
if (!cfg.belt_printer.value)
|
||||
@@ -1339,10 +1337,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) {
|
||||
@@ -1361,11 +1358,7 @@ static Transform3d compute_belt_back_transform(const PrintConfig& cfg)
|
||||
}
|
||||
const Transform3d ar_inv = ar.inverse();
|
||||
|
||||
Transform3d bf_inv = Transform3d::Identity();
|
||||
if (!cfg.gcode_back_transform.value)
|
||||
bf_inv = BeltTransformPipeline::build_forward_transform(cfg).inverse();
|
||||
|
||||
return bf_inv * ar_inv * mf_inv;
|
||||
return ar_inv * mf_inv;
|
||||
}
|
||||
|
||||
//BBS: always load shell at preview
|
||||
@@ -1394,11 +1387,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
m_viewer.set_dim_previous_layers_brightness(0.01f * std::stoi(get_app_config()->get("preview_dim_previous_layers_brightness")));
|
||||
|
||||
// avoid processing if called with the same gcode_result.
|
||||
// On a belt printer the toolpath geometry fed to libvgcode also depends on the
|
||||
// designed/raw view state (the back-transform is applied in convert), so the
|
||||
// same result is converted again only when that view has been toggled.
|
||||
const bool same_belt_view = !m_belt_view_enabled || m_last_belt_show_designed == m_belt_show_designed;
|
||||
if (m_last_result_id == gcode_result.id && wxGetApp().is_editor() && same_belt_view) {
|
||||
if (m_last_result_id == gcode_result.id && wxGetApp().is_editor()) {
|
||||
//BBS: add logs
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": the same id %1%, return directly, result %2% ") % m_last_result_id % (&gcode_result);
|
||||
|
||||
@@ -1440,22 +1429,20 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
}
|
||||
|
||||
// convert data from PrusaSlicer format to libvgcode format.
|
||||
// Belt printers: when the "designed (upright) view" is active, back-transform
|
||||
// the toolpath geometry into model/Cartesian space using the general belt
|
||||
// inverse (handles any mesh rotation + shear + axis remap). When off, the raw
|
||||
// machine-frame G-code is shown (useful for debugging the transform itself).
|
||||
// Belt printers: back-transform the toolpath geometry into model/Cartesian
|
||||
// space using the general belt inverse (handles the mesh rotation, shear and
|
||||
// axis remap), so the part is shown upright, the way it was designed.
|
||||
const bool is_belt = m_belt_view_enabled && print.config().belt_printer.value;
|
||||
Transform3d belt_inv = (is_belt && m_belt_show_designed)
|
||||
? compute_belt_back_transform(print.config()) : Transform3d::Identity();
|
||||
Transform3d belt_inv = is_belt ? compute_belt_back_transform(print.config()) : Transform3d::Identity();
|
||||
// Belt: move positions are stored as gcode_Z + belt_z_origin (the start G-code's
|
||||
// purge-blob advance baked into the machine-Z origin by its G92 Z0 resets). Subtract
|
||||
// that constant before the linear back-transform so every toolpath maps to the model's
|
||||
// belt coordinate. Without it the back-transform mixes the offset with the gantry-Y
|
||||
// term, leaving a per-move designed-Y error that min-corner anchoring cannot remove
|
||||
// when a bridge/keel move happens to cancel it at the bbox minimum.
|
||||
if (is_belt && m_belt_show_designed && gcode_result.belt_z_origin != 0.0f)
|
||||
if (is_belt && gcode_result.belt_z_origin != 0.0f)
|
||||
belt_inv = belt_inv * Transform3d(Eigen::Translation3d(Vec3d(0.0, 0.0, -double(gcode_result.belt_z_origin))));
|
||||
const bool apply_belt = is_belt && m_belt_show_designed
|
||||
const bool apply_belt = is_belt
|
||||
&& !belt_inv.matrix().isApprox(Transform3d::Identity().matrix());
|
||||
if (apply_belt) {
|
||||
// The linear belt back-transform recovers the print's shape and orientation but not
|
||||
@@ -1692,7 +1679,6 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
|
||||
//BBS: move the id to the end of reset
|
||||
m_last_result_id = gcode_result.id;
|
||||
m_last_belt_show_designed = m_belt_show_designed;
|
||||
m_gcode_result = &gcode_result;
|
||||
m_move_type_counts.fill(0);
|
||||
for (auto& move_type_times : m_move_type_times)
|
||||
@@ -5147,33 +5133,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
if (m_nozzle_nums > 1 && (m_viewer.get_view_type() == libvgcode::EViewType::Summary || m_viewer.get_view_type() == libvgcode::EViewType::ColorPrint)) // ORCA show only on summary and filament tab
|
||||
render_legend_color_arr_recommen(window_padding);
|
||||
|
||||
// Belt printer: toggle for viewing designed (upright) vs. machine-frame G-code.
|
||||
// Rendered with a separator and hint text so users can find it easily.
|
||||
if (m_belt_view_enabled) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
ImGui::Dummy({ window_padding, 0 });
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(0.f, 0.59f, 0.53f, 1.f), "%s", _u8L("Belt printer").c_str());
|
||||
ImGui::Dummy({ window_padding, 0 });
|
||||
ImGui::SameLine();
|
||||
// Checked = show the raw machine-frame G-code (designed/upright view off). Worded to
|
||||
// match the canvas-toolbar menu item "Show raw G-code (belt only)". m_belt_show_designed
|
||||
// is the inverse of this checkbox, so bind a temporary and flip it on change.
|
||||
bool show_raw = !m_belt_show_designed;
|
||||
const std::string key = wxGetApp().shortcuts().display(Shortcut::ToggleBeltRawGcode);
|
||||
const std::string label = _u8L("Show raw G-code (belt only)") + (key.empty() ? std::string() : " [" + key + "]");
|
||||
if (ImGui::Checkbox(label.c_str(), &show_raw)) {
|
||||
m_belt_show_designed = !show_raw;
|
||||
// The designed-view back-transform is baked into the toolpath geometry at load
|
||||
// time, so the toggle only takes effect once the preview is re-converted. Defer
|
||||
// the refresh to the next event-loop tick (CallAfter) to avoid re-entering the
|
||||
// preview load from inside legend rendering.
|
||||
if (Plater* plater = wxGetApp().plater())
|
||||
plater->CallAfter([plater]() { plater->refresh_belt_view(); });
|
||||
}
|
||||
}
|
||||
|
||||
legend_height = ImGui::GetCurrentWindow()->Size.y;
|
||||
imgui.end();
|
||||
|
||||
@@ -199,8 +199,6 @@ private:
|
||||
std::vector<int> m_plater_extruder;
|
||||
bool m_gl_data_initialized{ false };
|
||||
unsigned int m_last_result_id{ 0 };
|
||||
// Belt printers: the view the loaded result was converted for (see load_as_gcode).
|
||||
bool m_last_belt_show_designed{ true };
|
||||
//BBS: save m_gcode_result as well
|
||||
const GCodeProcessorResult* m_gcode_result;
|
||||
std::array<unsigned int, static_cast<size_t>(EMoveType::Count)> m_move_type_counts{};
|
||||
@@ -265,8 +263,6 @@ mutable bool m_no_render_path { false };
|
||||
|
||||
bool m_belt_view_enabled = false;
|
||||
float m_belt_angle_deg = 0.f;
|
||||
bool m_belt_show_designed = true; // Toggle: designed (upright, back-transformed) view by default;
|
||||
// turn off (hotkey B) to inspect the raw machine-frame G-code.
|
||||
|
||||
libvgcode::Viewer m_viewer;
|
||||
// ORCA: section view, as the viewer has it. What it cuts away casts no shadow.
|
||||
@@ -406,8 +402,6 @@ public:
|
||||
|
||||
void set_belt_printer(bool enabled, float angle_deg) { m_belt_view_enabled = enabled; m_belt_angle_deg = angle_deg; }
|
||||
bool is_belt_view() const { return m_belt_view_enabled && m_belt_angle_deg > 0.f; }
|
||||
void toggle_belt_show_designed() { if (m_belt_view_enabled) m_belt_show_designed = !m_belt_show_designed; }
|
||||
bool is_belt_show_designed() const { return m_belt_show_designed; }
|
||||
|
||||
size_t get_extruders_count() { return m_extruders_count; }
|
||||
void push_combo_style();
|
||||
|
||||
@@ -3800,16 +3800,6 @@ bool GLCanvas3D::handle_shortcut(const KeyChord& chord)
|
||||
m_dirty = true;
|
||||
request_extra_frame();
|
||||
break;
|
||||
case Shortcut::ToggleBeltRawGcode:
|
||||
// Same state as the legend checkbox and the canvas-toolbar menu item. The designed-view
|
||||
// back-transform is baked into the toolpaths at load time, so the preview is re-converted.
|
||||
if (m_gcode_viewer.is_belt_view()) {
|
||||
m_gcode_viewer.toggle_belt_show_designed();
|
||||
if (Plater* plater = wxGetApp().plater())
|
||||
plater->refresh_belt_view();
|
||||
m_dirty = true;
|
||||
}
|
||||
break;
|
||||
case Shortcut::ToggleOneLayerMode:
|
||||
get_gcode_viewer().get_layers_slider()->switch_one_layer_mode();
|
||||
m_dirty = true;
|
||||
@@ -10256,20 +10246,6 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
ImGui::TextColored(enable ? ImVec4(1,1,1,1) : ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "%s", into_u8(condition ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str());
|
||||
};
|
||||
|
||||
// Belt printers, G-code preview only: toggle the designed (upright) view vs the raw
|
||||
// machine-frame G-code. Same state as the shortcut and the legend checkbox; the reload is
|
||||
// deferred (CallAfter) so the preview is not rebuilt mid-render.
|
||||
if (m_canvas_type == ECanvasType::CanvasPreview && m_gcode_viewer.is_belt_view()) {
|
||||
create_menu_item( _utf8(L("Show raw G-code (belt only)")),
|
||||
true,
|
||||
!m_gcode_viewer.is_belt_show_designed(), // eye lit = raw machine-frame G-code (designed view off)
|
||||
[this, p]{
|
||||
m_gcode_viewer.toggle_belt_show_designed();
|
||||
p->CallAfter([p]{ p->refresh_belt_view(); });
|
||||
}
|
||||
);
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
create_menu_item( _utf8(L("3D Navigator")),
|
||||
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
||||
|
||||
@@ -369,17 +369,6 @@ void Preview::reload_print(bool only_gcode)
|
||||
m_only_gcode = only_gcode;
|
||||
}
|
||||
|
||||
void Preview::refresh_belt_view()
|
||||
{
|
||||
// Re-run the G-code preview conversion so the belt "designed view" toggle takes effect
|
||||
// (the back-transform is baked into the toolpath geometry in GCodeViewer::load_as_gcode,
|
||||
// whose same-result cache also keys on the view state, so the re-convert runs).
|
||||
// Reset m_loaded_print to bypass the "already loaded" guard the way reload_print does, but
|
||||
// keep the current layer (Z) range and only-gcode mode so the view doesn't jump on toggle.
|
||||
m_loaded_print = nullptr;
|
||||
load_print(true /*keep_z_range*/, m_only_gcode);
|
||||
}
|
||||
|
||||
//BBS: always load shell at preview
|
||||
void Preview::load_shells(const Print& print, bool force_previewing)
|
||||
{
|
||||
|
||||
@@ -149,7 +149,6 @@ public:
|
||||
void load_print(bool keep_z_range = false, bool only_gcode = false);
|
||||
void reload_print(bool only_gcode = false);
|
||||
// Belt printers: re-convert the G-code preview so the "designed view" toggle takes effect.
|
||||
void refresh_belt_view();
|
||||
//BBS: always load shell at preview
|
||||
void load_shells(const Print& print, bool force_previewing = false);
|
||||
void reset_shells();
|
||||
|
||||
@@ -17885,11 +17885,6 @@ void Plater::reload_print()
|
||||
p->preview->reload_print();
|
||||
}
|
||||
|
||||
void Plater::refresh_belt_view()
|
||||
{
|
||||
p->preview->refresh_belt_view();
|
||||
}
|
||||
|
||||
// BBS
|
||||
wxString Plater::get_project_name()
|
||||
{
|
||||
|
||||
@@ -388,7 +388,6 @@ public:
|
||||
// Belt printers: re-run the G-code preview conversion so the "designed view" toggle
|
||||
// (hotkey B / legend checkbox) takes effect; the back-transform is applied to the
|
||||
// toolpath geometry at load time. Keeps the current layer range and only-gcode mode.
|
||||
void refresh_belt_view();
|
||||
|
||||
// SoftFever
|
||||
void calib_pa(const Calib_Params& params);
|
||||
|
||||
@@ -149,7 +149,6 @@ constexpr std::array<ShortcutInfo, size_t(Shortcut::Count)> shortcut_table = {{
|
||||
SHORTCUT(ShowWireframe, "show_wireframe", L("Show/Hide wireframe"), CANVAS, { WXK_RETURN, CTRL_SHIFT }),
|
||||
SHORTCUT(ToggleGcodeWindow, "toggle_gcode_window", L("On/Off G-code window"), PREVIEW, { 'C' }),
|
||||
SHORTCUT(ToggleOneLayerMode, "toggle_one_layer_mode", L("On/Off one layer mode of the vertical slider"), PREVIEW, { 'L' }),
|
||||
SHORTCUT(ToggleBeltRawGcode, "toggle_belt_raw_gcode", L("Show raw G-code (belt only)"), PREVIEW, { 'B' }),
|
||||
|
||||
// Application
|
||||
SHORTCUT(Preferences, "preferences", L("Preferences"), GLOBAL, PREFERENCES_CHORD),
|
||||
|
||||
@@ -46,7 +46,7 @@ enum class Shortcut : uint8_t {
|
||||
// Camera
|
||||
ViewDefault, ViewTop, ViewBottom, ViewFront, ViewRear, ViewLeft, ViewRight, ViewPlate, ZoomIn, ZoomOut, Mouse3DSettings,
|
||||
// Display
|
||||
ShowLabels, ShowWireframe, ToggleGcodeWindow, ToggleOneLayerMode, ToggleBeltRawGcode,
|
||||
ShowLabels, ShowWireframe, ToggleGcodeWindow, ToggleOneLayerMode,
|
||||
// Application
|
||||
Preferences, Search, SwitchView, CollapseSidebar, ReloadDevicePage, KeyboardShortcuts,
|
||||
// Speed Dial
|
||||
|
||||
+22
-86
@@ -5250,77 +5250,24 @@ void TabPrinter::build_fff()
|
||||
// Belt tilt: the sole mesh-side transform and the single source of truth for
|
||||
// the physical tilt (drives bed rendering and support gravity tilt too).
|
||||
// Isometric rotation, no distortion; the back-transform inverts it before the
|
||||
// machine-frame remap.
|
||||
{
|
||||
Line line = { L("Belt tilt"),
|
||||
L("Belt tilt axis and angle, applied as a mesh rotation before "
|
||||
"slicing. Also drives bed rendering and support gravity tilt. "
|
||||
"Isometric (no distortion); the back-transform inverts it before "
|
||||
"the machine-frame remap.") };
|
||||
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);
|
||||
}
|
||||
// Support floor: split across lines so each setting's own mode controls
|
||||
// its visibility (floor_mode = Develop, floor_offset = Advanced, z_offset_mode = Expert).
|
||||
// machine-frame remap. The angle is what a user checks against the machine;
|
||||
// the axis is a profile-level kinematics choice, so it is Develop-only. They
|
||||
// are separate rows because a shared line is shown by its first option's mode.
|
||||
belt_og->append_single_option_line("belt_slice_rotation_angle", "printer_basic_information_belt_printer#tilt-angle");
|
||||
belt_og->append_single_option_line("belt_slice_rotation", "printer_basic_information_belt_printer#tilt-axis");
|
||||
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");
|
||||
@@ -6366,41 +6313,30 @@ void TabPrinter::toggle_options()
|
||||
bool expert_or_above = (m_mode >= comExpert);
|
||||
toggle_line("belt_printer_infinite_y", is_belt);
|
||||
// Belt tilt: the sole mesh-side belt transform (visible by default in belt mode).
|
||||
toggle_line("belt_slice_rotation_angle", is_belt);
|
||||
toggle_line("belt_slice_rotation", is_belt);
|
||||
|
||||
// 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"})
|
||||
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<ConfigOptionEnum<BeltRotationAxis>>("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);
|
||||
|
||||
for (auto el : {"belt_support_floor_mode", "belt_support_floor_offset", "belt_support_z_offset_mode"})
|
||||
toggle_line(el, is_belt);
|
||||
toggle_line("belt_support_floor_offset", is_belt);
|
||||
const bool support_parallel_printheads = printer_cfg.opt_bool("support_parallel_printheads");
|
||||
toggle_line("parallel_printheads_count", support_parallel_printheads);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user