mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-17 07:52:08 +00:00
Part 2.7: Add G-code back-transform and tree support belt floor clipping
- Add BeltBackTransform class that inverts the shear/scale matrix and applies it in GCodeWriter::to_machine_coords() so G-code outputs in the machine's physical coordinate space, gated by new belt_gcode_back_transform config option - Extend belt floor clipping to all three tree support pipelines (Prusa-style, Orca organic, TreeModelVolumes) with per-layer polygon clipping, anti-overhang integration, and belt raft extension layers - Fix tree drop_nodes() belt termination, organic support global Z offset, collision calculation index bug, and first-layer brim/empty layer checks for belt printers two-shot - first build built but didn't plumb to UI. Woah. add pre-slice axis remap, because Y needs to be Z going to change tactic and move based on bbox min switch to per axis snapping per axis swap snap now per object build plate tilt wasn't invalidating slicer settings support upper bound now correct, need to get lower bound corrected axis swapped support termination corrected Z Shear works with and without pre-slice remap now
This commit is contained in:
150
src/libslic3r/GCode/BeltBackTransform.cpp
Normal file
150
src/libslic3r/GCode/BeltBackTransform.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#include "BeltBackTransform.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Keep in sync with PrintObjectSlice.cpp compute_shear_factor (lines ~147-157).
|
||||
static double compute_shear_factor(BeltShearMode mode, double angle_deg)
|
||||
{
|
||||
double angle_rad = Geometry::deg2rad(angle_deg);
|
||||
double sin_a = std::sin(angle_rad);
|
||||
double 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.;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep in sync with PrintObjectSlice.cpp compute_scale_factor (lines ~180-192).
|
||||
static double compute_scale_factor(BeltScaleMode mode, double angle_deg)
|
||||
{
|
||||
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.;
|
||||
}
|
||||
}
|
||||
|
||||
bool BeltBackTransform::init_from_config(const PrintConfig &config)
|
||||
{
|
||||
m_active = false;
|
||||
m_inverse = Transform3d::Identity();
|
||||
|
||||
if (!config.belt_printer.value || !config.belt_gcode_back_transform.value)
|
||||
return false;
|
||||
|
||||
// --- Pre-slice axis remap (same as PrintObjectSlice.cpp) ---
|
||||
int pre_rx = int(config.belt_preslice_remap_x.value);
|
||||
int pre_ry = int(config.belt_preslice_remap_y.value);
|
||||
int pre_rz = int(config.belt_preslice_remap_z.value);
|
||||
|
||||
bool has_preslice_remap = (pre_rx != int(BeltRemapAxis::PosX) ||
|
||||
pre_ry != int(BeltRemapAxis::PosY) ||
|
||||
pre_rz != int(BeltRemapAxis::PosZ));
|
||||
|
||||
// Require at least one active transform to proceed.
|
||||
bool has_global_shear = config.belt_shear_x_global.value ||
|
||||
config.belt_shear_y_global.value ||
|
||||
config.belt_shear_z_global.value;
|
||||
if (!has_global_shear && !has_preslice_remap)
|
||||
return false;
|
||||
|
||||
// Build pre-slice remap matrix.
|
||||
Transform3d pre_remap = Transform3d::Identity();
|
||||
if (has_preslice_remap) {
|
||||
auto remap_column = [](int r) -> Vec3d {
|
||||
int axis = r % 3;
|
||||
Vec3d col = Vec3d::Zero();
|
||||
if (r < 3) col[axis] = 1.0;
|
||||
else if (r < 6) col[axis] = -1.0;
|
||||
else col[axis] = -1.0; // Rev: max - pos
|
||||
return col;
|
||||
};
|
||||
|
||||
Matrix3d remap_lin;
|
||||
remap_lin.col(0) = remap_column(pre_rx);
|
||||
remap_lin.col(1) = remap_column(pre_ry);
|
||||
remap_lin.col(2) = remap_column(pre_rz);
|
||||
pre_remap.linear() = remap_lin;
|
||||
|
||||
// Rev mode translation (needs build volume extents).
|
||||
Vec3d remap_trans = Vec3d::Zero();
|
||||
if (pre_rx >= 6 || pre_ry >= 6 || pre_rz >= 6) {
|
||||
BoundingBoxf bbox_bed(config.printable_area.values);
|
||||
Vec3d vol_max(bbox_bed.max.x(), bbox_bed.max.y(),
|
||||
config.printable_height.value);
|
||||
auto add_rev = [&](int r, int out) {
|
||||
if (r >= 6) remap_trans[out] = vol_max[r % 3];
|
||||
};
|
||||
add_rev(pre_rx, 0);
|
||||
add_rev(pre_ry, 1);
|
||||
add_rev(pre_rz, 2);
|
||||
}
|
||||
pre_remap.translation() = remap_trans;
|
||||
}
|
||||
|
||||
// Build per-axis shear matrix (same as PrintObjectSlice.cpp).
|
||||
struct AxisShear { BeltShearMode mode; double angle; int from; };
|
||||
AxisShear axes[3] = {
|
||||
{ config.belt_shear_x.value, config.belt_shear_x_angle.value, int(config.belt_shear_x_from.value) },
|
||||
{ config.belt_shear_y.value, config.belt_shear_y_angle.value, int(config.belt_shear_y_from.value) },
|
||||
{ config.belt_shear_z.value, config.belt_shear_z_angle.value, int(config.belt_shear_z_from.value) },
|
||||
};
|
||||
|
||||
Matrix3d shear = Matrix3d::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) {
|
||||
shear(row, axes[row].from) += factor;
|
||||
has_shear = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build per-axis scale diagonal matrix (same as PrintObjectSlice.cpp).
|
||||
double sx = compute_scale_factor(config.belt_scale_x.value, config.belt_scale_x_angle.value);
|
||||
double sy = compute_scale_factor(config.belt_scale_y.value, config.belt_scale_y_angle.value);
|
||||
double sz = compute_scale_factor(config.belt_scale_z.value, config.belt_scale_z_angle.value);
|
||||
|
||||
Matrix3d scale = Matrix3d::Identity();
|
||||
bool has_scale = (std::abs(sx - 1.) > EPSILON ||
|
||||
std::abs(sy - 1.) > EPSILON ||
|
||||
std::abs(sz - 1.) > EPSILON);
|
||||
if (has_scale) {
|
||||
scale(0, 0) = sx;
|
||||
scale(1, 1) = sy;
|
||||
scale(2, 2) = sz;
|
||||
}
|
||||
|
||||
if (!has_shear && !has_scale && !has_preslice_remap)
|
||||
return false;
|
||||
|
||||
// Forward pipeline: scale * shear * pre_remap (same order as PrintObjectSlice.cpp).
|
||||
Transform3d combined = Transform3d::Identity();
|
||||
combined.linear() = scale * shear;
|
||||
combined = combined * pre_remap;
|
||||
m_inverse = combined.inverse();
|
||||
m_active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Vec3d BeltBackTransform::apply(const Vec3d &pos) const
|
||||
{
|
||||
if (!m_active)
|
||||
return pos;
|
||||
return m_inverse * pos;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
Reference in New Issue
Block a user