diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 0af44aebf2..949177d4ec 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1387,7 +1387,11 @@ 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. - if (m_last_result_id == gcode_result.id && wxGetApp().is_editor()) { + // 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) { //BBS: add logs BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": the same id %1%, return directly, result %2% ") % m_last_result_id % (&gcode_result); @@ -1429,20 +1433,22 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const } // convert data from PrusaSlicer format to libvgcode format. - // 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. + // Belt printers: when the designed (upright) view is active, back-transform + // the toolpath geometry into model/Cartesian space using the general belt + // inverse (handles the mesh rotation, shear and axis remap). When off, the + // raw machine-frame G-code is shown (useful for checking the transform itself). const bool is_belt = m_belt_view_enabled && print.config().belt_printer.value; - Transform3d belt_inv = is_belt ? compute_belt_back_transform(print.config()) : Transform3d::Identity(); + Transform3d belt_inv = (is_belt && m_belt_show_designed) + ? 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 && gcode_result.belt_z_origin != 0.0f) + if (is_belt && m_belt_show_designed && 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 + const bool apply_belt = is_belt && m_belt_show_designed && !belt_inv.matrix().isApprox(Transform3d::Identity().matrix()); if (apply_belt) { // The linear belt back-transform recovers the print's shape and orientation but not @@ -1679,6 +1685,7 @@ 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) diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 9cd669372f..e5703939b2 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -199,6 +199,8 @@ private: std::vector 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(EMoveType::Count)> m_move_type_counts{}; @@ -262,6 +264,8 @@ mutable bool m_no_render_path { false }; bool m_is_dark = false; bool m_belt_view_enabled = false; + bool m_belt_show_designed = true; // Designed (upright, back-transformed) view by default; off shows + // the raw machine-frame G-code (canvas view menu, hotkey B). float m_belt_angle_deg = 0.f; libvgcode::Viewer m_viewer; @@ -402,6 +406,8 @@ 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(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1b4deced82..808c1831d2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3804,6 +3804,16 @@ bool GLCanvas3D::handle_shortcut(const KeyChord& chord) get_gcode_viewer().get_layers_slider()->switch_one_layer_mode(); m_dirty = true; break; + case Shortcut::ToggleBeltRawGcode: + // Same state as the canvas view 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::GoToLayer: if (!m_gizmos.is_enabled()) { get_gcode_viewer().get_layers_slider()->show_go_to_layer(true); @@ -10334,6 +10344,22 @@ void GLCanvas3D::_render_canvas_toolbar() [p]{p->show_view3D_labels(!p->are_view3D_labels_shown());} ); + // Belt printers, G-code preview only: show the raw machine-frame G-code instead of + // the designed (upright) view. This menu is the only place the toggle lives (plus + // its shortcut); 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()) { + ImGui::Separator(); + 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::PopItemFlag(); ImGui::EndPopup(); } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 1968df996f..1c17a02956 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -369,6 +369,25 @@ 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 range and only-gcode mode so the view doesn't jump on toggle. + // The layer Z values differ between the designed and the raw view (the raw view's are + // machine-frame heights), so keep_z_range alone cannot find the old span: carry the + // slider over by layer index instead. + IMSlider *layers_slider = m_canvas->get_gcode_viewer().get_layers_slider(); + const int lower = layers_slider->GetLowerValue(); + const int higher = layers_slider->GetHigherValue(); + m_loaded_print = nullptr; + load_print(true /*keep_z_range*/, m_only_gcode); + if (higher <= layers_slider->GetMaxValue()) + layers_slider->SetSelectionSpan(lower, higher); +} + //BBS: always load shell at preview void Preview::load_shells(const Print& print, bool force_previewing) { diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 2ad1f8788c..acb3211fd9 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -149,6 +149,7 @@ 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(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 09f3cd2b8f..3684020f8a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -17885,6 +17885,11 @@ void Plater::reload_print() p->preview->reload_print(); } +void Plater::refresh_belt_view() +{ + p->preview->refresh_belt_view(); +} + // BBS wxString Plater::get_project_name() { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index e7d94bc606..cf9a1536bb 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -387,6 +387,7 @@ public: void reload_print(); // 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 + void refresh_belt_view(); // toolpath geometry at load time. Keeps the current layer range and only-gcode mode. // SoftFever diff --git a/src/slic3r/GUI/Shortcuts.cpp b/src/slic3r/GUI/Shortcuts.cpp index 8773c6f364..2395d31778 100644 --- a/src/slic3r/GUI/Shortcuts.cpp +++ b/src/slic3r/GUI/Shortcuts.cpp @@ -149,6 +149,7 @@ constexpr std::array 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), diff --git a/src/slic3r/GUI/Shortcuts.hpp b/src/slic3r/GUI/Shortcuts.hpp index 0e61554e2f..6a58d64971 100644 --- a/src/slic3r/GUI/Shortcuts.hpp +++ b/src/slic3r/GUI/Shortcuts.hpp @@ -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, + ShowLabels, ShowWireframe, ToggleGcodeWindow, ToggleOneLayerMode, ToggleBeltRawGcode, // Application Preferences, Search, SwitchView, CollapseSidebar, ReloadDevicePage, KeyboardShortcuts, // Speed Dial