Preview: reuse a belt print's toolpaths until the view is toggled (#16173)

raistlin7447 pointed this out on #14394. The preview skips reconverting
a G-code result it already shows, but belt printers were exempt from
that check, so every time you came back to the Preview tab on a belt
print, it reconverted every toolpath and uploaded it to the GPU again,
even though nothing had changed.

The exemption existed for one reason: switching between the designed and
raw views changes the toolpaths for the same result, so the B toggle
needs a fresh conversion. This change keeps that, but narrows it. The
viewer now remembers which view the result was converted for and reuses
it as long as the view hasn't changed. B, the legend checkbox and the
toolbar menu still trigger a new conversion. The print settings the
back-transform reads can't change without producing a new G-code result,
so the result id covers those the same way it does for every other
printer.

I checked it with the same scripted GUI run on both builds: a BabyBelt
Pro benchy, sliced once, then three Prepare → Preview round trips and
two presses of B, counting the viewer's own log messages.

- Before: 10 full conversions, 0 reuses.
- After: 3 full conversions (the slice and the two B presses) and 7
reuses for the tab switches. B still switches views and comes back
exactly.

The merged tree builds cleanly, and the fff_print (including all the
belt tests) and libslic3r suites pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01AJzy1xeQV3FePh5HfahDyn
This commit is contained in:
Joseph Robertson
2026-10-05 15:46:43 -05:00
committed by GitHub
3 changed files with 9 additions and 6 deletions
+6 -5
View File
@@ -1390,11 +1390,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.
// Belt printers are exempt: the toolpath geometry fed to libvgcode depends on
// the current designed/raw view state (back-transform applied in convert), so
// re-running the conversion is required for the upright view and for toggling
// it (hotkey B) to take effect even when the G-code itself is unchanged.
if (m_last_result_id == gcode_result.id && wxGetApp().is_editor() && !print.config().belt_printer.value) {
// 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 = !print.config().belt_printer.value || 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);
@@ -1688,6 +1688,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)
+2
View File
@@ -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{};
+1 -1
View File
@@ -373,7 +373,7 @@ 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,
// and belt printers are exempt from the same-result-id load cache so the re-convert runs).
// 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;