mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 10:51:22 +00:00
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:
+8
-21
@@ -2414,28 +2414,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
|
|
||||||
m_writer.set_is_bbl_machine(is_bbl_printers);
|
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) {
|
if (print.config().belt_printer.value) {
|
||||||
m_writer.set_belt_angle(print.config().belt_printer_angle.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).
|
m_writer.set_axis_remap(
|
||||||
// This is needed by to_machine_coords() to undo the slicing transform.
|
int(print.config().belt_gcode_remap_x.value),
|
||||||
// For multiple objects, use the minimum min_z_rotated across all objects.
|
int(print.config().belt_gcode_remap_y.value),
|
||||||
double angle_rad = Geometry::deg2rad(print.config().belt_printer_angle.value);
|
int(print.config().belt_gcode_remap_z.value));
|
||||||
Transform3d belt_rotation = Transform3d::Identity();
|
// Build volume extents for Rev remap mode.
|
||||||
belt_rotation.rotate(Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()));
|
BoundingBoxf bbox_bed(print.config().printable_area.values);
|
||||||
double global_min_z = std::numeric_limits<double>::max();
|
m_writer.set_build_volume_max(Vec3d(bbox_bed.max.x(), bbox_bed.max.y(), print.config().printable_height.value));
|
||||||
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?
|
// 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.
|
// 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_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)
|
if (is_bbl_printers)
|
||||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||||
|
|||||||
@@ -3051,14 +3051,6 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
|||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
return;
|
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
|
// wipe start tag
|
||||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||||
m_wiping = true;
|
m_wiping = true;
|
||||||
|
|||||||
@@ -227,9 +227,8 @@ class Print;
|
|||||||
bool support_traditional_timelapse{true};
|
bool support_traditional_timelapse{true};
|
||||||
float printable_height;
|
float printable_height;
|
||||||
float z_offset;
|
float z_offset;
|
||||||
// Belt printer: angle and Z-shift for coordinate transformation in preview.
|
// Belt printer: angle for coordinate transformation in preview.
|
||||||
float belt_printer_angle{ 0.f };
|
float belt_printer_angle{ 0.f };
|
||||||
float belt_z_shift{ 0.f };
|
|
||||||
SettingsIds settings_ids;
|
SettingsIds settings_ids;
|
||||||
size_t filaments_count;
|
size_t filaments_count;
|
||||||
bool backtrace_enabled;
|
bool backtrace_enabled;
|
||||||
|
|||||||
@@ -23,26 +23,32 @@ bool GCodeWriter::full_gcode_comment = true;
|
|||||||
void GCodeWriter::set_belt_angle(double angle_deg)
|
void GCodeWriter::set_belt_angle(double angle_deg)
|
||||||
{
|
{
|
||||||
m_belt_angle_rad = Geometry::deg2rad(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);
|
|
||||||
|
void GCodeWriter::set_axis_remap(int rx, int ry, int rz)
|
||||||
|
{
|
||||||
|
m_remap_x = rx;
|
||||||
|
m_remap_y = ry;
|
||||||
|
m_remap_z = rz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeWriter::set_build_volume_max(const Vec3d &max)
|
||||||
|
{
|
||||||
|
m_build_vol_max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3d GCodeWriter::to_machine_coords(const Vec3d &pos) const
|
Vec3d GCodeWriter::to_machine_coords(const Vec3d &pos) const
|
||||||
{
|
{
|
||||||
if (!is_belt_printer())
|
if (!is_belt_printer())
|
||||||
return pos;
|
return pos;
|
||||||
|
// BeltRemapAxis: 0-2 = +X/+Y/+Z, 3-5 = -X/-Y/-Z, 6-8 = Rev X/Y/Z
|
||||||
// Undo the slicing transform to recover machine-frame coordinates.
|
auto remap = [this, &pos](int r) -> double {
|
||||||
// Slicing applied: T(0,0,-min_z_rot) * R(-alpha, X) * original_pos
|
int axis = r % 3;
|
||||||
// Inverse: R(+alpha, X) * T(0,0,+min_z_rot) * slicing_pos
|
if (r < 3) return pos[axis];
|
||||||
//
|
if (r < 6) return -pos[axis];
|
||||||
// First undo the Z-shift, then apply R(+alpha, X).
|
return m_build_vol_max[axis] - pos[axis];
|
||||||
double sz = pos.z() + m_belt_z_shift; // undo T(0,0,-min_z_rot)
|
};
|
||||||
return Vec3d(
|
return { remap(m_remap_x), remap(m_remap_y), remap(m_remap_z) };
|
||||||
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)
|
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
||||||
|
|||||||
@@ -127,10 +127,12 @@ public:
|
|||||||
|
|
||||||
// Belt printer: set the belt angle and precompute sin/cos for coordinate transformation.
|
// Belt printer: set the belt angle and precompute sin/cos for coordinate transformation.
|
||||||
void set_belt_angle(double angle_deg);
|
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.; }
|
bool is_belt_printer() const { return m_belt_angle_rad != 0.; }
|
||||||
// Transform a point from the slicing frame to machine/world coordinates (inverse rotation).
|
// Set axis remap for G-code output (BeltRemapAxis enum values).
|
||||||
|
void set_axis_remap(int rx, int ry, int rz);
|
||||||
|
// Set build volume extents for Rev remap mode (max X, Y, Z).
|
||||||
|
void set_build_volume_max(const Vec3d &max);
|
||||||
|
// Transform a point from the slicing frame to machine coordinates.
|
||||||
Vec3d to_machine_coords(const Vec3d &pos) const;
|
Vec3d to_machine_coords(const Vec3d &pos) const;
|
||||||
|
|
||||||
// Returns whether this flavor supports separate print and travel acceleration.
|
// Returns whether this flavor supports separate print and travel acceleration.
|
||||||
@@ -186,11 +188,12 @@ public:
|
|||||||
//SoftFever
|
//SoftFever
|
||||||
bool m_is_bbl_printers = false;
|
bool m_is_bbl_printers = false;
|
||||||
|
|
||||||
// Belt printer coordinate transformation (inverse of slicing rotation)
|
// Belt printer state
|
||||||
double m_belt_angle_rad = 0.;
|
double m_belt_angle_rad = 0.;
|
||||||
double m_belt_cos = 1.0;
|
int m_remap_x = 0;
|
||||||
double m_belt_sin = 0.0;
|
int m_remap_y = 1;
|
||||||
double m_belt_z_shift = 0.; // Z-shift applied during slicing (min_z_rotated, typically negative)
|
int m_remap_z = 2;
|
||||||
|
Vec3d m_build_vol_max = Vec3d::Zero();
|
||||||
double m_current_speed;
|
double m_current_speed;
|
||||||
bool m_is_first_layer = true;
|
bool m_is_first_layer = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1010,7 +1010,11 @@ static std::vector<std::string> s_Preset_machine_limits_options {
|
|||||||
|
|
||||||
static std::vector<std::string> s_Preset_printer_options {
|
static std::vector<std::string> s_Preset_printer_options {
|
||||||
"printer_technology",
|
"printer_technology",
|
||||||
"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",
|
"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", "belt_shear_x", "belt_shear_x_angle", "belt_shear_x_from",
|
||||||
|
"belt_shear_y", "belt_shear_y_angle", "belt_shear_y_from",
|
||||||
|
"belt_shear_z", "belt_shear_z_angle", "belt_shear_z_from",
|
||||||
|
"belt_scale_x", "belt_scale_x_angle", "belt_scale_y", "belt_scale_y_angle", "belt_scale_z", "belt_scale_z_angle",
|
||||||
|
"belt_gcode_remap_x", "belt_gcode_remap_y", "belt_gcode_remap_z", "gcode_flavor",
|
||||||
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
|
"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",
|
"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",
|
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
|
||||||
|
|||||||
@@ -288,6 +288,44 @@ static t_config_enum_values s_keys_map_SlicingMode {
|
|||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SlicingMode)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SlicingMode)
|
||||||
|
|
||||||
|
static t_config_enum_values s_keys_map_BeltShearMode {
|
||||||
|
{ "none", int(BeltShearMode::None) },
|
||||||
|
{ "pos_cot", int(BeltShearMode::PosCot) },
|
||||||
|
{ "neg_cot", int(BeltShearMode::NegCot) },
|
||||||
|
{ "pos_tan", int(BeltShearMode::PosTan) },
|
||||||
|
{ "neg_tan", int(BeltShearMode::NegTan) },
|
||||||
|
};
|
||||||
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltShearMode)
|
||||||
|
|
||||||
|
static t_config_enum_values s_keys_map_BeltAxis {
|
||||||
|
{ "x", int(BeltAxis::X) },
|
||||||
|
{ "y", int(BeltAxis::Y) },
|
||||||
|
{ "z", int(BeltAxis::Z) },
|
||||||
|
};
|
||||||
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltAxis)
|
||||||
|
|
||||||
|
static t_config_enum_values s_keys_map_BeltScaleMode {
|
||||||
|
{ "none", int(BeltScaleMode::None) },
|
||||||
|
{ "inv_sin", int(BeltScaleMode::InvSin) },
|
||||||
|
{ "inv_cos", int(BeltScaleMode::InvCos) },
|
||||||
|
{ "sin", int(BeltScaleMode::Sin) },
|
||||||
|
{ "cos", int(BeltScaleMode::Cos) },
|
||||||
|
};
|
||||||
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltScaleMode)
|
||||||
|
|
||||||
|
static t_config_enum_values s_keys_map_BeltRemapAxis {
|
||||||
|
{ "pos_x", int(BeltRemapAxis::PosX) },
|
||||||
|
{ "pos_y", int(BeltRemapAxis::PosY) },
|
||||||
|
{ "pos_z", int(BeltRemapAxis::PosZ) },
|
||||||
|
{ "neg_x", int(BeltRemapAxis::NegX) },
|
||||||
|
{ "neg_y", int(BeltRemapAxis::NegY) },
|
||||||
|
{ "neg_z", int(BeltRemapAxis::NegZ) },
|
||||||
|
{ "rev_x", int(BeltRemapAxis::RevX) },
|
||||||
|
{ "rev_y", int(BeltRemapAxis::RevY) },
|
||||||
|
{ "rev_z", int(BeltRemapAxis::RevZ) },
|
||||||
|
};
|
||||||
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltRemapAxis)
|
||||||
|
|
||||||
static t_config_enum_values s_keys_map_SupportMaterialPattern {
|
static t_config_enum_values s_keys_map_SupportMaterialPattern {
|
||||||
{ "rectilinear", smpRectilinear },
|
{ "rectilinear", smpRectilinear },
|
||||||
{ "rectilinear-grid", smpRectilinearGrid },
|
{ "rectilinear-grid", smpRectilinearGrid },
|
||||||
@@ -5978,6 +6016,103 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionBool(true));
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
|
// Per-axis shear controls for belt printer
|
||||||
|
auto add_belt_shear_mode = [this](const char *key, const char *label, BeltShearMode default_mode) {
|
||||||
|
auto def = this->add(key, coEnum);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L("Shear function applied to this axis in belt printer mode.");
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<BeltShearMode>::get_enum_values();
|
||||||
|
def->enum_values = {"none", "pos_cot", "neg_cot", "pos_tan", "neg_tan"};
|
||||||
|
def->enum_labels = {L("None"), L("+cot(α)"), L("-cot(α)"), L("+tan(α)"), L("-tan(α)")};
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<BeltShearMode>(default_mode));
|
||||||
|
};
|
||||||
|
auto add_belt_shear_angle = [this](const char *key, const char *label) {
|
||||||
|
auto def = this->add(key, coFloat);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L("Angle (degrees) for the shear function on this axis.");
|
||||||
|
def->sidetext = L("°");
|
||||||
|
def->min = 0.1;
|
||||||
|
def->max = 89.9;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(45));
|
||||||
|
};
|
||||||
|
auto add_belt_axis_enum = [this](const char *key, const char *label, const char *tooltip, BeltAxis default_axis) {
|
||||||
|
auto def = this->add(key, coEnum);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L(tooltip);
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<BeltAxis>::get_enum_values();
|
||||||
|
def->enum_values = {"x", "y", "z"};
|
||||||
|
def->enum_labels = {L("X"), L("Y"), L("Z")};
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<BeltAxis>(default_axis));
|
||||||
|
};
|
||||||
|
|
||||||
|
add_belt_shear_mode("belt_shear_x", "Function", BeltShearMode::None);
|
||||||
|
add_belt_shear_angle("belt_shear_x_angle", "Angle");
|
||||||
|
add_belt_axis_enum("belt_shear_x_from", "From", "Source axis for X shear.", BeltAxis::Z);
|
||||||
|
|
||||||
|
add_belt_shear_mode("belt_shear_y", "Function", BeltShearMode::PosCot);
|
||||||
|
add_belt_shear_angle("belt_shear_y_angle", "Angle");
|
||||||
|
add_belt_axis_enum("belt_shear_y_from", "From", "Source axis for Y shear.", BeltAxis::Z);
|
||||||
|
|
||||||
|
add_belt_shear_mode("belt_shear_z", "Function", BeltShearMode::None);
|
||||||
|
add_belt_shear_angle("belt_shear_z_angle", "Angle");
|
||||||
|
add_belt_axis_enum("belt_shear_z_from", "From", "Source axis for Z shear.", BeltAxis::Y);
|
||||||
|
|
||||||
|
// Per-axis scale controls for belt printer
|
||||||
|
auto add_belt_scale_mode = [this](const char *key, const char *label, BeltScaleMode default_mode) {
|
||||||
|
auto def = this->add(key, coEnum);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L("Scale factor applied to this axis in belt printer mode.");
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<BeltScaleMode>::get_enum_values();
|
||||||
|
def->enum_values = {"none", "inv_sin", "inv_cos", "sin", "cos"};
|
||||||
|
def->enum_labels = {L("None"), L("1/sin(α)"), L("1/cos(α)"), L("sin(α)"), L("cos(α)")};
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<BeltScaleMode>(default_mode));
|
||||||
|
};
|
||||||
|
auto add_belt_scale_angle = [this](const char *key, const char *label) {
|
||||||
|
auto def = this->add(key, coFloat);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L("Angle (degrees) for the scale function on this axis.");
|
||||||
|
def->sidetext = L("°");
|
||||||
|
def->min = 0.1;
|
||||||
|
def->max = 89.9;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(45));
|
||||||
|
};
|
||||||
|
|
||||||
|
add_belt_scale_mode("belt_scale_x", "Function", BeltScaleMode::None);
|
||||||
|
add_belt_scale_angle("belt_scale_x_angle", "Angle");
|
||||||
|
|
||||||
|
add_belt_scale_mode("belt_scale_y", "Function", BeltScaleMode::None);
|
||||||
|
add_belt_scale_angle("belt_scale_y_angle", "Angle");
|
||||||
|
|
||||||
|
add_belt_scale_mode("belt_scale_z", "Function", BeltScaleMode::None);
|
||||||
|
add_belt_scale_angle("belt_scale_z_angle", "Angle");
|
||||||
|
|
||||||
|
// G-code axis remap with sign
|
||||||
|
auto add_belt_remap = [this](const char *key, const char *label, const char *tooltip, BeltRemapAxis default_axis) {
|
||||||
|
auto def = this->add(key, coEnum);
|
||||||
|
def->label = L(label);
|
||||||
|
def->category = L("Printable space");
|
||||||
|
def->tooltip = L(tooltip);
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<BeltRemapAxis>::get_enum_values();
|
||||||
|
def->enum_values = {"pos_x", "pos_y", "pos_z", "neg_x", "neg_y", "neg_z", "rev_x", "rev_y", "rev_z"};
|
||||||
|
def->enum_labels = {L("+X"), L("+Y"), L("+Z"), L("-X"), L("-Y"), L("-Z"), L("Rev X"), L("Rev Y"), L("Rev Z")};
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<BeltRemapAxis>(default_axis));
|
||||||
|
};
|
||||||
|
|
||||||
|
add_belt_remap("belt_gcode_remap_x", "X", "Which slicing axis maps to machine X in G-code output.", BeltRemapAxis::PosX);
|
||||||
|
add_belt_remap("belt_gcode_remap_y", "Y", "Which slicing axis maps to machine Y in G-code output.", BeltRemapAxis::PosY);
|
||||||
|
add_belt_remap("belt_gcode_remap_z", "Z", "Which slicing axis maps to machine Z in G-code output.", BeltRemapAxis::PosZ);
|
||||||
|
|
||||||
def = this->add("tree_support_branch_angle", coFloat);
|
def = this->add("tree_support_branch_angle", coFloat);
|
||||||
def->label = L("Tree support branch angle");
|
def->label = L("Tree support branch angle");
|
||||||
def->category = L("Support");
|
def->category = L("Support");
|
||||||
|
|||||||
@@ -156,6 +156,38 @@ enum class SlicingMode
|
|||||||
CloseHoles,
|
CloseHoles,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class BeltShearMode
|
||||||
|
{
|
||||||
|
None, // No shear on this axis
|
||||||
|
PosCot, // += cot(α)
|
||||||
|
NegCot, // -= cot(α)
|
||||||
|
PosTan, // += tan(α)
|
||||||
|
NegTan, // -= tan(α)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BeltScaleMode
|
||||||
|
{
|
||||||
|
None, // No scaling (factor = 1)
|
||||||
|
InvSin, // 1/sin(α)
|
||||||
|
InvCos, // 1/cos(α)
|
||||||
|
Sin, // sin(α)
|
||||||
|
Cos, // cos(α)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BeltAxis
|
||||||
|
{
|
||||||
|
X = 0,
|
||||||
|
Y = 1,
|
||||||
|
Z = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class BeltRemapAxis
|
||||||
|
{
|
||||||
|
PosX = 0, PosY = 1, PosZ = 2,
|
||||||
|
NegX = 3, NegY = 4, NegZ = 5,
|
||||||
|
RevX = 6, RevY = 7, RevZ = 8, // Reversed: max - pos
|
||||||
|
};
|
||||||
|
|
||||||
enum SupportMaterialPattern {
|
enum SupportMaterialPattern {
|
||||||
smpDefault,
|
smpDefault,
|
||||||
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
|
smpRectilinear, smpRectilinearGrid, smpHoneycomb,
|
||||||
@@ -499,6 +531,10 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NoiseType)
|
|||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode)
|
||||||
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltShearMode)
|
||||||
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltScaleMode)
|
||||||
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltAxis)
|
||||||
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltRemapAxis)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialStyle)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialInterfacePattern)
|
||||||
@@ -1416,6 +1452,24 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionBool, belt_printer))
|
((ConfigOptionBool, belt_printer))
|
||||||
((ConfigOptionFloat, belt_printer_angle))
|
((ConfigOptionFloat, belt_printer_angle))
|
||||||
((ConfigOptionBool, belt_printer_infinite_y))
|
((ConfigOptionBool, belt_printer_infinite_y))
|
||||||
|
((ConfigOptionEnum<BeltShearMode>, belt_shear_x))
|
||||||
|
((ConfigOptionFloat, belt_shear_x_angle))
|
||||||
|
((ConfigOptionEnum<BeltAxis>, belt_shear_x_from))
|
||||||
|
((ConfigOptionEnum<BeltShearMode>, belt_shear_y))
|
||||||
|
((ConfigOptionFloat, belt_shear_y_angle))
|
||||||
|
((ConfigOptionEnum<BeltAxis>, belt_shear_y_from))
|
||||||
|
((ConfigOptionEnum<BeltShearMode>, belt_shear_z))
|
||||||
|
((ConfigOptionFloat, belt_shear_z_angle))
|
||||||
|
((ConfigOptionEnum<BeltAxis>, belt_shear_z_from))
|
||||||
|
((ConfigOptionEnum<BeltScaleMode>, belt_scale_x))
|
||||||
|
((ConfigOptionFloat, belt_scale_x_angle))
|
||||||
|
((ConfigOptionEnum<BeltScaleMode>, belt_scale_y))
|
||||||
|
((ConfigOptionFloat, belt_scale_y_angle))
|
||||||
|
((ConfigOptionEnum<BeltScaleMode>, belt_scale_z))
|
||||||
|
((ConfigOptionFloat, belt_scale_z_angle))
|
||||||
|
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_x))
|
||||||
|
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_y))
|
||||||
|
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_z))
|
||||||
//BBS
|
//BBS
|
||||||
((ConfigOptionInts, additional_cooling_fan_speed))
|
((ConfigOptionInts, additional_cooling_fan_speed))
|
||||||
((ConfigOptionBool, reduce_crossing_wall))
|
((ConfigOptionBool, reduce_crossing_wall))
|
||||||
|
|||||||
@@ -3392,14 +3392,55 @@ void PrintObject::update_slicing_parameters()
|
|||||||
// Orca: updated function call for XYZ shrinkage compensation
|
// Orca: updated function call for XYZ shrinkage compensation
|
||||||
if (!m_slicing_params.valid) {
|
if (!m_slicing_params.valid) {
|
||||||
coordf_t object_height = this->model_object()->max_z();
|
coordf_t object_height = this->model_object()->max_z();
|
||||||
if (this->print()->config().belt_printer.value) {
|
// Belt shear/scale may change the effective Z height.
|
||||||
// After mesh rotation R(-alpha, X), effective height in the slicing
|
const auto &pcfg = this->print()->config();
|
||||||
// direction is y_extent*sin(a) + z_extent*cos(a).
|
if (pcfg.belt_printer.value) {
|
||||||
double angle_rad = Geometry::deg2rad(this->print()->config().belt_printer_angle.value);
|
bool has_z_shear = pcfg.belt_shear_z.value != BeltShearMode::None;
|
||||||
BoundingBoxf3 bb = this->model_object()->raw_bounding_box();
|
bool has_z_scale = pcfg.belt_scale_z.value != BeltScaleMode::None;
|
||||||
object_height = bb.size().y() * std::sin(angle_rad) + bb.size().z() * std::cos(angle_rad);
|
if (has_z_shear || has_z_scale) {
|
||||||
|
auto compute_shear_factor = [](BeltShearMode mode, double angle_deg) -> double {
|
||||||
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
|
double sin_a = std::sin(angle_rad), cos_a = std::cos(angle_rad);
|
||||||
|
switch (mode) {
|
||||||
|
case BeltShearMode::PosCot: return (sin_a > EPSILON) ? cos_a / sin_a : 0.;
|
||||||
|
case BeltShearMode::NegCot: return (sin_a > EPSILON) ? -cos_a / sin_a : 0.;
|
||||||
|
case BeltShearMode::PosTan: return (cos_a > EPSILON) ? sin_a / cos_a : 0.;
|
||||||
|
case BeltShearMode::NegTan: return (cos_a > EPSILON) ? -sin_a / cos_a : 0.;
|
||||||
|
default: return 0.;
|
||||||
}
|
}
|
||||||
m_slicing_params = SlicingParameters::create_from_config(this->print()->config(), m_config, object_height,
|
};
|
||||||
|
auto compute_scale_factor = [](BeltScaleMode mode, double angle_deg) -> double {
|
||||||
|
if (mode == BeltScaleMode::None) return 1.;
|
||||||
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
|
double sin_a = std::sin(angle_rad), cos_a = std::cos(angle_rad);
|
||||||
|
switch (mode) {
|
||||||
|
case BeltScaleMode::InvSin: return (sin_a > EPSILON) ? 1. / sin_a : 1.;
|
||||||
|
case BeltScaleMode::InvCos: return (cos_a > EPSILON) ? 1. / cos_a : 1.;
|
||||||
|
case BeltScaleMode::Sin: return sin_a;
|
||||||
|
case BeltScaleMode::Cos: return cos_a;
|
||||||
|
default: return 1.;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
double shear_factor = has_z_shear ? compute_shear_factor(pcfg.belt_shear_z.value, pcfg.belt_shear_z_angle.value) : 0.;
|
||||||
|
double scale_z = compute_scale_factor(pcfg.belt_scale_z.value, pcfg.belt_scale_z_angle.value);
|
||||||
|
if (has_z_shear && std::abs(shear_factor) > EPSILON) {
|
||||||
|
int from = int(pcfg.belt_shear_z_from.value);
|
||||||
|
BoundingBoxf3 bb = this->model_object()->raw_bounding_box();
|
||||||
|
double min_rz = std::numeric_limits<double>::max();
|
||||||
|
double max_rz = std::numeric_limits<double>::lowest();
|
||||||
|
for (double vz : {bb.min.z(), bb.max.z()})
|
||||||
|
for (double vs : {bb.min(from), bb.max(from)}) {
|
||||||
|
double new_z = scale_z * (vz + shear_factor * vs);
|
||||||
|
min_rz = std::min(min_rz, new_z);
|
||||||
|
max_rz = std::max(max_rz, new_z);
|
||||||
|
}
|
||||||
|
object_height = max_rz - min_rz;
|
||||||
|
} else {
|
||||||
|
object_height *= scale_z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_slicing_params = SlicingParameters::create_from_config(pcfg, m_config, object_height,
|
||||||
this->object_extruders(), this->print()->shrinkage_compensation());
|
this->object_extruders(), this->print()->shrinkage_compensation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3441,9 +3482,51 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
|
|||||||
if (object_max_z <= 0.f) {
|
if (object_max_z <= 0.f) {
|
||||||
BoundingBoxf3 bb = model_object.raw_bounding_box();
|
BoundingBoxf3 bb = model_object.raw_bounding_box();
|
||||||
object_max_z = (float)bb.size().z();
|
object_max_z = (float)bb.size().z();
|
||||||
|
// Belt shear/scale may change the effective Z height.
|
||||||
if (print_config.belt_printer.value) {
|
if (print_config.belt_printer.value) {
|
||||||
double angle_rad = Geometry::deg2rad(print_config.belt_printer_angle.value);
|
bool has_z_shear = print_config.belt_shear_z.value != BeltShearMode::None;
|
||||||
object_max_z = (float)(bb.size().y() * std::sin(angle_rad) + bb.size().z() * std::cos(angle_rad));
|
bool has_z_scale = print_config.belt_scale_z.value != BeltScaleMode::None;
|
||||||
|
if (has_z_shear || has_z_scale) {
|
||||||
|
auto compute_shear_factor = [](BeltShearMode mode, double angle_deg) -> double {
|
||||||
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
|
double sin_a = std::sin(angle_rad), cos_a = std::cos(angle_rad);
|
||||||
|
switch (mode) {
|
||||||
|
case BeltShearMode::PosCot: return (sin_a > EPSILON) ? cos_a / sin_a : 0.;
|
||||||
|
case BeltShearMode::NegCot: return (sin_a > EPSILON) ? -cos_a / sin_a : 0.;
|
||||||
|
case BeltShearMode::PosTan: return (cos_a > EPSILON) ? sin_a / cos_a : 0.;
|
||||||
|
case BeltShearMode::NegTan: return (cos_a > EPSILON) ? -sin_a / cos_a : 0.;
|
||||||
|
default: return 0.;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto compute_scale_factor = [](BeltScaleMode mode, double angle_deg) -> double {
|
||||||
|
if (mode == BeltScaleMode::None) return 1.;
|
||||||
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
|
double sin_a = std::sin(angle_rad), cos_a = std::cos(angle_rad);
|
||||||
|
switch (mode) {
|
||||||
|
case BeltScaleMode::InvSin: return (sin_a > EPSILON) ? 1. / sin_a : 1.;
|
||||||
|
case BeltScaleMode::InvCos: return (cos_a > EPSILON) ? 1. / cos_a : 1.;
|
||||||
|
case BeltScaleMode::Sin: return sin_a;
|
||||||
|
case BeltScaleMode::Cos: return cos_a;
|
||||||
|
default: return 1.;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
double shear_factor = has_z_shear ? compute_shear_factor(print_config.belt_shear_z.value, print_config.belt_shear_z_angle.value) : 0.;
|
||||||
|
double scale_z = compute_scale_factor(print_config.belt_scale_z.value, print_config.belt_scale_z_angle.value);
|
||||||
|
if (has_z_shear && std::abs(shear_factor) > EPSILON) {
|
||||||
|
int from = int(print_config.belt_shear_z_from.value);
|
||||||
|
double min_rz = std::numeric_limits<double>::max();
|
||||||
|
double max_rz = std::numeric_limits<double>::lowest();
|
||||||
|
for (double vz : {bb.min.z(), bb.max.z()})
|
||||||
|
for (double vs : {bb.min(from), bb.max(from)}) {
|
||||||
|
double new_z = scale_z * (vz + shear_factor * vs);
|
||||||
|
min_rz = std::min(min_rz, new_z);
|
||||||
|
max_rz = std::max(max_rz, new_z);
|
||||||
|
}
|
||||||
|
object_max_z = (float)(max_rz - min_rz);
|
||||||
|
} else {
|
||||||
|
object_max_z *= (float)scale_z;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders, object_shrinkage_compensation);
|
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders, object_shrinkage_compensation);
|
||||||
|
|||||||
@@ -141,23 +141,69 @@ static std::vector<VolumeSlices> slice_volumes_inner(
|
|||||||
params_base.extra_offset = 0;
|
params_base.extra_offset = 0;
|
||||||
params_base.trafo = object_trafo;
|
params_base.trafo = object_trafo;
|
||||||
if (print_config.belt_printer.value) {
|
if (print_config.belt_printer.value) {
|
||||||
double angle_rad = Geometry::deg2rad(print_config.belt_printer_angle.value);
|
// Build per-axis shear matrix from 3 independent axis configs.
|
||||||
// Rotate mesh by -alpha about X so horizontal slice planes = gantry-parallel planes.
|
auto compute_shear_factor = [](BeltShearMode mode, double angle_deg) -> double {
|
||||||
// The gantry (XY) is tilted by belt_printer_angle; this rotation aligns it with horizontal.
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
Transform3d belt_rotation = Transform3d::Identity();
|
double sin_a = std::sin(angle_rad);
|
||||||
belt_rotation.rotate(Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()));
|
double cos_a = std::cos(angle_rad);
|
||||||
params_base.trafo = belt_rotation * params_base.trafo;
|
switch (mode) {
|
||||||
// Compute Z-shift from model_volumes: find min-Z of all rotated meshes
|
case BeltShearMode::PosCot: return (sin_a > EPSILON) ? cos_a / sin_a : 0.;
|
||||||
// so the rotated geometry starts at Z=0 (the belt surface in slicing frame).
|
case BeltShearMode::NegCot: return (sin_a > EPSILON) ? -cos_a / sin_a : 0.;
|
||||||
double min_z_rotated = std::numeric_limits<double>::max();
|
case BeltShearMode::PosTan: return (cos_a > EPSILON) ? sin_a / cos_a : 0.;
|
||||||
for (const ModelVolume *mv : model_volumes) {
|
case BeltShearMode::NegTan: return (cos_a > EPSILON) ? -sin_a / cos_a : 0.;
|
||||||
if (!model_volume_needs_slicing(*mv)) continue;
|
default: return 0.;
|
||||||
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;
|
|
||||||
|
struct AxisShear { BeltShearMode mode; double angle; int from; };
|
||||||
|
AxisShear axes[3] = {
|
||||||
|
{ print_config.belt_shear_x.value, print_config.belt_shear_x_angle.value, int(print_config.belt_shear_x_from.value) },
|
||||||
|
{ print_config.belt_shear_y.value, print_config.belt_shear_y_angle.value, int(print_config.belt_shear_y_from.value) },
|
||||||
|
{ print_config.belt_shear_z.value, print_config.belt_shear_z_angle.value, int(print_config.belt_shear_z_from.value) },
|
||||||
|
};
|
||||||
|
|
||||||
|
Transform3d belt_shear = Transform3d::Identity();
|
||||||
|
bool has_shear = false;
|
||||||
|
for (int row = 0; row < 3; ++row) {
|
||||||
|
if (axes[row].mode != BeltShearMode::None) {
|
||||||
|
double factor = compute_shear_factor(axes[row].mode, axes[row].angle);
|
||||||
|
if (std::abs(factor) > EPSILON) {
|
||||||
|
belt_shear.matrix()(row, axes[row].from) += factor;
|
||||||
|
has_shear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build per-axis scale matrix.
|
||||||
|
auto compute_scale_factor = [](BeltScaleMode mode, double angle_deg) -> double {
|
||||||
|
if (mode == BeltScaleMode::None) return 1.;
|
||||||
|
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
|
double sin_a = std::sin(angle_rad);
|
||||||
|
double cos_a = std::cos(angle_rad);
|
||||||
|
switch (mode) {
|
||||||
|
case BeltScaleMode::InvSin: return (sin_a > EPSILON) ? 1. / sin_a : 1.;
|
||||||
|
case BeltScaleMode::InvCos: return (cos_a > EPSILON) ? 1. / cos_a : 1.;
|
||||||
|
case BeltScaleMode::Sin: return sin_a;
|
||||||
|
case BeltScaleMode::Cos: return cos_a;
|
||||||
|
default: return 1.;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Transform3d belt_scale = Transform3d::Identity();
|
||||||
|
bool has_scale = false;
|
||||||
|
double sx = compute_scale_factor(print_config.belt_scale_x.value, print_config.belt_scale_x_angle.value);
|
||||||
|
double sy = compute_scale_factor(print_config.belt_scale_y.value, print_config.belt_scale_y_angle.value);
|
||||||
|
double sz = compute_scale_factor(print_config.belt_scale_z.value, print_config.belt_scale_z_angle.value);
|
||||||
|
if (std::abs(sx - 1.) > EPSILON || std::abs(sy - 1.) > EPSILON || std::abs(sz - 1.) > EPSILON) {
|
||||||
|
belt_scale.matrix()(0, 0) = sx;
|
||||||
|
belt_scale.matrix()(1, 1) = sy;
|
||||||
|
belt_scale.matrix()(2, 2) = sz;
|
||||||
|
has_scale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply: scale * shear * trafo (shear first, then scale).
|
||||||
|
if (has_shear || has_scale)
|
||||||
|
params_base.trafo = belt_scale * belt_shear * params_base.trafo;
|
||||||
}
|
}
|
||||||
//BBS: 0.0025mm is safe enough to simplify the data to speed slicing up for high-resolution model.
|
//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.
|
//Also has on influence on arc fitting which has default resolution 0.0125mm.
|
||||||
|
|||||||
@@ -1271,7 +1271,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
|
|
||||||
m_max_print_height = gcode_result.printable_height;
|
m_max_print_height = gcode_result.printable_height;
|
||||||
m_z_offset = gcode_result.z_offset;
|
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);
|
// load_toolpaths(gcode_result, build_volume, exclude_bounding_box);
|
||||||
|
|
||||||
@@ -2210,15 +2210,17 @@ 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 "raw" view: apply slicing rotation to view matrix so toolpaths appear
|
// Belt "designed" view: apply inverse shear to view matrix so toolpaths appear
|
||||||
// in the slicing frame (rotated part with horizontal layers).
|
// upright (as originally designed) instead of sheared on the belt.
|
||||||
if (m_belt_show_raw && m_belt_view_enabled && m_belt_angle_deg > 0.f) {
|
if (m_belt_show_designed && m_belt_view_enabled && m_belt_angle_deg > 0.f) {
|
||||||
double angle_rad = Geometry::deg2rad(static_cast<double>(m_belt_angle_deg));
|
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.
|
double sin_a = std::sin(angle_rad);
|
||||||
Transform3d slicing_trafo = Transform3d::Identity();
|
if (sin_a > 1e-6) {
|
||||||
slicing_trafo.translate(Vec3d(0., 0., -static_cast<double>(m_belt_z_shift)));
|
double cot_alpha = std::cos(angle_rad) / sin_a;
|
||||||
slicing_trafo = Eigen::AngleAxisd(-angle_rad, Vec3d::UnitX()) * slicing_trafo;
|
Transform3d inverse_shear = Transform3d::Identity();
|
||||||
view = (camera.get_view_matrix() * slicing_trafo).matrix().cast<float>();
|
inverse_shear.matrix()(1, 2) = -cot_alpha; // Y -= Z * cot(α)
|
||||||
|
view = (camera.get_view_matrix() * inverse_shear).matrix().cast<float>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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>()));
|
||||||
@@ -4421,7 +4423,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
|||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Dummy({ window_padding, 0 });
|
ImGui::Dummy({ window_padding, 0 });
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Checkbox("Show raw G-code (slicing frame)", &m_belt_show_raw);
|
ImGui::Checkbox("Show designed view (upright)", &m_belt_show_designed);
|
||||||
}
|
}
|
||||||
|
|
||||||
legend_height = ImGui::GetCurrentWindow()->Size.y;
|
legend_height = ImGui::GetCurrentWindow()->Size.y;
|
||||||
|
|||||||
@@ -239,8 +239,7 @@ mutable bool m_no_render_path { false };
|
|||||||
|
|
||||||
bool m_belt_view_enabled = false;
|
bool m_belt_view_enabled = false;
|
||||||
float m_belt_angle_deg = 0.f;
|
float m_belt_angle_deg = 0.f;
|
||||||
float m_belt_z_shift = 0.f;
|
bool m_belt_show_designed = false; // Toggle: show designed (upright) view via inverse shear
|
||||||
bool m_belt_show_raw = false; // Toggle: show raw slicing-frame G-code (rotated part)
|
|
||||||
|
|
||||||
libvgcode::Viewer m_viewer;
|
libvgcode::Viewer m_viewer;
|
||||||
bool m_loaded_as_preview{ false };
|
bool m_loaded_as_preview{ false };
|
||||||
|
|||||||
@@ -4370,6 +4370,53 @@ void TabPrinter::build_fff()
|
|||||||
optgroup->append_single_option_line("belt_printer");
|
optgroup->append_single_option_line("belt_printer");
|
||||||
optgroup->append_single_option_line("belt_printer_angle");
|
optgroup->append_single_option_line("belt_printer_angle");
|
||||||
optgroup->append_single_option_line("belt_printer_infinite_y");
|
optgroup->append_single_option_line("belt_printer_infinite_y");
|
||||||
|
// Per-axis shear: group mode + angle + source on one row per axis
|
||||||
|
{
|
||||||
|
Line line = { L("Shear X"), L("Shear applied to the X axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_x"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_x_angle"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_x_from"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("Shear Y"), L("Shear applied to the Y axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_y"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_y_angle"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_y_from"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("Shear Z"), L("Shear applied to the Z axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_z"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_z_angle"));
|
||||||
|
line.append_option(optgroup->get_option("belt_shear_z_from"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("Scale X"), L("Scale applied to the X axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_x"));
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_x_angle"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("Scale Y"), L("Scale applied to the Y axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_y"));
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_y_angle"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("Scale Z"), L("Scale applied to the Z axis before slicing") };
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_z"));
|
||||||
|
line.append_option(optgroup->get_option("belt_scale_z_angle"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Line line = { L("G-code axis remap"), L("Remap slicing-frame axes to machine axes in G-code output") };
|
||||||
|
line.append_option(optgroup->get_option("belt_gcode_remap_x"));
|
||||||
|
line.append_option(optgroup->get_option("belt_gcode_remap_y"));
|
||||||
|
line.append_option(optgroup->get_option("belt_gcode_remap_z"));
|
||||||
|
optgroup->append_line(line);
|
||||||
|
}
|
||||||
optgroup->append_single_option_line("support_multi_bed_types","printer_basic_information_printable_space#support-multi-bed-types");
|
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");
|
optgroup->append_single_option_line("best_object_pos", "printer_basic_information_printable_space#best-object-position");
|
||||||
// todo: for multi_extruder test
|
// todo: for multi_extruder test
|
||||||
@@ -5233,6 +5280,10 @@ void TabPrinter::toggle_options()
|
|||||||
bool is_belt = m_config->opt_bool("belt_printer");
|
bool is_belt = m_config->opt_bool("belt_printer");
|
||||||
toggle_line("belt_printer_angle", is_belt);
|
toggle_line("belt_printer_angle", is_belt);
|
||||||
toggle_line("belt_printer_infinite_y", is_belt);
|
toggle_line("belt_printer_infinite_y", is_belt);
|
||||||
|
for (auto el : {"belt_shear_x", "belt_shear_y", "belt_shear_z",
|
||||||
|
"belt_scale_x", "belt_scale_y", "belt_scale_z",
|
||||||
|
"belt_gcode_remap_x"})
|
||||||
|
toggle_line(el, is_belt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user