mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 05:27:50 +00:00
Part 3.2: decouple axis remapping, enable viewing settings in Developer mode or when Belt mode is active
This commit is contained in:
@@ -15,13 +15,7 @@ void BeltGCode::init_belt_writer(Print &print, bool is_bbl_printers)
|
|||||||
auto belt_writer = std::make_unique<BeltGCodeWriter>();
|
auto belt_writer = std::make_unique<BeltGCodeWriter>();
|
||||||
belt_writer->set_is_bbl_machine(is_bbl_printers);
|
belt_writer->set_is_bbl_machine(is_bbl_printers);
|
||||||
belt_writer->set_belt_angle(print.config().belt_printer_angle.value);
|
belt_writer->set_belt_angle(print.config().belt_printer_angle.value);
|
||||||
belt_writer->set_axis_remap(
|
// Axis remap and build volume max are set by base GCode after init_belt_writer returns.
|
||||||
int(print.config().belt_gcode_remap_x.value),
|
|
||||||
int(print.config().belt_gcode_remap_y.value),
|
|
||||||
int(print.config().belt_gcode_remap_z.value));
|
|
||||||
BoundingBoxf bbox_bed(print.config().printable_area.values);
|
|
||||||
belt_writer->set_build_volume_max(Vec3d(bbox_bed.max.x(), bbox_bed.max.y(),
|
|
||||||
print.config().printable_height.value));
|
|
||||||
belt_writer->set_belt_back_transform(print.config());
|
belt_writer->set_belt_back_transform(print.config());
|
||||||
m_writer = std::move(belt_writer);
|
m_writer = std::move(belt_writer);
|
||||||
|
|
||||||
@@ -59,9 +53,9 @@ void BeltGCode::write_belt_header(GCodeOutputStream &file, const Print &print)
|
|||||||
file.write_format("; belt_scale_z = %s\n", full_cfg.opt_serialize("belt_scale_z").c_str());
|
file.write_format("; belt_scale_z = %s\n", full_cfg.opt_serialize("belt_scale_z").c_str());
|
||||||
file.write_format("; belt_scale_z_angle = %.1f\n", print.config().belt_scale_z_angle.value);
|
file.write_format("; belt_scale_z_angle = %.1f\n", print.config().belt_scale_z_angle.value);
|
||||||
// Pre-slice remap configs
|
// Pre-slice remap configs
|
||||||
file.write_format("; belt_preslice_remap_x = %s\n", full_cfg.opt_serialize("belt_preslice_remap_x").c_str());
|
file.write_format("; preslice_remap_x = %s\n", full_cfg.opt_serialize("preslice_remap_x").c_str());
|
||||||
file.write_format("; belt_preslice_remap_y = %s\n", full_cfg.opt_serialize("belt_preslice_remap_y").c_str());
|
file.write_format("; preslice_remap_y = %s\n", full_cfg.opt_serialize("preslice_remap_y").c_str());
|
||||||
file.write_format("; belt_preslice_remap_z = %s\n", full_cfg.opt_serialize("belt_preslice_remap_z").c_str());
|
file.write_format("; preslice_remap_z = %s\n", full_cfg.opt_serialize("preslice_remap_z").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeltGCode::on_set_origin(const PrintObject *obj, const Point &inst_shift)
|
void BeltGCode::on_set_origin(const PrintObject *obj, const Point &inst_shift)
|
||||||
|
|||||||
@@ -10,18 +10,6 @@ void BeltGCodeWriter::set_belt_angle(double angle_deg)
|
|||||||
m_belt_angle_rad = Geometry::deg2rad(angle_deg);
|
m_belt_angle_rad = Geometry::deg2rad(angle_deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeltGCodeWriter::set_axis_remap(int rx, int ry, int rz)
|
|
||||||
{
|
|
||||||
m_remap_x = rx;
|
|
||||||
m_remap_y = ry;
|
|
||||||
m_remap_z = rz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeltGCodeWriter::set_build_volume_max(const Vec3d &max)
|
|
||||||
{
|
|
||||||
m_build_vol_max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeltGCodeWriter::set_belt_back_transform(const PrintConfig &config)
|
void BeltGCodeWriter::set_belt_back_transform(const PrintConfig &config)
|
||||||
{
|
{
|
||||||
m_belt_back_transform.init_from_config(config);
|
m_belt_back_transform.init_from_config(config);
|
||||||
@@ -40,16 +28,9 @@ Vec3d BeltGCodeWriter::to_machine_coords(const Vec3d &pos) const
|
|||||||
{
|
{
|
||||||
// Step 1: Undo the shear/scale applied during slicing.
|
// Step 1: Undo the shear/scale applied during slicing.
|
||||||
Vec3d p = m_belt_back_transform.apply(pos);
|
Vec3d p = m_belt_back_transform.apply(pos);
|
||||||
// Step 2: Apply axis remapping for the machine's coordinate convention.
|
// Step 2: Apply axis remap (uses inherited base class method).
|
||||||
// BeltRemapAxis: 0-2 = +X/+Y/+Z, 3-5 = -X/-Y/-Z, 6-8 = Rev X/Y/Z
|
Vec3d result = apply_axis_remap(p);
|
||||||
auto remap = [this, &p](int r) -> double {
|
// Step 3: Per-axis origin snap.
|
||||||
int axis = r % 3;
|
|
||||||
if (r < 3) return p[axis];
|
|
||||||
if (r < 6) return -p[axis];
|
|
||||||
return m_build_vol_max[axis] - p[axis];
|
|
||||||
};
|
|
||||||
Vec3d result = { remap(m_remap_x), remap(m_remap_y), remap(m_remap_z) };
|
|
||||||
// Per-axis origin snap: shift so bbox min on each enabled axis = offset.
|
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
if (m_origin_snap[i])
|
if (m_origin_snap[i])
|
||||||
result[i] -= (m_origin_bbox_min[i] - m_origin_offset[i]);
|
result[i] -= (m_origin_bbox_min[i] - m_origin_offset[i]);
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ class BeltGCodeWriter : public GCodeWriter
|
|||||||
public:
|
public:
|
||||||
BeltGCodeWriter() : GCodeWriter() {}
|
BeltGCodeWriter() : GCodeWriter() {}
|
||||||
|
|
||||||
// Belt configuration
|
// Belt configuration (axis remap is inherited from GCodeWriter)
|
||||||
void set_belt_angle(double angle_deg);
|
void set_belt_angle(double angle_deg);
|
||||||
bool is_belt_printer() const { return m_belt_angle_rad != 0.; }
|
bool is_belt_printer() const { return m_belt_angle_rad != 0.; }
|
||||||
void set_axis_remap(int rx, int ry, int rz);
|
|
||||||
void set_build_volume_max(const Vec3d &max);
|
|
||||||
void set_belt_back_transform(const PrintConfig &config);
|
void set_belt_back_transform(const PrintConfig &config);
|
||||||
void set_origin_snap(int axis, bool enable, double offset, double bbox_min);
|
void set_origin_snap(int axis, bool enable, double offset, double bbox_min);
|
||||||
Vec3d to_machine_coords(const Vec3d &pos) const;
|
Vec3d to_machine_coords(const Vec3d &pos) const;
|
||||||
@@ -37,10 +35,6 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
double m_belt_angle_rad = 0.;
|
double m_belt_angle_rad = 0.;
|
||||||
int m_remap_x = 0;
|
|
||||||
int m_remap_y = 1;
|
|
||||||
int m_remap_z = 2;
|
|
||||||
Vec3d m_build_vol_max = Vec3d::Zero();
|
|
||||||
BeltBackTransform m_belt_back_transform;
|
BeltBackTransform m_belt_back_transform;
|
||||||
bool m_origin_snap[3] = {false, false, false};
|
bool m_origin_snap[3] = {false, false, false};
|
||||||
double m_origin_offset[3] = {0., 0., 0.};
|
double m_origin_offset[3] = {0., 0., 0.};
|
||||||
|
|||||||
@@ -13,31 +13,24 @@ std::unique_ptr<BeltSliceStrategy> BeltSliceStrategy::create(const PrintConfig &
|
|||||||
|
|
||||||
BeltSliceStrategy::BeltSliceStrategy(const PrintConfig &config)
|
BeltSliceStrategy::BeltSliceStrategy(const PrintConfig &config)
|
||||||
{
|
{
|
||||||
m_has_remap = BeltTransformPipeline::has_preslice_remap(config);
|
|
||||||
if (m_has_remap)
|
|
||||||
m_pre_remap = BeltTransformPipeline::build_preslice_remap(config);
|
|
||||||
|
|
||||||
m_shear = BeltTransformPipeline::build_shear_matrix(config, &m_has_shear);
|
m_shear = BeltTransformPipeline::build_shear_matrix(config, &m_has_shear);
|
||||||
m_scale = BeltTransformPipeline::build_scale_matrix(config, &m_has_scale);
|
m_scale = BeltTransformPipeline::build_scale_matrix(config, &m_has_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeltSliceStrategy::apply_to_trafo(Transform3d &trafo,
|
void BeltSliceStrategy::apply_to_trafo(Transform3d &trafo,
|
||||||
const ModelVolumePtrs &model_volumes,
|
const ModelVolumePtrs &model_volumes,
|
||||||
|
bool has_remap,
|
||||||
double *out_belt_min_z) const
|
double *out_belt_min_z) const
|
||||||
{
|
{
|
||||||
// Step 1: Pre-slice axis remap.
|
// Shear + scale (belt-only; pre-slice remap is handled separately).
|
||||||
if (m_has_remap)
|
|
||||||
trafo = m_pre_remap * trafo;
|
|
||||||
|
|
||||||
// Step 2: Shear + scale.
|
|
||||||
if (m_has_shear || m_has_scale) {
|
if (m_has_shear || m_has_scale) {
|
||||||
Transform3d belt_xform = Transform3d::Identity();
|
Transform3d belt_xform = Transform3d::Identity();
|
||||||
belt_xform.linear() = m_scale * m_shear;
|
belt_xform.linear() = m_scale * m_shear;
|
||||||
trafo = belt_xform * trafo;
|
trafo = belt_xform * trafo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Z-shift — detect if mesh clips below build plate after transforms.
|
// Z-shift — detect if mesh clips below build plate after transforms.
|
||||||
if (m_has_remap || m_has_shear || m_has_scale) {
|
if (has_remap || m_has_shear || m_has_scale) {
|
||||||
double min_z = std::numeric_limits<double>::max();
|
double min_z = std::numeric_limits<double>::max();
|
||||||
for (const ModelVolume *mv : model_volumes) {
|
for (const ModelVolume *mv : model_volumes) {
|
||||||
if (!mv->is_model_part()) continue;
|
if (!mv->is_model_part()) continue;
|
||||||
|
|||||||
@@ -23,21 +23,19 @@ public:
|
|||||||
// Create a strategy if belt_printer is enabled; returns nullptr otherwise.
|
// Create a strategy if belt_printer is enabled; returns nullptr otherwise.
|
||||||
static std::unique_ptr<BeltSliceStrategy> create(const PrintConfig &config);
|
static std::unique_ptr<BeltSliceStrategy> create(const PrintConfig &config);
|
||||||
|
|
||||||
// Apply belt transforms to the slicing trafo.
|
// Apply belt-specific transforms (shear + scale + z-shift) to the slicing trafo.
|
||||||
// Modifies trafo in-place: trafo = z_shift * scale * shear * pre_remap * trafo
|
// Pre-slice remap is handled separately (standalone feature).
|
||||||
// Scans all model_part volumes to detect minimum Z and add z-shift if needed.
|
// has_remap: whether pre-slice remap was already applied (affects z-shift detection).
|
||||||
// Sets *out_belt_min_z to the minimum Z of the mesh after transforms.
|
|
||||||
void apply_to_trafo(Transform3d &trafo,
|
void apply_to_trafo(Transform3d &trafo,
|
||||||
const ModelVolumePtrs &model_volumes,
|
const ModelVolumePtrs &model_volumes,
|
||||||
|
bool has_remap,
|
||||||
double *out_belt_min_z) const;
|
double *out_belt_min_z) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit BeltSliceStrategy(const PrintConfig &config);
|
explicit BeltSliceStrategy(const PrintConfig &config);
|
||||||
|
|
||||||
bool m_has_remap = false;
|
|
||||||
bool m_has_shear = false;
|
bool m_has_shear = false;
|
||||||
bool m_has_scale = false;
|
bool m_has_scale = false;
|
||||||
Transform3d m_pre_remap = Transform3d::Identity();
|
|
||||||
Matrix3d m_shear = Matrix3d::Identity();
|
Matrix3d m_shear = Matrix3d::Identity();
|
||||||
Matrix3d m_scale = Matrix3d::Identity();
|
Matrix3d m_scale = Matrix3d::Identity();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ Transform3d BeltTransformPipeline::build_preslice_remap(const PrintConfig &confi
|
|||||||
if (!has_preslice_remap(config))
|
if (!has_preslice_remap(config))
|
||||||
return pre_remap;
|
return pre_remap;
|
||||||
|
|
||||||
int pre_rx = int(config.belt_preslice_remap_x.value);
|
int pre_rx = int(config.preslice_remap_x.value);
|
||||||
int pre_ry = int(config.belt_preslice_remap_y.value);
|
int pre_ry = int(config.preslice_remap_y.value);
|
||||||
int pre_rz = int(config.belt_preslice_remap_z.value);
|
int pre_rz = int(config.preslice_remap_z.value);
|
||||||
|
|
||||||
// Each remap value selects a source axis and sign.
|
// Each remap value selects a source axis and sign.
|
||||||
auto remap_column = [](int r) -> Vec3d {
|
auto remap_column = [](int r) -> Vec3d {
|
||||||
@@ -114,13 +114,13 @@ Transform3d BeltTransformPipeline::build_forward_transform(const PrintConfig &co
|
|||||||
|
|
||||||
BoundingBoxf3 BeltTransformPipeline::remap_bbox(const BoundingBoxf3 &bb, const PrintConfig &config)
|
BoundingBoxf3 BeltTransformPipeline::remap_bbox(const BoundingBoxf3 &bb, const PrintConfig &config)
|
||||||
{
|
{
|
||||||
int pre_rx = int(config.belt_preslice_remap_x.value);
|
int pre_rx = int(config.preslice_remap_x.value);
|
||||||
int pre_ry = int(config.belt_preslice_remap_y.value);
|
int pre_ry = int(config.preslice_remap_y.value);
|
||||||
int pre_rz = int(config.belt_preslice_remap_z.value);
|
int pre_rz = int(config.preslice_remap_z.value);
|
||||||
|
|
||||||
if (pre_rx == int(BeltRemapAxis::PosX) &&
|
if (pre_rx == int(RemapAxis::PosX) &&
|
||||||
pre_ry == int(BeltRemapAxis::PosY) &&
|
pre_ry == int(RemapAxis::PosY) &&
|
||||||
pre_rz == int(BeltRemapAxis::PosZ))
|
pre_rz == int(RemapAxis::PosZ))
|
||||||
return bb; // Identity remap.
|
return bb; // Identity remap.
|
||||||
|
|
||||||
auto remap_coord = [](int r, const Vec3d &v) -> double {
|
auto remap_coord = [](int r, const Vec3d &v) -> double {
|
||||||
|
|||||||
@@ -58,21 +58,21 @@ public:
|
|||||||
|
|
||||||
static bool has_preslice_remap(const PrintConfig &config)
|
static bool has_preslice_remap(const PrintConfig &config)
|
||||||
{
|
{
|
||||||
return int(config.belt_preslice_remap_x.value) != int(BeltRemapAxis::PosX) ||
|
return int(config.preslice_remap_x.value) != int(RemapAxis::PosX) ||
|
||||||
int(config.belt_preslice_remap_y.value) != int(BeltRemapAxis::PosY) ||
|
int(config.preslice_remap_y.value) != int(RemapAxis::PosY) ||
|
||||||
int(config.belt_preslice_remap_z.value) != int(BeltRemapAxis::PosZ);
|
int(config.preslice_remap_z.value) != int(RemapAxis::PosZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload accepting DynamicPrintConfig (used in static slicing_parameters).
|
// Overload accepting DynamicPrintConfig (used in static slicing_parameters).
|
||||||
static bool has_preslice_remap(const DynamicPrintConfig &config)
|
static bool has_preslice_remap(const DynamicPrintConfig &config)
|
||||||
{
|
{
|
||||||
auto get_int = [&](const char *key) -> int {
|
auto get_int = [&](const char *key) -> int {
|
||||||
auto *opt = config.option<ConfigOptionEnum<BeltRemapAxis>>(key);
|
auto *opt = config.option<ConfigOptionEnum<RemapAxis>>(key);
|
||||||
return opt ? int(opt->value) : 0;
|
return opt ? int(opt->value) : 0;
|
||||||
};
|
};
|
||||||
return get_int("belt_preslice_remap_x") != int(BeltRemapAxis::PosX) ||
|
return get_int("preslice_remap_x") != int(RemapAxis::PosX) ||
|
||||||
get_int("belt_preslice_remap_y") != int(BeltRemapAxis::PosY) ||
|
get_int("preslice_remap_y") != int(RemapAxis::PosY) ||
|
||||||
get_int("belt_preslice_remap_z") != int(BeltRemapAxis::PosZ);
|
get_int("preslice_remap_z") != int(RemapAxis::PosZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_shear(const PrintConfig &config)
|
static bool has_shear(const PrintConfig &config)
|
||||||
|
|||||||
@@ -2425,6 +2425,19 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
// Belt printer: initialize belt-specific writer via virtual hook.
|
// Belt printer: initialize belt-specific writer via virtual hook.
|
||||||
this->init_belt_writer(print, is_bbl_printers);
|
this->init_belt_writer(print, is_bbl_printers);
|
||||||
|
|
||||||
|
// Standalone axis remap (works with or without belt mode).
|
||||||
|
{
|
||||||
|
int rx = int(print.config().gcode_remap_x.value);
|
||||||
|
int ry = int(print.config().gcode_remap_y.value);
|
||||||
|
int rz = int(print.config().gcode_remap_z.value);
|
||||||
|
if (rx != 0 || ry != 1 || rz != 2) {
|
||||||
|
m_writer->set_axis_remap(rx, ry, rz);
|
||||||
|
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?
|
// How many times will be change_layer() called?
|
||||||
// change_layer() in turn increments the progress bar status.
|
// change_layer() in turn increments the progress bar status.
|
||||||
m_layer_count = 0;
|
m_layer_count = 0;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ bool BeltBackTransform::init_from_config(const PrintConfig &config)
|
|||||||
m_active = false;
|
m_active = false;
|
||||||
m_inverse = Transform3d::Identity();
|
m_inverse = Transform3d::Identity();
|
||||||
|
|
||||||
if (!config.belt_printer.value || !config.belt_gcode_back_transform.value)
|
if (!config.belt_printer.value || !config.gcode_back_transform.value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Require at least one active transform to proceed.
|
// Require at least one active transform to proceed.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Slic3r {
|
|||||||
// Initialized once from PrintConfig, then applied per-point in
|
// Initialized once from PrintConfig, then applied per-point in
|
||||||
// GCodeWriter::to_machine_coords() before axis remapping.
|
// GCodeWriter::to_machine_coords() before axis remapping.
|
||||||
//
|
//
|
||||||
// Active when belt_gcode_back_transform is true AND at least one of:
|
// Active when gcode_back_transform is true AND at least one of:
|
||||||
// - a shear axis has global mode enabled, or
|
// - a shear axis has global mode enabled, or
|
||||||
// - a pre-slice axis remap is non-identity.
|
// - a pre-slice axis remap is non-identity.
|
||||||
class BeltBackTransform
|
class BeltBackTransform
|
||||||
|
|||||||
@@ -3129,26 +3129,26 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
|
|||||||
try { m_result.belt_scale_z_angle = std::stof(std::string(comment.substr(22))); } catch (...) {} return;
|
try { m_result.belt_scale_z_angle = std::stof(std::string(comment.substr(22))); } catch (...) {} return;
|
||||||
}
|
}
|
||||||
// Pre-slice axis remap
|
// Pre-slice axis remap
|
||||||
auto parse_remap_axis = [](const std::string &s) -> BeltRemapAxis {
|
auto parse_remap_axis = [](const std::string &s) -> RemapAxis {
|
||||||
if (s == "pos_x") return BeltRemapAxis::PosX;
|
if (s == "pos_x") return RemapAxis::PosX;
|
||||||
if (s == "pos_y") return BeltRemapAxis::PosY;
|
if (s == "pos_y") return RemapAxis::PosY;
|
||||||
if (s == "pos_z") return BeltRemapAxis::PosZ;
|
if (s == "pos_z") return RemapAxis::PosZ;
|
||||||
if (s == "neg_x") return BeltRemapAxis::NegX;
|
if (s == "neg_x") return RemapAxis::NegX;
|
||||||
if (s == "neg_y") return BeltRemapAxis::NegY;
|
if (s == "neg_y") return RemapAxis::NegY;
|
||||||
if (s == "neg_z") return BeltRemapAxis::NegZ;
|
if (s == "neg_z") return RemapAxis::NegZ;
|
||||||
if (s == "rev_x") return BeltRemapAxis::RevX;
|
if (s == "rev_x") return RemapAxis::RevX;
|
||||||
if (s == "rev_y") return BeltRemapAxis::RevY;
|
if (s == "rev_y") return RemapAxis::RevY;
|
||||||
if (s == "rev_z") return BeltRemapAxis::RevZ;
|
if (s == "rev_z") return RemapAxis::RevZ;
|
||||||
return BeltRemapAxis::PosX;
|
return RemapAxis::PosX;
|
||||||
};
|
};
|
||||||
if (boost::starts_with(comment, " belt_preslice_remap_x = ")) {
|
if (boost::starts_with(comment, " preslice_remap_x = ")) {
|
||||||
m_result.belt_preslice_remap_x = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
m_result.preslice_remap_x = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
||||||
}
|
}
|
||||||
if (boost::starts_with(comment, " belt_preslice_remap_y = ")) {
|
if (boost::starts_with(comment, " preslice_remap_y = ")) {
|
||||||
m_result.belt_preslice_remap_y = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
m_result.preslice_remap_y = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
||||||
}
|
}
|
||||||
if (boost::starts_with(comment, " belt_preslice_remap_z = ")) {
|
if (boost::starts_with(comment, " preslice_remap_z = ")) {
|
||||||
m_result.belt_preslice_remap_z = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
m_result.preslice_remap_z = parse_remap_axis(trim(std::string(comment.substr(25)))); return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// wipe start tag
|
// wipe start tag
|
||||||
|
|||||||
@@ -246,9 +246,9 @@ class Print;
|
|||||||
float belt_scale_y_angle{ 45.f };
|
float belt_scale_y_angle{ 45.f };
|
||||||
BeltScaleMode belt_scale_z{ BeltScaleMode::None };
|
BeltScaleMode belt_scale_z{ BeltScaleMode::None };
|
||||||
float belt_scale_z_angle{ 45.f };
|
float belt_scale_z_angle{ 45.f };
|
||||||
BeltRemapAxis belt_preslice_remap_x{ BeltRemapAxis::PosX };
|
RemapAxis preslice_remap_x{ RemapAxis::PosX };
|
||||||
BeltRemapAxis belt_preslice_remap_y{ BeltRemapAxis::PosY };
|
RemapAxis preslice_remap_y{ RemapAxis::PosY };
|
||||||
BeltRemapAxis belt_preslice_remap_z{ BeltRemapAxis::PosZ };
|
RemapAxis preslice_remap_z{ RemapAxis::PosZ };
|
||||||
SettingsIds settings_ids;
|
SettingsIds settings_ids;
|
||||||
size_t filaments_count;
|
size_t filaments_count;
|
||||||
bool backtrace_enabled;
|
bool backtrace_enabled;
|
||||||
@@ -324,9 +324,9 @@ class Print;
|
|||||||
belt_scale_y_angle = other.belt_scale_y_angle;
|
belt_scale_y_angle = other.belt_scale_y_angle;
|
||||||
belt_scale_z = other.belt_scale_z;
|
belt_scale_z = other.belt_scale_z;
|
||||||
belt_scale_z_angle = other.belt_scale_z_angle;
|
belt_scale_z_angle = other.belt_scale_z_angle;
|
||||||
belt_preslice_remap_x = other.belt_preslice_remap_x;
|
preslice_remap_x = other.preslice_remap_x;
|
||||||
belt_preslice_remap_y = other.belt_preslice_remap_y;
|
preslice_remap_y = other.preslice_remap_y;
|
||||||
belt_preslice_remap_z = other.belt_preslice_remap_z;
|
preslice_remap_z = other.preslice_remap_z;
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
time = other.time;
|
time = other.time;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,6 +20,36 @@ namespace Slic3r {
|
|||||||
|
|
||||||
bool GCodeWriter::full_gcode_comment = true;
|
bool GCodeWriter::full_gcode_comment = true;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GCodeWriter::has_axis_remap() const
|
||||||
|
{
|
||||||
|
return m_remap_x != 0 || m_remap_y != 1 || m_remap_z != 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3d GCodeWriter::apply_axis_remap(const Vec3d &pos) const
|
||||||
|
{
|
||||||
|
if (!has_axis_remap())
|
||||||
|
return pos;
|
||||||
|
auto remap = [this, &pos](int r) -> double {
|
||||||
|
int axis = r % 3;
|
||||||
|
if (r < 3) return pos[axis];
|
||||||
|
if (r < 6) return -pos[axis];
|
||||||
|
return m_build_vol_max[axis] - pos[axis];
|
||||||
|
};
|
||||||
|
return { remap(m_remap_x), remap(m_remap_y), remap(m_remap_z) };
|
||||||
|
}
|
||||||
|
|
||||||
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
||||||
{
|
{
|
||||||
return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
|
return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
|
||||||
@@ -562,7 +592,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 };
|
Vec2d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset };
|
||||||
|
|
||||||
GCodeG1Formatter w;
|
GCodeG1Formatter w;
|
||||||
w.emit_xy(point_on_plate);
|
if (has_axis_remap()) {
|
||||||
|
// Axis remap may couple XY with Z; emit full XYZ in machine coordinates.
|
||||||
|
Vec3d machine = apply_axis_remap(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
|
auto speed = m_is_first_layer
|
||||||
? this->config.get_abs_value("initial_layer_travel_speed") : this->config.travel_speed.value;
|
? this->config.get_abs_value("initial_layer_travel_speed") : this->config.travel_speed.value;
|
||||||
w.emit_f(speed * 60.0);
|
w.emit_f(speed * 60.0);
|
||||||
@@ -794,7 +830,13 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GCodeG1Formatter w;
|
GCodeG1Formatter w;
|
||||||
w.emit_z(z);
|
if (has_axis_remap()) {
|
||||||
|
// Remap may couple Z with other axes; emit full XYZ.
|
||||||
|
Vec3d machine = apply_axis_remap(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);
|
w.emit_f(speed * 60.0);
|
||||||
//BBS
|
//BBS
|
||||||
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
w.emit_comment(GCodeWriter::full_gcode_comment, comment);
|
||||||
@@ -899,7 +941,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 };
|
Vec2d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset };
|
||||||
|
|
||||||
GCodeG1Formatter w;
|
GCodeG1Formatter w;
|
||||||
w.emit_xy(point_on_plate);
|
if (has_axis_remap()) {
|
||||||
|
Vec3d machine = apply_axis_remap(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)
|
if (!force_no_extrusion)
|
||||||
w.emit_e(filament()->E());
|
w.emit_e(filament()->E());
|
||||||
//BBS
|
//BBS
|
||||||
@@ -939,6 +986,9 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
|
|||||||
//BBS: take plate offset into consider
|
//BBS: take plate offset into consider
|
||||||
Vec3d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset, point(2) };
|
Vec3d point_on_plate = { point(0) - m_x_offset, point(1) - m_y_offset, point(2) };
|
||||||
|
|
||||||
|
if (has_axis_remap())
|
||||||
|
point_on_plate = apply_axis_remap(point_on_plate);
|
||||||
|
|
||||||
GCodeG1Formatter w;
|
GCodeG1Formatter w;
|
||||||
w.emit_xyz(point_on_plate);
|
w.emit_xyz(point_on_plate);
|
||||||
if (!force_no_extrusion)
|
if (!force_no_extrusion)
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ public:
|
|||||||
void set_is_first_layer(bool bval) { m_is_first_layer = bval; }
|
void set_is_first_layer(bool bval) { m_is_first_layer = bval; }
|
||||||
GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; }
|
GCodeFlavor get_gcode_flavor() const { return config.gcode_flavor; }
|
||||||
|
|
||||||
|
// Axis remap: permute/negate/reverse axes in G-code output.
|
||||||
|
// Works standalone (without belt mode) for printers with non-standard axis conventions.
|
||||||
|
void set_axis_remap(int rx, int ry, int rz);
|
||||||
|
void set_build_volume_max(const Vec3d &max);
|
||||||
|
bool has_axis_remap() const;
|
||||||
|
|
||||||
// Returns whether this flavor supports separate print and travel acceleration.
|
// Returns whether this flavor supports separate print and travel acceleration.
|
||||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||||
protected:
|
protected:
|
||||||
@@ -141,6 +147,15 @@ protected:
|
|||||||
|
|
||||||
virtual std::string _travel_to_z(double z, const std::string &comment);
|
virtual std::string _travel_to_z(double z, const std::string &comment);
|
||||||
|
|
||||||
|
// Axis remap state — accessible to subclasses.
|
||||||
|
int m_remap_x = 0; // RemapAxis: 0=+X, 1=+Y, 2=+Z, 3=-X, etc.
|
||||||
|
int m_remap_y = 1;
|
||||||
|
int m_remap_z = 2;
|
||||||
|
Vec3d m_build_vol_max = Vec3d::Zero();
|
||||||
|
|
||||||
|
// Apply axis remap to a point. Returns pos unchanged if remap is identity.
|
||||||
|
Vec3d apply_axis_remap(const Vec3d &pos) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Extruders are sorted by their ID, so that binary search is possible.
|
// Extruders are sorted by their ID, so that binary search is possible.
|
||||||
std::vector<Extruder> m_filament_extruders;
|
std::vector<Extruder> m_filament_extruders;
|
||||||
|
|||||||
@@ -1014,8 +1014,8 @@ static std::vector<std::string> s_Preset_printer_options {
|
|||||||
"belt_shear_y", "belt_shear_y_angle", "belt_shear_y_from", "belt_shear_y_global",
|
"belt_shear_y", "belt_shear_y_angle", "belt_shear_y_from", "belt_shear_y_global",
|
||||||
"belt_shear_z", "belt_shear_z_angle", "belt_shear_z_from", "belt_shear_z_global",
|
"belt_shear_z", "belt_shear_z_angle", "belt_shear_z_from", "belt_shear_z_global",
|
||||||
"belt_scale_x", "belt_scale_x_angle", "belt_scale_y", "belt_scale_y_angle", "belt_scale_z", "belt_scale_z_angle",
|
"belt_scale_x", "belt_scale_x_angle", "belt_scale_y", "belt_scale_y_angle", "belt_scale_z", "belt_scale_z_angle",
|
||||||
"belt_preslice_remap_x", "belt_preslice_remap_y", "belt_preslice_remap_z",
|
"preslice_remap_x", "preslice_remap_y", "preslice_remap_z",
|
||||||
"belt_gcode_remap_x", "belt_gcode_remap_y", "belt_gcode_remap_z", "belt_gcode_back_transform",
|
"gcode_remap_x", "gcode_remap_y", "gcode_remap_z", "gcode_back_transform",
|
||||||
"belt_origin_snap_x", "belt_origin_offset_x",
|
"belt_origin_snap_x", "belt_origin_offset_x",
|
||||||
"belt_origin_snap_y", "belt_origin_offset_y",
|
"belt_origin_snap_y", "belt_origin_offset_y",
|
||||||
"belt_origin_snap_z", "belt_origin_offset_z",
|
"belt_origin_snap_z", "belt_origin_offset_z",
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
// or they are only notes not influencing the generated G-code.
|
// or they are only notes not influencing the generated G-code.
|
||||||
static std::unordered_set<std::string> steps_gcode = {
|
static std::unordered_set<std::string> steps_gcode = {
|
||||||
// Belt printer G-code axis remap (only affects G-code output, not slicing).
|
// Belt printer G-code axis remap (only affects G-code output, not slicing).
|
||||||
"belt_gcode_remap_x",
|
"gcode_remap_x",
|
||||||
"belt_gcode_remap_y",
|
"gcode_remap_y",
|
||||||
"belt_gcode_remap_z",
|
"gcode_remap_z",
|
||||||
"belt_origin_snap_x", "belt_origin_offset_x",
|
"belt_origin_snap_x", "belt_origin_offset_x",
|
||||||
"belt_origin_snap_y", "belt_origin_offset_y",
|
"belt_origin_snap_y", "belt_origin_offset_y",
|
||||||
"belt_origin_snap_z", "belt_origin_offset_z",
|
"belt_origin_snap_z", "belt_origin_offset_z",
|
||||||
@@ -308,9 +308,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
|| opt_key == "belt_scale_y_angle"
|
|| opt_key == "belt_scale_y_angle"
|
||||||
|| opt_key == "belt_scale_z"
|
|| opt_key == "belt_scale_z"
|
||||||
|| opt_key == "belt_scale_z_angle"
|
|| opt_key == "belt_scale_z_angle"
|
||||||
|| opt_key == "belt_preslice_remap_x"
|
|| opt_key == "preslice_remap_x"
|
||||||
|| opt_key == "belt_preslice_remap_y"
|
|| opt_key == "preslice_remap_y"
|
||||||
|| opt_key == "belt_preslice_remap_z") {
|
|| opt_key == "preslice_remap_z") {
|
||||||
osteps.emplace_back(posSlice);
|
osteps.emplace_back(posSlice);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "belt_support_floor_offset"
|
opt_key == "belt_support_floor_offset"
|
||||||
|
|||||||
@@ -313,18 +313,18 @@ static t_config_enum_values s_keys_map_BeltScaleMode {
|
|||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltScaleMode)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltScaleMode)
|
||||||
|
|
||||||
static t_config_enum_values s_keys_map_BeltRemapAxis {
|
static t_config_enum_values s_keys_map_RemapAxis {
|
||||||
{ "pos_x", int(BeltRemapAxis::PosX) },
|
{ "pos_x", int(RemapAxis::PosX) },
|
||||||
{ "pos_y", int(BeltRemapAxis::PosY) },
|
{ "pos_y", int(RemapAxis::PosY) },
|
||||||
{ "pos_z", int(BeltRemapAxis::PosZ) },
|
{ "pos_z", int(RemapAxis::PosZ) },
|
||||||
{ "neg_x", int(BeltRemapAxis::NegX) },
|
{ "neg_x", int(RemapAxis::NegX) },
|
||||||
{ "neg_y", int(BeltRemapAxis::NegY) },
|
{ "neg_y", int(RemapAxis::NegY) },
|
||||||
{ "neg_z", int(BeltRemapAxis::NegZ) },
|
{ "neg_z", int(RemapAxis::NegZ) },
|
||||||
{ "rev_x", int(BeltRemapAxis::RevX) },
|
{ "rev_x", int(RemapAxis::RevX) },
|
||||||
{ "rev_y", int(BeltRemapAxis::RevY) },
|
{ "rev_y", int(RemapAxis::RevY) },
|
||||||
{ "rev_z", int(BeltRemapAxis::RevZ) },
|
{ "rev_z", int(RemapAxis::RevZ) },
|
||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BeltRemapAxis)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(RemapAxis)
|
||||||
|
|
||||||
static t_config_enum_values s_keys_map_BeltSupportFloorMode {
|
static t_config_enum_values s_keys_map_BeltSupportFloorMode {
|
||||||
{ "none", int(BeltSupportFloorMode::None) },
|
{ "none", int(BeltSupportFloorMode::None) },
|
||||||
@@ -6124,49 +6124,49 @@ void PrintConfigDef::init_fff_params()
|
|||||||
add_belt_scale_angle("belt_scale_z_angle", "Angle");
|
add_belt_scale_angle("belt_scale_z_angle", "Angle");
|
||||||
|
|
||||||
// G-code axis remap with sign
|
// G-code axis remap with sign
|
||||||
auto add_belt_remap = [this](const char *key, const char *label, const char *tooltip, BeltRemapAxis default_axis) {
|
auto add_belt_remap = [this](const char *key, const char *label, const char *tooltip, RemapAxis default_axis) {
|
||||||
auto def = this->add(key, coEnum);
|
auto def = this->add(key, coEnum);
|
||||||
def->label = L(label);
|
def->label = L(label);
|
||||||
def->category = L("Printable space");
|
def->category = L("Printable space");
|
||||||
def->tooltip = L(tooltip);
|
def->tooltip = L(tooltip);
|
||||||
def->enum_keys_map = &ConfigOptionEnum<BeltRemapAxis>::get_enum_values();
|
def->enum_keys_map = &ConfigOptionEnum<RemapAxis>::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_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->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->mode = comSimple; // Visibility controlled by toggle_line in Tab.cpp
|
||||||
def->set_default_value(new ConfigOptionEnum<BeltRemapAxis>(default_axis));
|
def->set_default_value(new ConfigOptionEnum<RemapAxis>(default_axis));
|
||||||
};
|
};
|
||||||
|
|
||||||
add_belt_remap("belt_preslice_remap_x", "X",
|
add_belt_remap("preslice_remap_x", "X",
|
||||||
"Before slicing, which model-space axis becomes the slicer's X axis. "
|
"Before slicing, which model-space axis becomes the slicer's X axis. "
|
||||||
"Use this to re-orient the coordinate system so the slicer's XY plane matches "
|
"Use this to re-orient the coordinate system so the slicer's XY plane matches "
|
||||||
"your belt printer's physical bed plane. For a printer whose bed is in the XZ plane, "
|
"your belt printer's physical bed plane. For a printer whose bed is in the XZ plane, "
|
||||||
"set Y to +Z and Z to +Y (or -Y) to swap the vertical and belt-travel axes. "
|
"set Y to +Z and Z to +Y (or -Y) to swap the vertical and belt-travel axes. "
|
||||||
"Default +X: no change.",
|
"Default +X: no change.",
|
||||||
BeltRemapAxis::PosX);
|
RemapAxis::PosX);
|
||||||
add_belt_remap("belt_preslice_remap_y", "Y",
|
add_belt_remap("preslice_remap_y", "Y",
|
||||||
"Before slicing, which model-space axis becomes the slicer's Y axis. "
|
"Before slicing, which model-space axis becomes the slicer's Y axis. "
|
||||||
"The slicer treats Y as one of the two horizontal bed axes. If your physical "
|
"The slicer treats Y as one of the two horizontal bed axes. If your physical "
|
||||||
"belt surface runs along the Z axis, map Y to +Z here so the slicer slices "
|
"belt surface runs along the Z axis, map Y to +Z here so the slicer slices "
|
||||||
"along the correct plane. Default +Y: no change.",
|
"along the correct plane. Default +Y: no change.",
|
||||||
BeltRemapAxis::PosY);
|
RemapAxis::PosY);
|
||||||
add_belt_remap("belt_preslice_remap_z", "Z",
|
add_belt_remap("preslice_remap_z", "Z",
|
||||||
"Before slicing, which model-space axis becomes the slicer's Z axis (layer stacking direction). "
|
"Before slicing, which model-space axis becomes the slicer's Z axis (layer stacking direction). "
|
||||||
"The slicer builds layers upward along this axis. If your printer's layer-stacking "
|
"The slicer builds layers upward along this axis. If your printer's layer-stacking "
|
||||||
"direction is the physical Y axis, map Z to +Y (or -Y for inverted direction). "
|
"direction is the physical Y axis, map Z to +Y (or -Y for inverted direction). "
|
||||||
"Rev mode mirrors relative to the build volume maximum. Default +Z: no change.",
|
"Rev mode mirrors relative to the build volume maximum. Default +Z: no change.",
|
||||||
BeltRemapAxis::PosZ);
|
RemapAxis::PosZ);
|
||||||
|
|
||||||
add_belt_remap("belt_gcode_remap_x", "X", "Which slicing axis maps to machine X in G-code output. Applied AFTER slicing, during G-code generation.", BeltRemapAxis::PosX);
|
add_belt_remap("gcode_remap_x", "X", "Which slicing axis maps to machine X in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosX);
|
||||||
add_belt_remap("belt_gcode_remap_y", "Y", "Which slicing axis maps to machine Y in G-code output. Applied AFTER slicing, during G-code generation.", BeltRemapAxis::PosY);
|
add_belt_remap("gcode_remap_y", "Y", "Which slicing axis maps to machine Y in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosY);
|
||||||
add_belt_remap("belt_gcode_remap_z", "Z", "Which slicing axis maps to machine Z in G-code output. Applied AFTER slicing, during G-code generation.", BeltRemapAxis::PosZ);
|
add_belt_remap("gcode_remap_z", "Z", "Which slicing axis maps to machine Z in G-code output. Applied AFTER slicing, during G-code generation.", RemapAxis::PosZ);
|
||||||
|
|
||||||
def = this->add("belt_gcode_back_transform", coBool);
|
def = this->add("gcode_back_transform", coBool);
|
||||||
def->label = L("G-code back-transform");
|
def->label = L("G-code back-transform");
|
||||||
def->category = L("Printable space");
|
def->category = L("Printable space");
|
||||||
def->tooltip = L("Reverse the shear/scale transform applied during slicing so G-code "
|
def->tooltip = L("Reverse the shear/scale transform applied during slicing so G-code "
|
||||||
"coordinates are in the machine's physical coordinate space. "
|
"coordinates are in the machine's physical coordinate space. "
|
||||||
"Requires at least one shear axis with global mode enabled.");
|
"Requires at least one shear axis with global mode enabled.");
|
||||||
def->mode = comAdvanced;
|
def->mode = comSimple; // Visibility controlled by toggle_line in Tab.cpp
|
||||||
def->set_default_value(new ConfigOptionBool(false));
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
auto add_belt_origin_snap = [this](const char *key_snap, const char *key_offset,
|
auto add_belt_origin_snap = [this](const char *key_snap, const char *key_offset,
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ enum class BeltAxis
|
|||||||
Z = 2,
|
Z = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BeltRemapAxis
|
enum class RemapAxis
|
||||||
{
|
{
|
||||||
PosX = 0, PosY = 1, PosZ = 2,
|
PosX = 0, PosY = 1, PosZ = 2,
|
||||||
NegX = 3, NegY = 4, NegZ = 5,
|
NegX = 3, NegY = 4, NegZ = 5,
|
||||||
@@ -549,7 +549,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode)
|
|||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltShearMode)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltShearMode)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltScaleMode)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltScaleMode)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltAxis)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltAxis)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltRemapAxis)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(RemapAxis)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportFloorMode)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportFloorMode)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportZOffsetMode)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BeltSupportZOffsetMode)
|
||||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
|
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SupportMaterialPattern)
|
||||||
@@ -1487,13 +1487,13 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
((ConfigOptionFloat, belt_scale_y_angle))
|
((ConfigOptionFloat, belt_scale_y_angle))
|
||||||
((ConfigOptionEnum<BeltScaleMode>, belt_scale_z))
|
((ConfigOptionEnum<BeltScaleMode>, belt_scale_z))
|
||||||
((ConfigOptionFloat, belt_scale_z_angle))
|
((ConfigOptionFloat, belt_scale_z_angle))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_preslice_remap_x))
|
((ConfigOptionEnum<RemapAxis>, preslice_remap_x))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_preslice_remap_y))
|
((ConfigOptionEnum<RemapAxis>, preslice_remap_y))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_preslice_remap_z))
|
((ConfigOptionEnum<RemapAxis>, preslice_remap_z))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_x))
|
((ConfigOptionEnum<RemapAxis>, gcode_remap_x))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_y))
|
((ConfigOptionEnum<RemapAxis>, gcode_remap_y))
|
||||||
((ConfigOptionEnum<BeltRemapAxis>, belt_gcode_remap_z))
|
((ConfigOptionEnum<RemapAxis>, gcode_remap_z))
|
||||||
((ConfigOptionBool, belt_gcode_back_transform))
|
((ConfigOptionBool, gcode_back_transform))
|
||||||
((ConfigOptionBool, belt_origin_snap_x))
|
((ConfigOptionBool, belt_origin_snap_x))
|
||||||
((ConfigOptionFloat, belt_origin_offset_x))
|
((ConfigOptionFloat, belt_origin_offset_x))
|
||||||
((ConfigOptionBool, belt_origin_snap_y))
|
((ConfigOptionBool, belt_origin_snap_y))
|
||||||
|
|||||||
@@ -144,11 +144,31 @@ static std::vector<VolumeSlices> slice_volumes_inner(
|
|||||||
params_base.closing_radius = print_object_config.slice_closing_radius.value;
|
params_base.closing_radius = print_object_config.slice_closing_radius.value;
|
||||||
params_base.extra_offset = 0;
|
params_base.extra_offset = 0;
|
||||||
params_base.trafo = object_trafo;
|
params_base.trafo = object_trafo;
|
||||||
|
// Standalone pre-slice axis remap (works without belt mode).
|
||||||
|
bool has_remap = BeltTransformPipeline::has_preslice_remap(print_config);
|
||||||
|
if (has_remap)
|
||||||
|
params_base.trafo = BeltTransformPipeline::build_preslice_remap(print_config) * params_base.trafo;
|
||||||
{
|
{
|
||||||
// Belt printer: apply pre-slice transforms (remap, shear, scale, z-shift) via strategy.
|
// Belt-specific transforms (shear, scale, z-shift) via strategy.
|
||||||
auto belt_strategy = BeltSliceStrategy::create(print_config);
|
auto belt_strategy = BeltSliceStrategy::create(print_config);
|
||||||
if (belt_strategy)
|
if (belt_strategy)
|
||||||
belt_strategy->apply_to_trafo(params_base.trafo, model_volumes, out_belt_min_z);
|
belt_strategy->apply_to_trafo(params_base.trafo, model_volumes, has_remap, out_belt_min_z);
|
||||||
|
}
|
||||||
|
// If only remap (no belt), still need z-shift detection.
|
||||||
|
if (has_remap && !print_config.belt_printer.value) {
|
||||||
|
double min_z = std::numeric_limits<double>::max();
|
||||||
|
for (const ModelVolume *mv : model_volumes) {
|
||||||
|
if (!mv->is_model_part()) continue;
|
||||||
|
for (const stl_vertex &v : mv->mesh().its.vertices) {
|
||||||
|
Vec3d pt = params_base.trafo * v.cast<double>();
|
||||||
|
min_z = std::min(min_z, pt.z());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min_z < 0. && min_z != std::numeric_limits<double>::max()) {
|
||||||
|
Transform3d z_shift = Transform3d::Identity();
|
||||||
|
z_shift.matrix()(2, 3) = -min_z;
|
||||||
|
params_base.trafo = z_shift * 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.
|
||||||
|
|||||||
+12
-9
@@ -4436,19 +4436,19 @@ void TabPrinter::build_fff()
|
|||||||
L("Remap model axes before slicing so the slicer's coordinate system matches "
|
L("Remap model axes before slicing so the slicer's coordinate system matches "
|
||||||
"the physical bed orientation. For belt printers whose bed is NOT in the XY plane, "
|
"the physical bed orientation. For belt printers whose bed is NOT in the XY plane, "
|
||||||
"use this to swap axes so layers are stacked in the correct physical direction.") };
|
"use this to swap axes so layers are stacked in the correct physical direction.") };
|
||||||
line.append_option(optgroup->get_option("belt_preslice_remap_x"));
|
line.append_option(optgroup->get_option("preslice_remap_x"));
|
||||||
line.append_option(optgroup->get_option("belt_preslice_remap_y"));
|
line.append_option(optgroup->get_option("preslice_remap_y"));
|
||||||
line.append_option(optgroup->get_option("belt_preslice_remap_z"));
|
line.append_option(optgroup->get_option("preslice_remap_z"));
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Line line = { L("G-code axis remap (post-slice)"), L("Remap slicing-frame axes to machine axes in G-code output. Applied AFTER slicing, during G-code generation.") };
|
Line line = { L("G-code axis remap (post-slice)"), L("Remap slicing-frame axes to machine axes in G-code output. Applied AFTER slicing, during G-code generation.") };
|
||||||
line.append_option(optgroup->get_option("belt_gcode_remap_x"));
|
line.append_option(optgroup->get_option("gcode_remap_x"));
|
||||||
line.append_option(optgroup->get_option("belt_gcode_remap_y"));
|
line.append_option(optgroup->get_option("gcode_remap_y"));
|
||||||
line.append_option(optgroup->get_option("belt_gcode_remap_z"));
|
line.append_option(optgroup->get_option("gcode_remap_z"));
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
}
|
}
|
||||||
optgroup->append_single_option_line("belt_gcode_back_transform");
|
optgroup->append_single_option_line("gcode_back_transform");
|
||||||
{
|
{
|
||||||
Line line = { L("Origin snap X"), L("Snap object bbox min X to offset in G-code output") };
|
Line line = { L("Origin snap X"), L("Snap object bbox min X to offset in G-code output") };
|
||||||
line.append_option(optgroup->get_option("belt_origin_snap_x"));
|
line.append_option(optgroup->get_option("belt_origin_snap_x"));
|
||||||
@@ -5321,11 +5321,14 @@ void TabPrinter::toggle_options()
|
|||||||
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",
|
for (auto el : {"belt_shear_x", "belt_shear_y", "belt_shear_z",
|
||||||
"belt_scale_x", "belt_scale_y", "belt_scale_z",
|
"belt_scale_x", "belt_scale_y", "belt_scale_z",
|
||||||
"belt_preslice_remap_x",
|
|
||||||
"belt_gcode_remap_x", "belt_gcode_back_transform",
|
|
||||||
"belt_origin_snap_x", "belt_origin_snap_y", "belt_origin_snap_z"})
|
"belt_origin_snap_x", "belt_origin_snap_y", "belt_origin_snap_z"})
|
||||||
toggle_line(el, is_belt);
|
toggle_line(el, is_belt);
|
||||||
|
|
||||||
|
// Remap options: visible when belt mode is on OR when UI is in developer mode.
|
||||||
|
bool show_remap = is_belt || (m_mode >= comDevelop);
|
||||||
|
for (auto el : {"preslice_remap_x", "gcode_remap_x", "gcode_back_transform"})
|
||||||
|
toggle_line(el, show_remap);
|
||||||
|
|
||||||
// Gray out angle/from sub-options when their parent shear/scale mode is None.
|
// Gray out angle/from sub-options when their parent shear/scale mode is None.
|
||||||
auto sx = m_config->option<ConfigOptionEnum<BeltShearMode>>("belt_shear_x")->value;
|
auto sx = m_config->option<ConfigOptionEnum<BeltShearMode>>("belt_shear_x")->value;
|
||||||
toggle_option("belt_shear_x_angle", is_belt && sx != BeltShearMode::None);
|
toggle_option("belt_shear_x_angle", is_belt && sx != BeltShearMode::None);
|
||||||
|
|||||||
Reference in New Issue
Block a user