mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-28 13:22:06 +00:00
render the G-code preview upright (designed view) + toggle UI
This commit is contained in:
@@ -1140,6 +1140,14 @@ static Transform3d compute_belt_back_transform(const PrintConfig& cfg)
|
|||||||
const Transform3d mf_inv = mft.is_active() ? Transform3d(mft.transform().inverse())
|
const Transform3d mf_inv = mft.is_active() ? Transform3d(mft.transform().inverse())
|
||||||
: Transform3d::Identity();
|
: Transform3d::Identity();
|
||||||
|
|
||||||
|
// Forward G-code axis remap as an affine matrix (out_i = sign * in[r_i % 3], plus a
|
||||||
|
// 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.)
|
||||||
Transform3d ar = Transform3d::Identity();
|
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) };
|
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) {
|
if (rr[0] != 0 || rr[1] != 1 || rr[2] != 2) {
|
||||||
@@ -1172,6 +1180,14 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
{
|
{
|
||||||
m_loaded_as_preview = false;
|
m_loaded_as_preview = false;
|
||||||
|
|
||||||
|
// Belt printers: drive the designed/raw view UI (legend checkbox, hotkey B, canvas-toolbar
|
||||||
|
// menu item) from the loaded print here. Plater::set_bed_shape also calls set_belt_printer(),
|
||||||
|
// but only on bed-shape changes — not reliably on every slice/preview load — so the UI was
|
||||||
|
// staying hidden even though the (config-driven) designed view rendered. The tilt magnitude
|
||||||
|
// comes from the G-code header (gcode_result.belt_tilt_angle, abs of the slicing rotation).
|
||||||
|
m_belt_view_enabled = print.config().belt_printer.value;
|
||||||
|
m_belt_angle_deg = gcode_result.belt_tilt_angle;
|
||||||
|
|
||||||
const bool current_top_layer_only = m_viewer.is_top_layer_only_view_range();
|
const bool current_top_layer_only = m_viewer.is_top_layer_only_view_range();
|
||||||
const bool required_top_layer_only = get_app_config()->get_bool("seq_top_layer_only");
|
const bool required_top_layer_only = get_app_config()->get_bool("seq_top_layer_only");
|
||||||
if (current_top_layer_only != required_top_layer_only)
|
if (current_top_layer_only != required_top_layer_only)
|
||||||
@@ -1260,23 +1276,36 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
// inverse to well outside the model body; if one becomes the bbox minimum it
|
// inverse to well outside the model body; if one becomes the bbox minimum it
|
||||||
// drags the min-corner anchor by ~20mm. Drop moves that land clearly outside the
|
// drags the min-corner anchor by ~20mm. Drop moves that land clearly outside the
|
||||||
// (correct) model bbox — a geometric filter, not a role guess.
|
// (correct) model bbox — a geometric filter, not a role guess.
|
||||||
|
// Tolerance around the model bbox for outlier rejection, and the minimum fraction
|
||||||
|
// of MOVES (by count) the clip must retain before we trust it over the full bbox.
|
||||||
|
// Count, not bbox extent: a single far-flung outlier move (e.g. a belt-entry purge
|
||||||
|
// that maps to y~0) inflates the full bbox so much that a size-fraction test would
|
||||||
|
// wrongly reject the clip and re-include the outlier, dragging the min-corner anchor
|
||||||
|
// by ~the offset. By count the clip keeps ~100% of moves here and ~0% only when the
|
||||||
|
// object is genuinely offset from the belt entry (the real fall-back-to-full case).
|
||||||
|
constexpr double ANCHOR_CLIP_MARGIN_MM = 10.0;
|
||||||
|
constexpr double ANCHOR_CLIP_MIN_KEEP = 0.5;
|
||||||
BoundingBoxf3 tp_bb_clip, tp_bb_full;
|
BoundingBoxf3 tp_bb_clip, tp_bb_full;
|
||||||
const double y_lo = model_bb.defined ? model_bb.min.y() - 10.0 : -1e30;
|
size_t n_filtered = 0, n_clip = 0;
|
||||||
const double y_hi = model_bb.defined ? model_bb.max.y() + 10.0 : 1e30;
|
const double y_lo = model_bb.defined ? model_bb.min.y() - ANCHOR_CLIP_MARGIN_MM : -1e30;
|
||||||
|
const double y_hi = model_bb.defined ? model_bb.max.y() + ANCHOR_CLIP_MARGIN_MM : 1e30;
|
||||||
for (const GCodeProcessorResult::MoveVertex& mv : gcode_result.moves)
|
for (const GCodeProcessorResult::MoveVertex& mv : gcode_result.moves)
|
||||||
if (mv.type == EMoveType::Extrude && mv.layer_id >= 1) { // skip layer-0 prime/skirt
|
if (mv.type == EMoveType::Extrude && mv.layer_id >= 1) { // skip layer-0 prime/skirt
|
||||||
|
++n_filtered;
|
||||||
const Vec3d p = belt_inv * mv.position.cast<double>();
|
const Vec3d p = belt_inv * mv.position.cast<double>();
|
||||||
tp_bb_full.merge(p);
|
tp_bb_full.merge(p);
|
||||||
if (p.y() >= y_lo && p.y() <= y_hi)
|
if (p.y() >= y_lo && p.y() <= y_hi) {
|
||||||
tp_bb_clip.merge(p);
|
tp_bb_clip.merge(p);
|
||||||
|
++n_clip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Use the clipped bbox only when it still holds the bulk of the body (outliers
|
// Use the clipped bbox when it still holds the bulk of the moves (outliers removed).
|
||||||
// removed). If the object sits far from the belt entry the toolpaths are grossly
|
// If the object sits far from the belt entry the toolpaths are grossly offset and the
|
||||||
// offset and the clip would drop most of them — fall back to the full bbox so the
|
// clip drops most of them — fall back to the full bbox so the min-corner anchor still
|
||||||
// min-corner anchor still recovers that gross translation rather than breaking.
|
// recovers that gross translation rather than breaking.
|
||||||
const BoundingBoxf3& tp_bb =
|
const BoundingBoxf3& tp_bb =
|
||||||
(tp_bb_clip.defined && tp_bb_full.defined &&
|
(tp_bb_clip.defined && n_filtered > 0 &&
|
||||||
tp_bb_clip.size().y() >= 0.5 * tp_bb_full.size().y()) ? tp_bb_clip : tp_bb_full;
|
double(n_clip) >= ANCHOR_CLIP_MIN_KEEP * double(n_filtered)) ? tp_bb_clip : tp_bb_full;
|
||||||
if (model_bb.defined && tp_bb.defined) {
|
if (model_bb.defined && tp_bb.defined) {
|
||||||
// Anchor the back-transformed toolpath body onto the upright model bbox by
|
// Anchor the back-transformed toolpath body onto the upright model bbox by
|
||||||
// its MIN corner. (Center anchoring was tried and regressed when the toolpath
|
// its MIN corner. (Center anchoring was tried and regressed when the toolpath
|
||||||
@@ -1287,9 +1316,8 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
// translation, which this min-corner step recovers.
|
// translation, which this min-corner step recovers.
|
||||||
const Vec3d d = model_bb.min - tp_bb.min;
|
const Vec3d d = model_bb.min - tp_bb.min;
|
||||||
belt_inv = Transform3d(Eigen::Translation3d(d)) * belt_inv;
|
belt_inv = Transform3d(Eigen::Translation3d(d)) * belt_inv;
|
||||||
BOOST_LOG_TRIVIAL(debug) << "[BELT-PREVIEW] z_origin=" << gcode_result.belt_z_origin
|
BOOST_LOG_TRIVIAL(debug) << "[BELT-PREVIEW] anchor d=[" << d.x() << "," << d.y() << "," << d.z()
|
||||||
<< " model_bb.y=[" << model_bb.min.y() << "," << model_bb.max.y()
|
<< "] (clip kept " << n_clip << "/" << n_filtered << " moves)";
|
||||||
<< "] tp_bb.y=[" << tp_bb.min.y() << "," << tp_bb.max.y() << "] d.y=" << d.y();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
libvgcode::GCodeInputData data = libvgcode::convert(gcode_result, str_tool_colors, str_color_print_colors, m_viewer,
|
libvgcode::GCodeInputData data = libvgcode::convert(gcode_result, str_tool_colors, str_color_print_colors, m_viewer,
|
||||||
@@ -2423,12 +2451,12 @@ void GCodeViewer::render_toolpaths()
|
|||||||
{
|
{
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
Matrix4f view = camera.get_view_matrix().matrix().cast<float>();
|
Matrix4f view = camera.get_view_matrix().matrix().cast<float>();
|
||||||
// Belt "designed" (upright) view is now produced by back-transforming the
|
// Belt "designed" (upright) view is produced by back-transforming the toolpath
|
||||||
// toolpath GEOMETRY into model space at load time (see load_as_gcode ->
|
// GEOMETRY into model space at load time (see load_as_gcode ->
|
||||||
// libvgcode::convert with m_belt_inverse_transform). The camera is therefore
|
// compute_belt_back_transform -> libvgcode::convert). The camera is left untouched
|
||||||
// left untouched here; transforming the view as well would double-apply the
|
// here; transforming the view as well would double-apply the inverse. Baking the
|
||||||
// inverse. Keeping m_belt_inverse_transform on the geometry (not the camera)
|
// transform into the geometry (not the camera) also keeps the bed and toolpaths in
|
||||||
// also keeps the bed and toolpaths in the same frame so they stay aligned.
|
// the same frame so they stay aligned.
|
||||||
const libvgcode::Mat4x4 converted_view_matrix = libvgcode::convert(view);
|
const libvgcode::Mat4x4 converted_view_matrix = libvgcode::convert(view);
|
||||||
const libvgcode::Mat4x4 converted_projetion_matrix = libvgcode::convert(static_cast<Matrix4f>(camera.get_projection_matrix().matrix().cast<float>()));
|
const libvgcode::Mat4x4 converted_projetion_matrix = libvgcode::convert(static_cast<Matrix4f>(camera.get_projection_matrix().matrix().cast<float>()));
|
||||||
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||||
@@ -4822,7 +4850,19 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
|||||||
ImGui::TextColored(ImVec4(0.f, 0.59f, 0.53f, 1.f), "%s", _u8L("Belt Printer").c_str());
|
ImGui::TextColored(ImVec4(0.f, 0.59f, 0.53f, 1.f), "%s", _u8L("Belt Printer").c_str());
|
||||||
ImGui::Dummy({ window_padding, 0 });
|
ImGui::Dummy({ window_padding, 0 });
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Checkbox(_u8L("Show designed view (upright) [B]").c_str(), &m_belt_show_designed);
|
// 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;
|
||||||
|
if (ImGui::Checkbox(_u8L("Show raw G-code (belt only) [B]").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;
|
legend_height = ImGui::GetCurrentWindow()->Size.y;
|
||||||
|
|||||||
@@ -247,7 +247,6 @@ mutable bool m_no_render_path { false };
|
|||||||
float m_belt_angle_deg = 0.f;
|
float m_belt_angle_deg = 0.f;
|
||||||
bool m_belt_show_designed = true; // Toggle: designed (upright, back-transformed) view by default;
|
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.
|
// turn off (hotkey B) to inspect the raw machine-frame G-code.
|
||||||
Transform3d m_belt_inverse_transform{Transform3d::Identity()};
|
|
||||||
|
|
||||||
libvgcode::Viewer m_viewer;
|
libvgcode::Viewer m_viewer;
|
||||||
bool m_loaded_as_preview{ false };
|
bool m_loaded_as_preview{ false };
|
||||||
@@ -349,7 +348,6 @@ public:
|
|||||||
void export_toolpaths_to_obj(const char* filename) const;
|
void export_toolpaths_to_obj(const char* filename) const;
|
||||||
|
|
||||||
void set_belt_printer(bool enabled, float angle_deg) { m_belt_view_enabled = enabled; m_belt_angle_deg = angle_deg; }
|
void set_belt_printer(bool enabled, float angle_deg) { m_belt_view_enabled = enabled; m_belt_angle_deg = angle_deg; }
|
||||||
void set_belt_inverse_transform(const Transform3d& t) { m_belt_inverse_transform = t; }
|
|
||||||
bool is_belt_view() const { return m_belt_view_enabled && m_belt_angle_deg > 0.f; }
|
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; }
|
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; }
|
bool is_belt_show_designed() const { return m_belt_show_designed; }
|
||||||
|
|||||||
@@ -3512,6 +3512,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||||||
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr &&
|
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr &&
|
||||||
m_gcode_viewer.is_belt_view()) {
|
m_gcode_viewer.is_belt_view()) {
|
||||||
m_gcode_viewer.toggle_belt_show_designed();
|
m_gcode_viewer.toggle_belt_show_designed();
|
||||||
|
// The designed-view back-transform is baked into the toolpath geometry at load
|
||||||
|
// time, so the toggle only takes visual effect once the preview is re-converted.
|
||||||
|
if (Plater* plater = wxGetApp().plater())
|
||||||
|
plater->refresh_belt_view();
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -9190,6 +9194,21 @@ 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());
|
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 hotkey B 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")),
|
create_menu_item( _utf8(L("3D Navigator")),
|
||||||
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
||||||
wxGetApp().show_3d_navigator(),
|
wxGetApp().show_3d_navigator(),
|
||||||
|
|||||||
@@ -351,6 +351,17 @@ void Preview::reload_print(bool only_gcode)
|
|||||||
m_only_gcode = 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,
|
||||||
|
// and belt printers are exempt from the same-result-id load cache 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
|
//BBS: always load shell at preview
|
||||||
void Preview::load_shells(const Print& print, bool force_previewing)
|
void Preview::load_shells(const Print& print, bool force_previewing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ public:
|
|||||||
//BBS: add only gcode mode
|
//BBS: add only gcode mode
|
||||||
void load_print(bool keep_z_range = false, bool only_gcode = false);
|
void load_print(bool keep_z_range = false, bool only_gcode = false);
|
||||||
void reload_print(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
|
//BBS: always load shell at preview
|
||||||
void load_shells(const Print& print, bool force_previewing = false);
|
void load_shells(const Print& print, bool force_previewing = false);
|
||||||
void reset_shells();
|
void reset_shells();
|
||||||
|
|||||||
@@ -11381,31 +11381,13 @@ void Plater::priv::set_bed_shape(const Pointfs &shape,
|
|||||||
bed.set_belt_printer(true, static_cast<float>(belt_angle), tilt_axis);
|
bed.set_belt_printer(true, static_cast<float>(belt_angle), tilt_axis);
|
||||||
if (preview)
|
if (preview)
|
||||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(true, static_cast<float>(belt_angle));
|
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(true, static_cast<float>(belt_angle));
|
||||||
|
// The belt "designed view" back-transform is rebuilt from the print config at
|
||||||
// Compute the inverse of the mesh-side belt transform for the G-code
|
// G-code load time (GCodeViewer::compute_belt_back_transform), so no mesh-side
|
||||||
// viewer. The sole mesh transform is the slicing rotation; build its
|
// inverse needs to be pushed to the viewer here.
|
||||||
// matrix from config and hand the viewer its inverse (rotation is
|
|
||||||
// orthogonal, so the inverse is the transpose).
|
|
||||||
Transform3d forward = Transform3d::Identity();
|
|
||||||
if (rot_axis != BeltRotationAxis::None && std::abs(rot_angle) > EPSILON) {
|
|
||||||
Vec3d unit_axis = Vec3d::UnitX();
|
|
||||||
switch (rot_axis) {
|
|
||||||
case BeltRotationAxis::X: unit_axis = Vec3d::UnitX(); break;
|
|
||||||
case BeltRotationAxis::Y: unit_axis = Vec3d::UnitY(); break;
|
|
||||||
case BeltRotationAxis::Z: unit_axis = Vec3d::UnitZ(); break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
forward.linear() = Eigen::AngleAxisd(Geometry::deg2rad(rot_angle), unit_axis).toRotationMatrix();
|
|
||||||
}
|
|
||||||
Transform3d inverse = forward.inverse();
|
|
||||||
if (preview)
|
|
||||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_inverse_transform(inverse);
|
|
||||||
} else {
|
} else {
|
||||||
bed.set_belt_printer(false, 0.f);
|
bed.set_belt_printer(false, 0.f);
|
||||||
if (preview) {
|
if (preview)
|
||||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(false, 0.f);
|
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(false, 0.f);
|
||||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_inverse_transform(Transform3d::Identity());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14166,6 +14148,11 @@ void Plater::reload_print()
|
|||||||
p->preview->reload_print();
|
p->preview->reload_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::refresh_belt_view()
|
||||||
|
{
|
||||||
|
p->preview->refresh_belt_view();
|
||||||
|
}
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
wxString Plater::get_project_name()
|
wxString Plater::get_project_name()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -329,6 +329,10 @@ public:
|
|||||||
void load_gcode(const wxString& filename);
|
void load_gcode(const wxString& filename);
|
||||||
void reload_gcode_from_disk();
|
void reload_gcode_from_disk();
|
||||||
void reload_print();
|
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
|
||||||
|
// toolpath geometry at load time. Keeps the current layer range and only-gcode mode.
|
||||||
|
void refresh_belt_view();
|
||||||
|
|
||||||
// SoftFever
|
// SoftFever
|
||||||
void calib_pa(const Calib_Params& params);
|
void calib_pa(const Calib_Params& params);
|
||||||
|
|||||||
Reference in New Issue
Block a user