Part 2.5: Add global shear transform, support clipping, and belt UI improvements

- Implement per-object global shear transform in PrintObject with
  layer Z-offset calculation, config invalidation, and fix for
  shared-object layer optimization breaking copied objects
- Clip support layers to the transformed belt floor plane and begin
  work on tree support adaptation for sheared coordinate space
- Improve belt UI: gray out inactive sub-options, add B keyboard
  shortcut for G-code viewer design-view toggle, fix mesh clipping
  through build plate after shear/scale transform

y' = y + z·cot(α),
  while x' = x and z' = z

getting closer to customizable variant

getting closer

X/Y/Z shear initial

clean up UI

add 1/sin(a) transform, idea taken from blackbelt cura plugin

Things work now (turns out I've been using the wrong set of  transforms)
This commit is contained in:
harrierpigeon
2026-04-09 23:07:07 -05:00
parent 501aff7e53
commit 98f4d34dcb
13 changed files with 452 additions and 91 deletions
+9 -22
View File
@@ -2411,31 +2411,19 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_is_role_based_fan_on.fill(false);
m_fan_mover.release();
m_writer.set_is_bbl_machine(is_bbl_printers);
// Belt printer: initialize coordinate transformation on the writer.
// Belt printer: initialize coordinate transformation and axis remap on the writer.
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
m_writer.set_axis_remap(
int(print.config().belt_gcode_remap_x.value),
int(print.config().belt_gcode_remap_y.value),
int(print.config().belt_gcode_remap_z.value));
// Build volume extents for Rev remap mode.
BoundingBoxf bbox_bed(print.config().printable_area.values);
m_writer.set_build_volume_max(Vec3d(bbox_bed.max.x(), bbox_bed.max.y(), print.config().printable_height.value));
}
// How many times will be change_layer() called?
@@ -2530,7 +2518,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// Belt printer: embed angle in header for G-code processor detection.
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());