mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-16 15:32:09 +00:00
Part 2: Replace belt rotation w/ per-axis shear transforms and G-code axis remap
- Replace monolithic belt rotation transform with independent per-axis
shear controls (mode/angle/source-axis for X, Y, Z) and G-code axis
remapping, giving full flexibility to match any belt printer's
coordinate system
- Remove all rotation mode logic and intermediate type+axes dropdowns,
simplifying the pipeline to pure shear matrices while preserving the
default behavior (Y += Z*cot(45deg) with identity remap)
- Clean up GCodeWriter, GCodeProcessor, and GCodeViewer for the new
shear-only model; expose 12 new settings in printer UI via
Tab.cpp/Preset.cpp
Implement belt printer tilted slicing
Implement the core belt slicing pipeline that makes the slicer
tilt-aware:
Step 1: GCodeWriter::to_machine_coords() - R(+alpha, X) rotation
from slicing frame to machine frame
Step 2: PrintObject - belt-rotated object height calculation
(y*sin(a) + z*cos(a)) for correct layer count
Step 3: PrintObjectSlice - apply R(-alpha, X) rotation trafo so
horizontal slice planes correspond to belt-parallel planes,
with Z-shift computed from model volumes
Step 4: GCodeProcessor - machine-frame preview (no transform needed)
Step 5: 3DBed - rotate bed visualization about X by belt angle
Fix: belt surface IS the build plate, no mesh rotation
Currently still slicing perpendicular to the belt normal. Need to figure out why.
Fix G-code Z sign: use R(-alpha, X) so Z+ is away from belt
The previous R(+alpha, X) transform produced negative Z values
(-y*sin(a) term dominated). Changed to R(-alpha, X) which gives
machine_z = y*sin(a) + z*cos(a), always positive for points
above the belt surface. Z increases with each layer as expected.
reverting and changing slice methodology
Add pink slicing direction arrow from origin
Shows the effective slicing direction (gantry normal) as a pink
arrow from the origin. Shorter and wider than the gravity arrow.
Direction: R(+alpha, X) * Z = (0, -sin(a), cos(a)), which is
the layer stacking direction in the original mesh frame.
Fix slicing arrow visibility and add raw G-code toggle
- Disable depth test for pink slicing arrow so it renders on top of
the tilted bed geometry (was being occluded)
- Remove unnecessary 5mm Z-offset from arrow position
- Add m_belt_show_raw toggle to GCodeViewer
- Add "Show raw G-code (slicing frame)" checkbox in legend when
belt mode is active
Implement to_machine_coords inverse rotation for belt printer G-code
The slicing pipeline rotates the mesh by R(-alpha, X) and shifts Z to
start at 0. The G-code output now undoes this transform via
to_machine_coords: R(+alpha, X) * T(0,0,+z_shift), recovering the
original machine-frame coordinates where Y is horizontal and Z is
vertical.
Changes:
- GCodeWriter: implement to_machine_coords with inverse rotation + Z-shift
- GCodeWriter: add belt_z_shift member and setter/getter
- GCode.cpp: compute Z-shift from print objects (same logic as
PrintObjectSlice) and pass to writer; write z_shift to G-code header
- GCodeProcessor: parse belt_z_shift from G-code header
- GCodeViewer: store belt_z_shift from processor result
Wire raw G-code toggle to apply slicing-frame view transform
When "Show raw G-code (slicing frame)" is checked in the preview
legend, the view matrix is modified to apply R(-alpha, X) * T(0,0,-z_shift)
to the toolpath rendering. This shows the G-code as it was during
slicing: rotated part with horizontal layers.
Default (unchecked): machine-frame view — upright part with tilted layers.
Remove belt printer placeholder comment from GCodeProcessor
The preview now correctly displays machine-frame G-code with the
optional raw view toggle. No transform is needed in the processor.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "Exception.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Geometry/ConvexHull.hpp"
|
||||
#include "GCode/PrintExtents.hpp"
|
||||
#include "GCode/Thumbnails.hpp"
|
||||
@@ -2414,8 +2415,28 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
m_writer.set_is_bbl_machine(is_bbl_printers);
|
||||
|
||||
// Belt printer: initialize coordinate transformation on the writer.
|
||||
if (print.config().belt_printer.value)
|
||||
if (print.config().belt_printer.value) {
|
||||
m_writer.set_belt_angle(print.config().belt_printer_angle.value);
|
||||
// Compute the Z-shift that was applied during slicing (same logic as PrintObjectSlice.cpp).
|
||||
// This is needed by to_machine_coords() to undo the slicing transform.
|
||||
// For multiple objects, use the minimum min_z_rotated across all objects.
|
||||
double angle_rad = Geometry::deg2rad(print.config().belt_printer_angle.value);
|
||||
Transform3d belt_rotation = Transform3d::Identity();
|
||||
belt_rotation.rotate(Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()));
|
||||
double global_min_z = std::numeric_limits<double>::max();
|
||||
for (const PrintObject *obj : print.objects()) {
|
||||
Transform3d obj_trafo = belt_rotation * obj->trafo_centered();
|
||||
for (const ModelVolume *mv : obj->model_object()->volumes) {
|
||||
if (! mv->is_model_part() && ! mv->is_modifier())
|
||||
continue;
|
||||
BoundingBoxf3 bb = mv->mesh().bounding_box();
|
||||
bb = bb.transformed(obj_trafo * mv->get_matrix());
|
||||
global_min_z = std::min(global_min_z, bb.min.z());
|
||||
}
|
||||
}
|
||||
if (global_min_z != std::numeric_limits<double>::max() && std::abs(global_min_z) > EPSILON)
|
||||
m_writer.set_belt_z_shift(global_min_z); // typically negative
|
||||
}
|
||||
|
||||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
@@ -2507,8 +2528,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// Write information on the generator.
|
||||
file.write_format("; generated by %s on %s\n", Slic3r::header_slic3r_generated().c_str(), Slic3r::Utils::local_timestamp().c_str());
|
||||
// Belt printer: embed angle in header for G-code processor detection.
|
||||
if (print.config().belt_printer.value)
|
||||
if (print.config().belt_printer.value) {
|
||||
file.write_format("; belt_printer_angle = %.1f\n", print.config().belt_printer_angle.value);
|
||||
file.write_format("; belt_z_shift = %.4f\n", m_writer.belt_z_shift());
|
||||
}
|
||||
if (is_bbl_printers)
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||
//BBS: total layer number
|
||||
|
||||
@@ -2597,8 +2597,6 @@ void GCodeProcessor::finalize(bool post_process)
|
||||
}
|
||||
}
|
||||
|
||||
// Belt printer: preview coordinate transform placeholder (to be implemented in next cycle).
|
||||
|
||||
calculate_time(m_result);
|
||||
|
||||
// process the time blocks
|
||||
@@ -3053,6 +3051,13 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
||||
} catch (...) {}
|
||||
return;
|
||||
}
|
||||
// Belt printer Z-shift for raw G-code toggle in preview.
|
||||
if (boost::starts_with(comment, " belt_z_shift = ")) {
|
||||
try {
|
||||
m_result.belt_z_shift = std::stof(std::string(comment.substr(16)));
|
||||
} catch (...) {}
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe start tag
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||
|
||||
@@ -227,8 +227,9 @@ class Print;
|
||||
bool support_traditional_timelapse{true};
|
||||
float printable_height;
|
||||
float z_offset;
|
||||
// Belt printer: angle for coordinate transformation in preview.
|
||||
// Belt printer: angle and Z-shift for coordinate transformation in preview.
|
||||
float belt_printer_angle{ 0.f };
|
||||
float belt_z_shift{ 0.f };
|
||||
SettingsIds settings_ids;
|
||||
size_t filaments_count;
|
||||
bool backtrace_enabled;
|
||||
|
||||
@@ -29,8 +29,20 @@ void GCodeWriter::set_belt_angle(double angle_deg)
|
||||
|
||||
Vec3d GCodeWriter::to_machine_coords(const Vec3d &pos) const
|
||||
{
|
||||
// Belt printer: coordinate transform placeholder (to be implemented in next cycle).
|
||||
return pos;
|
||||
if (!is_belt_printer())
|
||||
return pos;
|
||||
|
||||
// Undo the slicing transform to recover machine-frame coordinates.
|
||||
// Slicing applied: T(0,0,-min_z_rot) * R(-alpha, X) * original_pos
|
||||
// Inverse: R(+alpha, X) * T(0,0,+min_z_rot) * slicing_pos
|
||||
//
|
||||
// First undo the Z-shift, then apply R(+alpha, X).
|
||||
double sz = pos.z() + m_belt_z_shift; // undo T(0,0,-min_z_rot)
|
||||
return Vec3d(
|
||||
pos.x(),
|
||||
pos.y() * m_belt_cos - sz * m_belt_sin, // R(+alpha, X)
|
||||
pos.y() * m_belt_sin + sz * m_belt_cos
|
||||
);
|
||||
}
|
||||
|
||||
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
||||
|
||||
@@ -127,8 +127,10 @@ public:
|
||||
|
||||
// Belt printer: set the belt angle and precompute sin/cos for coordinate transformation.
|
||||
void set_belt_angle(double angle_deg);
|
||||
void set_belt_z_shift(double z_shift) { m_belt_z_shift = z_shift; }
|
||||
double belt_z_shift() const { return m_belt_z_shift; }
|
||||
bool is_belt_printer() const { return m_belt_angle_rad != 0.; }
|
||||
// Transform a point from the slicing frame to machine/world coordinates (inverse shear).
|
||||
// Transform a point from the slicing frame to machine/world coordinates (inverse rotation).
|
||||
Vec3d to_machine_coords(const Vec3d &pos) const;
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
@@ -184,10 +186,11 @@ public:
|
||||
//SoftFever
|
||||
bool m_is_bbl_printers = false;
|
||||
|
||||
// Belt printer coordinate transformation (YZ shear)
|
||||
// Belt printer coordinate transformation (inverse of slicing rotation)
|
||||
double m_belt_angle_rad = 0.;
|
||||
double m_belt_cos = 1.0;
|
||||
double m_belt_sin = 0.0;
|
||||
double m_belt_z_shift = 0.; // Z-shift applied during slicing (min_z_rotated, typically negative)
|
||||
double m_current_speed;
|
||||
bool m_is_first_layer = true;
|
||||
|
||||
|
||||
@@ -3392,7 +3392,13 @@ void PrintObject::update_slicing_parameters()
|
||||
// Orca: updated function call for XYZ shrinkage compensation
|
||||
if (!m_slicing_params.valid) {
|
||||
coordf_t object_height = this->model_object()->max_z();
|
||||
// Belt printer: height adjustment placeholder (to be implemented in next cycle).
|
||||
if (this->print()->config().belt_printer.value) {
|
||||
// After mesh rotation R(-alpha, X), effective height in the slicing
|
||||
// direction is y_extent*sin(a) + z_extent*cos(a).
|
||||
double angle_rad = Geometry::deg2rad(this->print()->config().belt_printer_angle.value);
|
||||
BoundingBoxf3 bb = this->model_object()->raw_bounding_box();
|
||||
object_height = bb.size().y() * std::sin(angle_rad) + bb.size().z() * std::cos(angle_rad);
|
||||
}
|
||||
m_slicing_params = SlicingParameters::create_from_config(this->print()->config(), m_config, object_height,
|
||||
this->object_extruders(), this->print()->shrinkage_compensation());
|
||||
}
|
||||
@@ -3432,9 +3438,14 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
|
||||
sort_remove_duplicates(object_extruders);
|
||||
//FIXME add painting extruders
|
||||
|
||||
if (object_max_z <= 0.f)
|
||||
object_max_z = (float)model_object.raw_bounding_box().size().z();
|
||||
// Belt printer: height adjustment placeholder (to be implemented in next cycle).
|
||||
if (object_max_z <= 0.f) {
|
||||
BoundingBoxf3 bb = model_object.raw_bounding_box();
|
||||
object_max_z = (float)bb.size().z();
|
||||
if (print_config.belt_printer.value) {
|
||||
double angle_rad = Geometry::deg2rad(print_config.belt_printer_angle.value);
|
||||
object_max_z = (float)(bb.size().y() * std::sin(angle_rad) + bb.size().z() * std::cos(angle_rad));
|
||||
}
|
||||
}
|
||||
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders, object_shrinkage_compensation);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,25 @@ static std::vector<VolumeSlices> slice_volumes_inner(
|
||||
params_base.closing_radius = print_object_config.slice_closing_radius.value;
|
||||
params_base.extra_offset = 0;
|
||||
params_base.trafo = object_trafo;
|
||||
// Belt printer: mesh transform placeholder (to be implemented in next cycle).
|
||||
if (print_config.belt_printer.value) {
|
||||
double angle_rad = Geometry::deg2rad(print_config.belt_printer_angle.value);
|
||||
// Rotate mesh by -alpha about X so horizontal slice planes = gantry-parallel planes.
|
||||
// The gantry (XY) is tilted by belt_printer_angle; this rotation aligns it with horizontal.
|
||||
Transform3d belt_rotation = Transform3d::Identity();
|
||||
belt_rotation.rotate(Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()));
|
||||
params_base.trafo = belt_rotation * params_base.trafo;
|
||||
// Compute Z-shift from model_volumes: find min-Z of all rotated meshes
|
||||
// so the rotated geometry starts at Z=0 (the belt surface in slicing frame).
|
||||
double min_z_rotated = std::numeric_limits<double>::max();
|
||||
for (const ModelVolume *mv : model_volumes) {
|
||||
if (!model_volume_needs_slicing(*mv)) continue;
|
||||
BoundingBoxf3 bb = mv->mesh().bounding_box();
|
||||
bb = bb.transformed(params_base.trafo * mv->get_matrix());
|
||||
min_z_rotated = std::min(min_z_rotated, bb.min.z());
|
||||
}
|
||||
if (min_z_rotated != std::numeric_limits<double>::max() && std::abs(min_z_rotated) > EPSILON)
|
||||
params_base.trafo = Eigen::Translation3d(0, 0, -min_z_rotated) * params_base.trafo;
|
||||
}
|
||||
//BBS: 0.0025mm is safe enough to simplify the data to speed slicing up for high-resolution model.
|
||||
//Also has on influence on arc fitting which has default resolution 0.0125mm.
|
||||
params_base.resolution = print_config.resolution <= 0.001 ? 0.0f : 0.0025;
|
||||
|
||||
@@ -387,17 +387,18 @@ void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix,
|
||||
|
||||
m_model.set_color(m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR);
|
||||
|
||||
// Belt printer: bed view transform placeholder (to be implemented in next cycle).
|
||||
Transform3d belt_view_matrix = view_matrix;
|
||||
// Belt printer: bed rotation is applied inside render_model() and render_default()
|
||||
// using m_is_belt_printer and m_belt_angle members.
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case Type::System: { render_system(canvas, belt_view_matrix, projection_matrix, bottom); break; }
|
||||
case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom); break; }
|
||||
default:
|
||||
case Type::Custom: { render_custom(canvas, belt_view_matrix, projection_matrix, bottom); break; }
|
||||
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom); break; }
|
||||
}
|
||||
|
||||
render_gravity_arrow(view_matrix, projection_matrix);
|
||||
render_slicing_arrow(view_matrix, projection_matrix);
|
||||
render_slicing_plane(view_matrix, projection_matrix);
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
@@ -698,7 +699,13 @@ void Bed3D::render_model(const Transform3d& view_matrix, const Transform3d& proj
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
const Transform3d model_matrix = Geometry::assemble_transform(m_model_offset);
|
||||
Transform3d model_matrix = Geometry::assemble_transform(m_model_offset);
|
||||
// Belt printer: rotate the bed model about X so the belt tilt is visible.
|
||||
// Negative angle: belt surface tilts downward away from the nozzle.
|
||||
if (m_is_belt_printer && m_belt_angle > 0.f) {
|
||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle));
|
||||
model_matrix = Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()) * model_matrix;
|
||||
}
|
||||
shader->set_uniform("volume_world_matrix", model_matrix);
|
||||
shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
@@ -798,6 +805,58 @@ void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
void Bed3D::render_slicing_arrow(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
if (!m_is_belt_printer || m_belt_angle <= 0.f)
|
||||
return;
|
||||
|
||||
// Build the arrow model: shorter and wider than the gravity arrow.
|
||||
if (!m_slicing_arrow.is_initialized()) {
|
||||
const float stem_length = 15.0f; // shorter than gravity arrow (25)
|
||||
const float stem_radius = 1.0f; // wider than gravity arrow (~0.33)
|
||||
const float tip_radius = 3.0f; // wider tip
|
||||
const float tip_length = 5.0f;
|
||||
m_slicing_arrow.init_from(stilized_arrow(16, tip_radius, tip_length, stem_radius, stem_length));
|
||||
}
|
||||
|
||||
// The slicing direction: layers stack along the gantry normal.
|
||||
// With mesh rotation R(-alpha, X), the slicing Z-axis in the original frame
|
||||
// points in direction R(+alpha, X) * (0, 0, 1) = (0, -sin(alpha), cos(alpha)).
|
||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle));
|
||||
Vec3d slice_dir = Vec3d(0., -std::sin(angle_rad), std::cos(angle_rad)).normalized();
|
||||
|
||||
// Compute rotation to align +Z (arrow default) with slice_dir.
|
||||
Vec3d from = Vec3d::UnitZ();
|
||||
double dot = from.dot(slice_dir);
|
||||
Transform3d rot = Transform3d::Identity();
|
||||
if (dot < -0.9999) {
|
||||
rot = Eigen::AngleAxisd(M_PI, Vec3d::UnitX()) * rot;
|
||||
} else if (dot < 0.9999) {
|
||||
Vec3d axis = from.cross(slice_dir).normalized();
|
||||
double angle = std::acos(std::clamp(dot, -1.0, 1.0));
|
||||
rot = Eigen::AngleAxisd(angle, axis) * rot;
|
||||
}
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
// Disable depth test so the arrow is always visible (not occluded by the tilted bed).
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
shader->start_using();
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
Transform3d model_matrix = rot;
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
||||
m_slicing_arrow.set_color({ 1.0f, 0.2f, 0.6f, 1.0f }); // pink
|
||||
m_slicing_arrow.render();
|
||||
|
||||
shader->stop_using();
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
}
|
||||
|
||||
void Bed3D::render_slicing_plane(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
if (!m_is_belt_printer || m_belt_angle <= 0.f)
|
||||
@@ -863,7 +922,15 @@ void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Tr
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_matrix);
|
||||
// Belt printer: rotate the default bed about X so the belt tilt is visible.
|
||||
Transform3d view_model_matrix = view_matrix;
|
||||
if (m_is_belt_printer && m_belt_angle > 0.f) {
|
||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle));
|
||||
Transform3d belt_rotation = Transform3d::Identity();
|
||||
belt_rotation.rotate(Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()));
|
||||
view_model_matrix = view_matrix * belt_rotation;
|
||||
}
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
@@ -111,6 +111,7 @@ private:
|
||||
GLModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
GLModel m_gravity_arrow;
|
||||
GLModel m_slicing_arrow; // Pink arrow showing the effective slicing direction
|
||||
GLModel m_slicing_plane; // Debug: shows the intended slicing plane direction
|
||||
Axes m_axes;
|
||||
|
||||
@@ -189,6 +190,7 @@ private:
|
||||
void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
|
||||
void render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
void render_gravity_arrow(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
void render_slicing_arrow(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
void render_slicing_plane(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
|
||||
// BBS: remove the bed picking logic
|
||||
|
||||
@@ -1271,6 +1271,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
|
||||
m_max_print_height = gcode_result.printable_height;
|
||||
m_z_offset = gcode_result.z_offset;
|
||||
m_belt_z_shift = gcode_result.belt_z_shift;
|
||||
|
||||
// load_toolpaths(gcode_result, build_volume, exclude_bounding_box);
|
||||
|
||||
@@ -2209,7 +2210,16 @@ void GCodeViewer::render_toolpaths()
|
||||
{
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
Matrix4f view = camera.get_view_matrix().matrix().cast<float>();
|
||||
// Belt view: view matrix transform placeholder (to be implemented in next cycle).
|
||||
// Belt "raw" view: apply slicing rotation to view matrix so toolpaths appear
|
||||
// in the slicing frame (rotated part with horizontal layers).
|
||||
if (m_belt_show_raw && m_belt_view_enabled && m_belt_angle_deg > 0.f) {
|
||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle_deg));
|
||||
// Apply R(-alpha, X) * T(0,0,-z_shift) to bring machine coords back to slicing frame.
|
||||
Transform3d slicing_trafo = Transform3d::Identity();
|
||||
slicing_trafo.translate(Vec3d(0., 0., -static_cast<double>(m_belt_z_shift)));
|
||||
slicing_trafo = Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()) * slicing_trafo;
|
||||
view = (camera.get_view_matrix() * slicing_trafo).matrix().cast<float>();
|
||||
}
|
||||
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>()));
|
||||
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
@@ -4406,6 +4416,14 @@ 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 raw slicing-frame G-code
|
||||
if (m_belt_view_enabled) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Dummy({ window_padding, 0 });
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Show raw G-code (slicing frame)", &m_belt_show_raw);
|
||||
}
|
||||
|
||||
legend_height = ImGui::GetCurrentWindow()->Size.y;
|
||||
imgui.end();
|
||||
ImGui::PopStyleColor(7);
|
||||
|
||||
@@ -239,6 +239,8 @@ mutable bool m_no_render_path { false };
|
||||
|
||||
bool m_belt_view_enabled = false;
|
||||
float m_belt_angle_deg = 0.f;
|
||||
float m_belt_z_shift = 0.f;
|
||||
bool m_belt_show_raw = false; // Toggle: show raw slicing-frame G-code (rotated part)
|
||||
|
||||
libvgcode::Viewer m_viewer;
|
||||
bool m_loaded_as_preview{ false };
|
||||
|
||||
Reference in New Issue
Block a user