mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
Add belt printer transform pipeline: slicing rotation, G-code coords, preview
- Implement core belt slicing pipeline: R(-alpha, X) mesh rotation in PrintObjectSlice with corrected object height calculation for proper layer count Add to_machine_coords() in GCodeWriter to convert slicing-frame coordinates back to machine-frame, propagated through GCode, GCodeProcessor, and GCodeViewer Add belt-mode UI: tilted bed visualization, slicing-direction arrow, and raw G-code toggle to switch between machine-frame and slicing-frame views This is a combination of 6 commits. checkpoint 1: initial MVP. Slicing functions, but rotates instead of skews are happening and a lot of other stuff too getting somewhere, getting to the point where I need to figure out how to verify this stuff this appears to be a dead end. getting somewhere I think maybe I'm pretty sure we've completely lost the plot at this point and need to restart this process... remove slice logic in preparation for new, more invasive plan
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"error_string": "Success.",
|
||||
"export_time": 0,
|
||||
"plate_index": 0,
|
||||
"prepare_time": 0,
|
||||
"return_code": 0
|
||||
}
|
||||
@@ -881,6 +881,10 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_
|
||||
std::vector<std::pair<ObjectID, unsigned int>> &objPrintVec,
|
||||
std::vector<unsigned int>& printExtruders)
|
||||
{
|
||||
// Belt printer: brim is not compatible with belt printing.
|
||||
if (print.config().belt_printer.value)
|
||||
return;
|
||||
|
||||
std::map<ObjectID, double> brim_width_map;
|
||||
std::map<ObjectID, ExPolygons> brimAreaMap;
|
||||
std::map<ObjectID, ExPolygons> supportBrimAreaMap;
|
||||
|
||||
@@ -176,6 +176,26 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
|
||||
BOOST_LOG_TRIVIAL(debug) << "BuildVolume printable_area clasified as: " << this->type_name();
|
||||
}
|
||||
|
||||
void BuildVolume::set_belt_printer(bool enabled, double angle_deg, bool infinite_y)
|
||||
{
|
||||
m_is_belt_printer = enabled;
|
||||
m_belt_angle = angle_deg;
|
||||
m_belt_infinite_y = infinite_y;
|
||||
|
||||
if (enabled) {
|
||||
if (infinite_y) {
|
||||
// Extend the Y bound to a very large value for infinite belt.
|
||||
m_bboxf.max.y() = 100000.;
|
||||
}
|
||||
// Adjust max print height to diagonal reach: printable_height / sin(belt_angle).
|
||||
if (angle_deg > 0. && angle_deg < 90.) {
|
||||
double sin_a = std::sin(angle_deg * M_PI / 180.0);
|
||||
if (sin_a > 0.)
|
||||
m_bboxf.max.z() = m_max_print_height / sin_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Tests intersections of projected triangles, not just their vertices against a bounding box.
|
||||
// This test also correctly evaluates collision of a non-convex object with the bounding box.
|
||||
@@ -384,6 +404,11 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
|
||||
build_volume.max.z() = std::numeric_limits<double>::max();
|
||||
if (ignore_bottom)
|
||||
build_volume.min.z() = -std::numeric_limits<double>::max();
|
||||
// Belt printer: extend Y bounds for infinite Y.
|
||||
if (m_is_belt_printer && m_belt_infinite_y) {
|
||||
build_volume.min.y() = -std::numeric_limits<double>::max();
|
||||
build_volume.max.y() = std::numeric_limits<double>::max();
|
||||
}
|
||||
BoundingBox3Base<Vec3f> build_volumef(build_volume.min.cast<float>(), build_volume.max.cast<float>());
|
||||
// The following test correctly interprets intersection of a non-convex object with a rectangular build volume.
|
||||
//return rectangle_test(its, trafo, to_2d(build_volume.min), to_2d(build_volume.max), build_volume.max.z());
|
||||
|
||||
@@ -57,6 +57,10 @@ public:
|
||||
// Initialize from PrintConfig::printable_area and PrintConfig::printable_height
|
||||
BuildVolume(const std::vector<Vec2d> &printable_area, const double printable_height, const std::vector<std::vector<Vec2d>> &extruder_areas, const std::vector<double>& extruder_printable_heights);
|
||||
|
||||
// Belt printer configuration.
|
||||
void set_belt_printer(bool enabled, double angle_deg, bool infinite_y);
|
||||
bool is_belt_printer() const { return m_is_belt_printer; }
|
||||
|
||||
// Source data, unscaled coordinates.
|
||||
const std::vector<Vec2d>& printable_area() const { return m_bed_shape; }
|
||||
double printable_height() const { return m_max_print_height; }
|
||||
@@ -139,6 +143,10 @@ private:
|
||||
// Source definition of the print volume height (PrintConfig::printable_height)
|
||||
double m_max_print_height { 0.f };
|
||||
std::vector<double> m_extruder_printable_height;
|
||||
// Belt printer state.
|
||||
bool m_is_belt_printer { false };
|
||||
double m_belt_angle { 0. };
|
||||
bool m_belt_infinite_y { false };
|
||||
|
||||
// Derived values.
|
||||
BuildVolume_Type m_type { BuildVolume_Type::Invalid };
|
||||
|
||||
@@ -2413,6 +2413,10 @@ 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)
|
||||
m_writer.set_belt_angle(print.config().belt_printer_angle.value);
|
||||
|
||||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
m_layer_count = 0;
|
||||
@@ -2502,6 +2506,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
file.write_format("; HEADER_BLOCK_START\n");
|
||||
// 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)
|
||||
file.write_format("; belt_printer_angle = %.1f\n", print.config().belt_printer_angle.value);
|
||||
if (is_bbl_printers)
|
||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||
//BBS: total layer number
|
||||
@@ -6758,7 +6765,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
// BBS: use G1 if not enable arc fitting or has no arc fitting result or in spiral_mode mode or we are doing sloped extrusion
|
||||
// Attention: G2 and G3 is not supported in spiral_mode mode
|
||||
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr) {
|
||||
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr || m_config.belt_printer) {
|
||||
double path_length = 0.;
|
||||
double total_length = sloped == nullptr ? 0. : path.polyline.length() * SCALING_FACTOR;
|
||||
for (const Line& line : path.polyline.lines()) {
|
||||
|
||||
@@ -2597,6 +2597,8 @@ 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
|
||||
@@ -3044,6 +3046,14 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
||||
return;
|
||||
}
|
||||
|
||||
// Belt printer angle detection from G-code header comment.
|
||||
if (boost::starts_with(comment, " belt_printer_angle = ")) {
|
||||
try {
|
||||
m_result.belt_printer_angle = std::stof(std::string(comment.substr(22)));
|
||||
} catch (...) {}
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe start tag
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||
m_wiping = true;
|
||||
|
||||
@@ -227,6 +227,8 @@ class Print;
|
||||
bool support_traditional_timelapse{true};
|
||||
float printable_height;
|
||||
float z_offset;
|
||||
// Belt printer: angle for coordinate transformation in preview.
|
||||
float belt_printer_angle{ 0.f };
|
||||
SettingsIds settings_ids;
|
||||
size_t filaments_count;
|
||||
bool backtrace_enabled;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
@@ -19,6 +20,19 @@ namespace Slic3r {
|
||||
|
||||
bool GCodeWriter::full_gcode_comment = true;
|
||||
|
||||
void GCodeWriter::set_belt_angle(double angle_deg)
|
||||
{
|
||||
m_belt_angle_rad = Geometry::deg2rad(angle_deg);
|
||||
m_belt_cos = std::cos(m_belt_angle_rad);
|
||||
m_belt_sin = std::sin(m_belt_angle_rad);
|
||||
}
|
||||
|
||||
Vec3d GCodeWriter::to_machine_coords(const Vec3d &pos) const
|
||||
{
|
||||
// Belt printer: coordinate transform placeholder (to be implemented in next cycle).
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
||||
{
|
||||
return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
|
||||
@@ -561,7 +575,13 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &com
|
||||
Vec2d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset };
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point_on_plate);
|
||||
if (is_belt_printer()) {
|
||||
// Belt printer: transform to machine coordinates (XY travel also needs Z due to YZ rotation)
|
||||
Vec3d machine = to_machine_coords(Vec3d(point_on_plate.x(), point_on_plate.y(), m_pos.z()));
|
||||
w.emit_xyz(machine);
|
||||
} else {
|
||||
w.emit_xy(point_on_plate);
|
||||
}
|
||||
auto speed = m_is_first_layer
|
||||
? this->config.get_abs_value("initial_layer_travel_speed") : this->config.travel_speed.value;
|
||||
w.emit_f(speed * 60.0);
|
||||
@@ -575,6 +595,11 @@ it will not perform subsequent lifts, even if Z was raised manually
|
||||
(i.e. with travel_to_z()) and thus _lifted was reduced. */
|
||||
std::string GCodeWriter::lazy_lift(LiftType lift_type, bool spiral_vase)
|
||||
{
|
||||
// Belt printer: force NormalLift since SpiralLift and SlopeLift compute slope angles
|
||||
// that don't account for the YZ coordinate rotation.
|
||||
if (is_belt_printer())
|
||||
lift_type = LiftType::NormalLift;
|
||||
|
||||
// check whether the above/below conditions are met
|
||||
double target_lift = 0;
|
||||
{
|
||||
@@ -603,6 +628,8 @@ std::string GCodeWriter::lazy_lift(LiftType lift_type, bool spiral_vase)
|
||||
// BBS: immediately execute an undelayed lift move with a spiral lift pattern
|
||||
// designed specifically for subsequent gcode injection (e.g. timelapse)
|
||||
std::string GCodeWriter::eager_lift(const LiftType type) {
|
||||
// Belt printer: force NormalLift (SpiralLift/SlopeLift don't account for YZ rotation).
|
||||
const LiftType effective_type = is_belt_printer() ? LiftType::NormalLift : type;
|
||||
std::string lift_move;
|
||||
double target_lift = 0;
|
||||
{
|
||||
@@ -617,7 +644,7 @@ std::string GCodeWriter::eager_lift(const LiftType type) {
|
||||
|
||||
// BBS: spiral lift only safe with known position
|
||||
// TODO: check the arc will move within bed area
|
||||
if (type == LiftType::SpiralLift && this->is_current_position_clear()) {
|
||||
if (effective_type == LiftType::SpiralLift && this->is_current_position_clear()) {
|
||||
double radius = target_lift / (2 * PI * atan(filament()->travel_slope()));
|
||||
// static spiral alignment when no move in x,y plane.
|
||||
// spiral centra is a radius distance to the right (y=0)
|
||||
@@ -689,6 +716,8 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
// / to make the z list early to avoid to hit some warping place when travel is long.
|
||||
Vec2d temp = delta_no_z.normalized() * delta(2) / tan(this->filament()->travel_slope());
|
||||
Vec3d slope_top_point = Vec3d(temp(0), temp(1), delta(2)) + source;
|
||||
if (is_belt_printer())
|
||||
slope_top_point = to_machine_coords(slope_top_point);
|
||||
GCodeG1Formatter w0;
|
||||
w0.emit_xyz(slope_top_point);
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
@@ -703,18 +732,27 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
|
||||
std::string xy_z_move;
|
||||
{
|
||||
Vec3d emit_target = is_belt_printer() ? to_machine_coords(target) : target;
|
||||
GCodeG1Formatter w0;
|
||||
if (this->is_current_position_clear()) {
|
||||
w0.emit_xyz(target);
|
||||
w0.emit_xyz(emit_target);
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
xy_z_move = w0.string();
|
||||
}
|
||||
else {
|
||||
w0.emit_xy(Vec2d(target.x(), target.y()));
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
xy_z_move = w0.string() + _travel_to_z(target.z(), comment);
|
||||
if (is_belt_printer()) {
|
||||
// Belt mode: can't split XY and Z moves independently, emit full XYZ
|
||||
w0.emit_xyz(emit_target);
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
xy_z_move = w0.string();
|
||||
} else {
|
||||
w0.emit_xy(Vec2d(target.x(), target.y()));
|
||||
w0.emit_f(travel_speed * 60.0);
|
||||
w0.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
xy_z_move = w0.string() + _travel_to_z(target.z(), comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pos = dest_point;
|
||||
@@ -740,15 +778,25 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
|
||||
//BBS: take plate offset into consider
|
||||
Vec3d point_on_plate = { dest_point(0) - m_x_offset, dest_point(1) - m_y_offset, dest_point(2) };
|
||||
if (is_belt_printer())
|
||||
point_on_plate = to_machine_coords(point_on_plate);
|
||||
std::string out_string;
|
||||
GCodeG1Formatter w;
|
||||
if (!this->is_current_position_clear())
|
||||
{
|
||||
//force to move xy first then z after filament change
|
||||
w.emit_xy(Vec2d(point_on_plate.x(), point_on_plate.y()));
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
out_string = w.string() + _travel_to_z(point_on_plate.z(), comment);
|
||||
if (is_belt_printer()) {
|
||||
// Belt mode: emit full XYZ since Y and Z are coupled
|
||||
w.emit_xyz(point_on_plate);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
out_string = w.string();
|
||||
} else {
|
||||
//force to move xy first then z after filament change
|
||||
w.emit_xy(Vec2d(point_on_plate.x(), point_on_plate.y()));
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
out_string = w.string() + _travel_to_z(point_on_plate.z(), comment);
|
||||
}
|
||||
} else {
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xyz(point_on_plate);
|
||||
@@ -792,7 +840,13 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment)
|
||||
}
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_z(z);
|
||||
if (is_belt_printer()) {
|
||||
// Belt printer: a Z-only move in slicing frame needs to emit both Y and Z in machine coords.
|
||||
Vec3d machine = to_machine_coords(Vec3d(m_pos.x() - m_x_offset, m_pos.y() - m_y_offset, z));
|
||||
w.emit_xyz(machine);
|
||||
} else {
|
||||
w.emit_z(z);
|
||||
}
|
||||
w.emit_f(speed * 60.0);
|
||||
//BBS
|
||||
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||
@@ -897,7 +951,12 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
||||
Vec2d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset };
|
||||
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point_on_plate);
|
||||
if (is_belt_printer()) {
|
||||
Vec3d machine = to_machine_coords(Vec3d(point_on_plate.x(), point_on_plate.y(), m_pos.z()));
|
||||
w.emit_xyz(machine);
|
||||
} else {
|
||||
w.emit_xy(point_on_plate);
|
||||
}
|
||||
if (!force_no_extrusion)
|
||||
w.emit_e(filament()->E());
|
||||
//BBS
|
||||
@@ -938,6 +997,8 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
|
||||
Vec3d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset, point(2) };
|
||||
|
||||
GCodeG1Formatter w;
|
||||
if (is_belt_printer())
|
||||
point_on_plate = to_machine_coords(point_on_plate);
|
||||
w.emit_xyz(point_on_plate);
|
||||
if (!force_no_extrusion)
|
||||
w.emit_e(filament()->E());
|
||||
|
||||
@@ -125,6 +125,12 @@ public:
|
||||
void set_is_first_layer(bool bval) { m_is_first_layer = bval; }
|
||||
GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; }
|
||||
|
||||
// Belt printer: set the belt angle and precompute sin/cos for coordinate transformation.
|
||||
void set_belt_angle(double angle_deg);
|
||||
bool is_belt_printer() const { return m_belt_angle_rad != 0.; }
|
||||
// Transform a point from the slicing frame to machine/world coordinates (inverse shear).
|
||||
Vec3d to_machine_coords(const Vec3d &pos) const;
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
private:
|
||||
@@ -177,6 +183,11 @@ public:
|
||||
|
||||
//SoftFever
|
||||
bool m_is_bbl_printers = false;
|
||||
|
||||
// Belt printer coordinate transformation (YZ shear)
|
||||
double m_belt_angle_rad = 0.;
|
||||
double m_belt_cos = 1.0;
|
||||
double m_belt_sin = 0.0;
|
||||
double m_current_speed;
|
||||
bool m_is_first_layer = true;
|
||||
|
||||
|
||||
@@ -1010,7 +1010,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
|
||||
|
||||
static std::vector<std::string> s_Preset_printer_options {
|
||||
"printer_technology",
|
||||
"printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "build_plate_tilt_x", "build_plate_tilt_y", "gcode_flavor",
|
||||
"printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "build_plate_tilt_x", "build_plate_tilt_y", "belt_printer", "belt_printer_angle", "belt_printer_infinite_y", "gcode_flavor",
|
||||
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
|
||||
"single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
|
||||
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
|
||||
|
||||
@@ -565,6 +565,9 @@ std::vector<ObjectID> Print::print_object_ids() const
|
||||
|
||||
bool Print::has_infinite_skirt() const
|
||||
{
|
||||
// Belt printer: no skirt support.
|
||||
if (m_config.belt_printer.value)
|
||||
return false;
|
||||
// Orca: unclear why (m_config.ooze_prevention && this->extruders().size() > 1) logic is here, removed.
|
||||
// return (m_config.draft_shield == dsEnabled && m_config.skirt_loops > 0) || (m_config.ooze_prevention && this->extruders().size() > 1);
|
||||
|
||||
@@ -573,6 +576,9 @@ bool Print::has_infinite_skirt() const
|
||||
|
||||
bool Print::has_skirt() const
|
||||
{
|
||||
// Belt printer: no skirt support.
|
||||
if (m_config.belt_printer.value)
|
||||
return false;
|
||||
return (m_config.skirt_height > 0);
|
||||
}
|
||||
|
||||
@@ -1194,6 +1200,16 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
if (extruders.empty())
|
||||
return { L("No extrusions under current settings.") };
|
||||
|
||||
// Belt printer validation: incompatible features.
|
||||
if (m_config.belt_printer.value) {
|
||||
for (const PrintObject *object : m_objects) {
|
||||
if (object->config().raft_layers > 0)
|
||||
return { L("Raft is not compatible with belt printer mode.") };
|
||||
}
|
||||
if (m_config.draft_shield != dsDisabled)
|
||||
return { L("Draft shield is not compatible with belt printer mode.") };
|
||||
}
|
||||
|
||||
if (nozzles < 2 && extruders.size() > 1) {
|
||||
auto ret = check_multi_filament_valid(*this);
|
||||
if (!ret.string.empty())
|
||||
@@ -2501,6 +2517,10 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
||||
|
||||
void Print::_make_skirt()
|
||||
{
|
||||
// Belt printer: skirt is not compatible.
|
||||
if (m_config.belt_printer.value)
|
||||
return;
|
||||
|
||||
// First off we need to decide how tall the skirt must be.
|
||||
// The skirt_height option from config is expressed in layers, but our
|
||||
// object might have different layer heights, so we need to find the print_z
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "PrintConfigConstants.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "MaterialType.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "format.hpp"
|
||||
@@ -5927,10 +5928,11 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("Tilt angle of the build plate along the X axis. "
|
||||
"A positive value tilts the plate so the +X side is higher, shifting gravity toward -X and increasing overhangs on the +X side. "
|
||||
"A negative value tilts the -X side higher. Set to 0 for no X-axis tilt.");
|
||||
"A negative value tilts the -X side higher. Set to 0 for no X-axis tilt. "
|
||||
"In belt printer mode, this is automatically synced to the belt angle.");
|
||||
def->sidetext = u8"\u00B0";
|
||||
def->min = -45;
|
||||
def->max = 45;
|
||||
def->min = -90;
|
||||
def->max = 90;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
@@ -5941,11 +5943,41 @@ void PrintConfigDef::init_fff_params()
|
||||
"A positive value tilts the plate so the +Y side is higher, shifting gravity toward -Y and increasing overhangs on the +Y side. "
|
||||
"A negative value tilts the -Y side higher. Set to 0 for no Y-axis tilt.");
|
||||
def->sidetext = u8"\u00B0";
|
||||
def->min = -45;
|
||||
def->max = 45;
|
||||
def->min = -90;
|
||||
def->max = 90;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
def = this->add("belt_printer", coBool);
|
||||
def->label = L("Belt printer");
|
||||
def->category = L("Printable space");
|
||||
def->tooltip = L("Enable belt printer mode. Belt printers use a conveyor belt as the build surface, "
|
||||
"tilted at an angle (typically 45 degrees). The slicer will rotate the slicing plane "
|
||||
"and transform G-code coordinates for the tilted build surface.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("belt_printer_angle", coFloat);
|
||||
def->label = L("Belt angle");
|
||||
def->category = L("Printable space");
|
||||
def->tooltip = L("The tilt angle of the belt surface in degrees. "
|
||||
"Most belt printers use a 45-degree angle. "
|
||||
"This controls the rotation applied to the slicing plane and G-code coordinates.");
|
||||
def->sidetext = u8"\u00B0";
|
||||
def->min = 0;
|
||||
def->max = 90;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(45.));
|
||||
|
||||
def = this->add("belt_printer_infinite_y", coBool);
|
||||
def->label = L("Infinite Y axis");
|
||||
def->category = L("Printable space");
|
||||
def->tooltip = L("Enable infinite Y axis for belt printers. "
|
||||
"When enabled, the Y axis build volume limit is effectively removed, "
|
||||
"allowing objects of any length to be printed along the belt direction.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("tree_support_branch_angle", coFloat);
|
||||
def->label = L("Tree support branch angle");
|
||||
def->category = L("Support");
|
||||
@@ -10827,10 +10859,16 @@ Polygons get_bed_excluded_area(const PrintConfig& cfg)
|
||||
{
|
||||
const Pointfs exclude_area_points = cfg.bed_exclude_area.values;
|
||||
|
||||
// Belt printer: project exclusion zone points from belt surface to machine-frame XY.
|
||||
// On the belt surface, Z=0, so machine_Y = belt_Y * cos(angle).
|
||||
const bool is_belt = cfg.belt_printer.value;
|
||||
const double belt_cos = is_belt ? std::cos(Geometry::deg2rad(cfg.belt_printer_angle.value)) : 1.0;
|
||||
|
||||
Polygon exclude_poly;
|
||||
for (int i = 0; i < exclude_area_points.size(); i++) {
|
||||
auto pt = exclude_area_points[i];
|
||||
exclude_poly.points.emplace_back(scale_(pt.x()), scale_(pt.y()));
|
||||
double y = is_belt ? pt.y() * belt_cos : pt.y();
|
||||
exclude_poly.points.emplace_back(scale_(pt.x()), scale_(y));
|
||||
}
|
||||
|
||||
exclude_poly.make_counter_clockwise();
|
||||
|
||||
@@ -1412,6 +1412,10 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
// Build plate tilt for off-axis gravity support generation (printer-level setting).
|
||||
((ConfigOptionFloat, build_plate_tilt_x))
|
||||
((ConfigOptionFloat, build_plate_tilt_y))
|
||||
// Belt printer settings (printer-level).
|
||||
((ConfigOptionBool, belt_printer))
|
||||
((ConfigOptionFloat, belt_printer_angle))
|
||||
((ConfigOptionBool, belt_printer_infinite_y))
|
||||
//BBS
|
||||
((ConfigOptionInts, additional_cooling_fan_speed))
|
||||
((ConfigOptionBool, reduce_crossing_wall))
|
||||
|
||||
@@ -3391,7 +3391,9 @@ void PrintObject::update_slicing_parameters()
|
||||
{
|
||||
// Orca: updated function call for XYZ shrinkage compensation
|
||||
if (!m_slicing_params.valid) {
|
||||
m_slicing_params = SlicingParameters::create_from_config(this->print()->config(), m_config, this->model_object()->max_z(),
|
||||
coordf_t object_height = this->model_object()->max_z();
|
||||
// Belt printer: height adjustment placeholder (to be implemented in next cycle).
|
||||
m_slicing_params = SlicingParameters::create_from_config(this->print()->config(), m_config, object_height,
|
||||
this->object_extruders(), this->print()->shrinkage_compensation());
|
||||
}
|
||||
}
|
||||
@@ -3432,6 +3434,7 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
|
||||
|
||||
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).
|
||||
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders, object_shrinkage_compensation);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Layer.hpp"
|
||||
#include "MultiMaterialSegmentation.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "Geometry.hpp"
|
||||
//BBS
|
||||
#include "ShortestPath.hpp"
|
||||
#include "libslic3r/Feature/Interlocking/InterlockingGenerator.hpp"
|
||||
@@ -139,6 +140,7 @@ 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).
|
||||
//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,14 +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;
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case Type::System: { render_system(canvas, view_matrix, projection_matrix, bottom); break; }
|
||||
case Type::System: { render_system(canvas, belt_view_matrix, projection_matrix, bottom); break; }
|
||||
default:
|
||||
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom); break; }
|
||||
case Type::Custom: { render_custom(canvas, belt_view_matrix, projection_matrix, bottom); break; }
|
||||
}
|
||||
|
||||
render_gravity_arrow(view_matrix, projection_matrix);
|
||||
render_slicing_plane(view_matrix, projection_matrix);
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
}
|
||||
@@ -738,6 +742,10 @@ void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
double tilt_x_deg = cfg.opt_float("build_plate_tilt_x");
|
||||
double tilt_y_deg = cfg.opt_float("build_plate_tilt_y");
|
||||
// Belt printer: auto-derive gravity direction from belt angle if belt mode is active.
|
||||
if (m_is_belt_printer && m_belt_angle > 0.f) {
|
||||
tilt_x_deg = m_belt_angle;
|
||||
}
|
||||
if (tilt_x_deg == 0. && tilt_y_deg == 0.) {
|
||||
m_gravity_arrow.reset();
|
||||
return;
|
||||
@@ -790,6 +798,61 @@ void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
void Bed3D::render_slicing_plane(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
if (!m_is_belt_printer || m_belt_angle <= 0.f)
|
||||
return;
|
||||
|
||||
// Build a quad in the XZ plane (world frame) representing the belt slicing plane.
|
||||
// The plane is tilted at belt_angle from horizontal, with normal (0, -sin(a), cos(a)).
|
||||
// We render it as a semi-transparent quad centered on the build plate.
|
||||
if (!m_slicing_plane.is_initialized()) {
|
||||
const float half_size = 120.f; // mm, large enough to be visible
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
|
||||
init_data.reserve_vertices(4);
|
||||
init_data.reserve_indices(2); // 2 triangles
|
||||
|
||||
// Quad corners in local frame (XY plane, will be rotated to match slicing plane)
|
||||
Vec3f n = Vec3f::UnitZ();
|
||||
init_data.add_vertex(Vec3f(-half_size, -half_size, 0.f), n);
|
||||
init_data.add_vertex(Vec3f( half_size, -half_size, 0.f), n);
|
||||
init_data.add_vertex(Vec3f( half_size, half_size, 0.f), n);
|
||||
init_data.add_vertex(Vec3f(-half_size, half_size, 0.f), n);
|
||||
init_data.add_triangle(0, 1, 2);
|
||||
init_data.add_triangle(0, 2, 3);
|
||||
|
||||
m_slicing_plane.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
shader->start_using();
|
||||
|
||||
// Show a tilted plane representing the slicing direction.
|
||||
// The slicing plane is rotated by belt_angle about X from horizontal.
|
||||
// Raise it slightly so it's visible above the bed surface.
|
||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle));
|
||||
Transform3d model_matrix = Transform3d::Identity();
|
||||
model_matrix.translate(Vec3d(0., 0., 30.));
|
||||
model_matrix.rotate(Eigen::AngleAxisd(angle_rad, Vec3d::UnitX()));
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
|
||||
m_slicing_plane.set_color({ 0.2f, 0.6f, 1.0f, 0.3f }); // semi-transparent blue
|
||||
m_slicing_plane.render();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
// m_texture.reset();
|
||||
|
||||
@@ -111,6 +111,7 @@ private:
|
||||
GLModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
GLModel m_gravity_arrow;
|
||||
GLModel m_slicing_plane; // Debug: shows the intended slicing plane direction
|
||||
Axes m_axes;
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
@@ -120,6 +121,9 @@ private:
|
||||
std::vector<std::vector<Vec2d>> m_extruder_shapes;
|
||||
std::vector<double> m_extruder_heights;
|
||||
bool m_is_dark = false;
|
||||
// Belt printer state for rendering.
|
||||
bool m_is_belt_printer = false;
|
||||
float m_belt_angle = 0.f;
|
||||
|
||||
public:
|
||||
Bed3D() = default;
|
||||
@@ -139,6 +143,12 @@ public:
|
||||
|
||||
// Build volume geometry for various collision detection tasks.
|
||||
const BuildVolume& build_volume() const { return m_build_volume; }
|
||||
BuildVolume& build_volume() { return m_build_volume; }
|
||||
|
||||
// Belt printer bed settings.
|
||||
void set_belt_printer(bool enabled, float angle_deg) { m_is_belt_printer = enabled; m_belt_angle = angle_deg; }
|
||||
bool is_belt_printer() const { return m_is_belt_printer; }
|
||||
float belt_angle() const { return m_belt_angle; }
|
||||
|
||||
// Was the model provided, or was it generated procedurally?
|
||||
Type get_type() const { return m_type; }
|
||||
@@ -179,6 +189,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_plane(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
|
||||
// BBS: remove the bed picking logic
|
||||
// void register_raycasters_for_picking(const GLModel::Geometry& geometry, const Transform3d& trafo);
|
||||
|
||||
@@ -573,9 +573,17 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
|
||||
auto gcflavor = preset_bundle->printers.get_edited_preset().config.option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
|
||||
|
||||
// Belt printer: detect early since it affects multiple toggle decisions below.
|
||||
bool is_belt_printer = false;
|
||||
{
|
||||
const auto *belt_opt = preset_bundle->printers.get_edited_preset().config.option<ConfigOptionBool>("belt_printer");
|
||||
if (belt_opt)
|
||||
is_belt_printer = belt_opt->value;
|
||||
}
|
||||
|
||||
bool have_volumetric_extrusion_rate_slope = config->option<ConfigOptionFloat>("max_volumetric_extrusion_rate_slope")->value > 0;
|
||||
float have_volumetric_extrusion_rate_slope_segment_length = config->option<ConfigOptionFloat>("max_volumetric_extrusion_rate_slope_segment_length")->value;
|
||||
toggle_field("enable_arc_fitting", !have_volumetric_extrusion_rate_slope);
|
||||
toggle_field("enable_arc_fitting", !have_volumetric_extrusion_rate_slope && !is_belt_printer);
|
||||
toggle_line("max_volumetric_extrusion_rate_slope_segment_length", have_volumetric_extrusion_rate_slope);
|
||||
toggle_line("extrusion_rate_smoothing_external_perimeter_only", have_volumetric_extrusion_rate_slope);
|
||||
if(have_volumetric_extrusion_rate_slope) config->set_key_value("enable_arc_fitting", new ConfigOptionBool(false));
|
||||
@@ -693,13 +701,20 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
}
|
||||
}
|
||||
|
||||
bool have_skirt = config->opt_int("skirt_loops") > 0;
|
||||
// Belt printer: disable skirt, brim, raft, and draft shield controls.
|
||||
bool have_skirt = config->opt_int("skirt_loops") > 0 && !is_belt_printer;
|
||||
toggle_field("skirt_height", have_skirt && config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
|
||||
toggle_line("single_loop_draft_shield", have_skirt); // ORCA: Display one wall if skirt enabled
|
||||
for (auto el : {"skirt_type", "min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_speed", "draft_shield"})
|
||||
toggle_field(el, have_skirt);
|
||||
if (is_belt_printer) {
|
||||
toggle_field("skirt_loops", false);
|
||||
toggle_field("skirt_height", false);
|
||||
}
|
||||
|
||||
bool have_brim = (config->opt_enum<BrimType>("brim_type") != btNoBrim);
|
||||
bool have_brim = (config->opt_enum<BrimType>("brim_type") != btNoBrim) && !is_belt_printer;
|
||||
if (is_belt_printer)
|
||||
toggle_field("brim_type", false);
|
||||
toggle_field("brim_object_gap", have_brim);
|
||||
toggle_field("brim_use_efc_outline", have_brim);
|
||||
toggle_field("combine_brims", have_brim);
|
||||
@@ -721,7 +736,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
// Hide Elephant foot compensation layers if elefant_foot_compensation is not enabled
|
||||
toggle_line("elefant_foot_compensation_layers", config->opt_float("elefant_foot_compensation") > 0);
|
||||
|
||||
bool have_raft = config->opt_int("raft_layers") > 0;
|
||||
bool have_raft = config->opt_int("raft_layers") > 0 && !is_belt_printer;
|
||||
if (is_belt_printer)
|
||||
toggle_field("raft_layers", false);
|
||||
bool have_support_material = config->opt_bool("enable_support") || have_raft;
|
||||
|
||||
SupportType support_type = config->opt_enum<SupportType>("support_type");
|
||||
|
||||
@@ -2208,7 +2208,9 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p
|
||||
void GCodeViewer::render_toolpaths()
|
||||
{
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const libvgcode::Mat4x4 converted_view_matrix = libvgcode::convert(static_cast<Matrix4f>(camera.get_view_matrix().matrix().cast<float>()));
|
||||
Matrix4f view = camera.get_view_matrix().matrix().cast<float>();
|
||||
// Belt view: view matrix transform placeholder (to be implemented in next cycle).
|
||||
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
|
||||
m_viewer.set_cog_marker_scale_factor(m_cog_marker_fixed_screen_size ? 10.0f * m_cog_marker_size * camera.get_inv_zoom() : m_cog_marker_size);
|
||||
|
||||
@@ -237,6 +237,9 @@ private:
|
||||
mutable bool m_no_render_path { false };
|
||||
bool m_is_dark = false;
|
||||
|
||||
bool m_belt_view_enabled = false;
|
||||
float m_belt_angle_deg = 0.f;
|
||||
|
||||
libvgcode::Viewer m_viewer;
|
||||
bool m_loaded_as_preview{ false };
|
||||
|
||||
@@ -336,6 +339,9 @@ public:
|
||||
|
||||
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; }
|
||||
bool is_belt_view() const { return m_belt_view_enabled && m_belt_angle_deg > 0.f; }
|
||||
|
||||
size_t get_extruders_count() { return m_extruders_count; }
|
||||
void push_combo_style();
|
||||
void pop_combo_style();
|
||||
|
||||
@@ -10980,6 +10980,24 @@ void Plater::priv::set_bed_shape(const Pointfs &shape,
|
||||
Vec2d shape_position = partplate_list.get_current_shape_position();
|
||||
bool new_shape = bed.set_shape(shape, printable_height, extruder_areas, extruder_heights, custom_model, force_as_custom, shape_position);
|
||||
|
||||
// Belt printer: configure build volume and bed rendering for belt mode.
|
||||
{
|
||||
const auto *belt_opt = config->option<ConfigOptionBool>("belt_printer");
|
||||
bool is_belt = belt_opt && belt_opt->value;
|
||||
if (is_belt) {
|
||||
double belt_angle = config->opt_float("belt_printer_angle");
|
||||
bool infinite_y = config->opt_bool("belt_printer_infinite_y");
|
||||
bed.build_volume().set_belt_printer(true, belt_angle, infinite_y);
|
||||
bed.set_belt_printer(true, static_cast<float>(belt_angle));
|
||||
if (preview)
|
||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(true, static_cast<float>(belt_angle));
|
||||
} else {
|
||||
bed.set_belt_printer(false, 0.f);
|
||||
if (preview)
|
||||
preview->get_canvas3d()->get_gcode_viewer().set_belt_printer(false, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
float prev_height_lid, prev_height_rod;
|
||||
partplate_list.get_height_limits(prev_height_lid, prev_height_rod);
|
||||
double height_to_lid = config->opt_float("extruder_clearance_height_to_lid");
|
||||
|
||||
@@ -4367,6 +4367,9 @@ void TabPrinter::build_fff()
|
||||
optgroup->append_single_option_line("printable_height", "printer_basic_information_printable_space#printable-height");
|
||||
optgroup->append_single_option_line("build_plate_tilt_x");
|
||||
optgroup->append_single_option_line("build_plate_tilt_y");
|
||||
optgroup->append_single_option_line("belt_printer");
|
||||
optgroup->append_single_option_line("belt_printer_angle");
|
||||
optgroup->append_single_option_line("belt_printer_infinite_y");
|
||||
optgroup->append_single_option_line("support_multi_bed_types","printer_basic_information_printable_space#support-multi-bed-types");
|
||||
optgroup->append_single_option_line("best_object_pos", "printer_basic_information_printable_space#best-object-position");
|
||||
// todo: for multi_extruder test
|
||||
@@ -5225,6 +5228,11 @@ void TabPrinter::toggle_options()
|
||||
|
||||
auto gcf = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
|
||||
toggle_line("enable_power_loss_recovery", is_BBL_printer || gcf == gcfMarlinFirmware);
|
||||
|
||||
// Belt printer: show belt-specific settings only when belt_printer is enabled.
|
||||
bool is_belt = m_config->opt_bool("belt_printer");
|
||||
toggle_line("belt_printer_angle", is_belt);
|
||||
toggle_line("belt_printer_infinite_y", is_belt);
|
||||
}
|
||||
|
||||
|
||||
@@ -5396,6 +5404,23 @@ void TabPrinter::update_fff()
|
||||
m_use_silent_mode = m_config->opt_bool("silent_mode");
|
||||
}
|
||||
|
||||
// Belt printer: auto-sync build_plate_tilt_x to belt_printer_angle when belt mode is active.
|
||||
// When belt mode is off, reset build_plate_tilt_x to 0 if it was set by belt mode.
|
||||
if (m_config->opt_bool("belt_printer")) {
|
||||
double belt_angle = m_config->opt_float("belt_printer_angle");
|
||||
if (m_config->opt_float("build_plate_tilt_x") != belt_angle) {
|
||||
m_config->set_key_value("build_plate_tilt_x", new ConfigOptionFloat(belt_angle));
|
||||
}
|
||||
} else {
|
||||
// Only reset if build_plate_tilt_x matches a typical belt angle (was set by auto-sync).
|
||||
// Avoid clobbering a manually-set tilt value for non-belt tilted printers.
|
||||
double current_tilt = m_config->opt_float("build_plate_tilt_x");
|
||||
double belt_angle = m_config->opt_float("belt_printer_angle");
|
||||
if (current_tilt != 0. && std::abs(current_tilt - belt_angle) < 0.01) {
|
||||
m_config->set_key_value("build_plate_tilt_x", new ConfigOptionFloat(0.));
|
||||
}
|
||||
}
|
||||
|
||||
toggle_options();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user