mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-07 07:41:06 +00:00
Belt printer: bring back the raw G-code view in the canvas view menu (#16241)
The *Show raw G-code (belt only)* toggle retired in #16236 returns, as an item of the Preview canvas view menu (the eye-icon popup, after *Labels*) with its `B` shortcut, and only there: no legend checkbox. Unlit, the preview shows the designed (upright) view; lit, the raw machine-frame G-code, which is what to look at when checking the machine frame transforms. The item only appears on a belt printer in Preview. The toggle is view only (exported G-code is byte-identical either way), and the layer slider now keeps its layer index across the reload (the layer Z values differ between the two views, so the old keep-by-Z lost the position). ## Verification - Scripted GUI pass: item present only in the belt Preview menu (absent in Prepare and on a non-belt printer), toggles from the menu and from `B` with the eye following the state, legend has no belt entry, exported G-code identical with the view on and off, slider stays at its layer through toggles, 3MF reopen and printer switch unaffected. - `fff_print_tests` 355 passed, `libslic3r_tests` 1116 passed; `scripts/clang_tidy_diff.py --base upstream/belt-printer`: no findings. Wiki: OrcaSlicer/OrcaSlicer_WIKI#374 documents the menu item and shortcut with screenshots.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -199,6 +199,8 @@ 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{};
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -149,6 +149,7 @@ 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,
|
||||
ShowLabels, ShowWireframe, ToggleGcodeWindow, ToggleOneLayerMode, ToggleBeltRawGcode,
|
||||
// Application
|
||||
Preferences, Search, SwitchView, CollapseSidebar, ReloadDevicePage, KeyboardShortcuts,
|
||||
// Speed Dial
|
||||
|
||||
Reference in New Issue
Block a user