mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-15 23:12:08 +00:00
Relocate Pre-Slice remap logic
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#include "BeltSliceStrategy.hpp"
|
||||
#include "Model.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
#include <iomanip>
|
||||
@@ -10,130 +12,132 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
std::unique_ptr<BeltSliceStrategy> BeltSliceStrategy::create(const PrintConfig &config)
|
||||
void BeltSliceStrategy::apply_preslice_transforms(Transform3d &trafo,
|
||||
const PrintConfig &config,
|
||||
const ModelVolumePtrs &model_volumes,
|
||||
double *out_belt_min_z)
|
||||
{
|
||||
if (!config.belt_printer.value)
|
||||
return nullptr;
|
||||
return std::unique_ptr<BeltSliceStrategy>(new BeltSliceStrategy(config));
|
||||
}
|
||||
// 1. Standalone pre-slice axis remap (works without belt mode).
|
||||
const bool has_remap = BeltTransformPipeline::has_preslice_remap(config);
|
||||
if (has_remap)
|
||||
trafo = BeltTransformPipeline::build_preslice_remap(config) * trafo;
|
||||
|
||||
BeltSliceStrategy::BeltSliceStrategy(const PrintConfig &config)
|
||||
{
|
||||
m_rotation = BeltTransformPipeline::build_rotation_matrix(config, &m_has_rotation);
|
||||
}
|
||||
|
||||
void BeltSliceStrategy::apply_to_trafo(Transform3d &trafo,
|
||||
const ModelVolumePtrs &model_volumes,
|
||||
bool has_remap,
|
||||
double *out_belt_min_z) const
|
||||
{
|
||||
// Rotation is the only mesh-side belt transform (matching build_forward_transform).
|
||||
if (m_has_rotation) {
|
||||
Transform3d belt_xform = Transform3d::Identity();
|
||||
belt_xform.linear() = m_rotation;
|
||||
trafo = belt_xform * trafo;
|
||||
// 2. Belt rotation — the sole mesh-side belt transform (matching
|
||||
// BeltTransformPipeline::build_forward_transform). Only active in
|
||||
// belt-printer mode.
|
||||
bool has_rotation = false;
|
||||
if (config.belt_printer.value) {
|
||||
const Matrix3d rot = BeltTransformPipeline::build_rotation_matrix(config, &has_rotation);
|
||||
if (has_rotation) {
|
||||
Transform3d belt_xform = Transform3d::Identity();
|
||||
belt_xform.linear() = rot;
|
||||
trafo = belt_xform * trafo;
|
||||
}
|
||||
}
|
||||
|
||||
// Z-shift — detect if mesh clips below build plate after transforms.
|
||||
// Each mesh vertex must be brought into object space via mv->get_matrix()
|
||||
// before applying the full trafo (which is in object space). Missing this
|
||||
// step on assemblies (where per-volume get_matrix() positions each volume
|
||||
// within the object) causes min_z to be computed against mesh-local vertex
|
||||
// coordinates rather than object-space coordinates, so volumes translated
|
||||
// along the slicer's Z axis are silently excluded from the bound check.
|
||||
if (has_remap || m_has_rotation) {
|
||||
if (!has_remap && !has_rotation)
|
||||
return;
|
||||
|
||||
// 3. Z-shift — detect if the mesh clips below the build plate after the
|
||||
// transforms and lift it. Each mesh vertex must be brought into object space
|
||||
// via mv->get_matrix() before applying the full trafo (which is in object
|
||||
// space). Missing this on assemblies (where per-volume get_matrix() positions
|
||||
// each volume within the object) would compute min_z against mesh-local vertex
|
||||
// coordinates rather than object-space coordinates, so volumes translated along
|
||||
// the slicer's Z axis would be silently excluded from the bound check.
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
// Capture the incoming trafo for diagnostic logging.
|
||||
// This is the slicer-frame transform AFTER belt_xform but BEFORE z_shift.
|
||||
const Transform3d trafo_pre_shift = trafo;
|
||||
auto log_mat = [](const Matrix3d &m) {
|
||||
std::ostringstream ss;
|
||||
ss << std::fixed << std::setprecision(4);
|
||||
ss << "[[" << m(0,0) << "," << m(0,1) << "," << m(0,2) << "],"
|
||||
<< "[" << m(1,0) << "," << m(1,1) << "," << m(1,2) << "],"
|
||||
<< "[" << m(2,0) << "," << m(2,1) << "," << m(2,2) << "]]";
|
||||
return ss.str();
|
||||
};
|
||||
auto log_vec3 = [](const Vec3d &v) {
|
||||
std::ostringstream ss;
|
||||
ss << std::fixed << std::setprecision(4);
|
||||
ss << "(" << v.x() << "," << v.y() << "," << v.z() << ")";
|
||||
return ss.str();
|
||||
};
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] apply_to_trafo enter"
|
||||
<< " has_rotation=" << m_has_rotation
|
||||
<< " has_remap=" << has_remap
|
||||
<< " trafo.linear=" << log_mat(trafo_pre_shift.linear())
|
||||
<< " trafo.translation=" << log_vec3(trafo_pre_shift.translation())
|
||||
<< " volumes=" << model_volumes.size();
|
||||
// Capture the incoming trafo for diagnostic logging.
|
||||
// This is the slicer-frame transform AFTER remap + rotation but BEFORE z_shift.
|
||||
const Transform3d trafo_pre_shift = trafo;
|
||||
auto log_mat = [](const Matrix3d &m) {
|
||||
std::ostringstream ss;
|
||||
ss << std::fixed << std::setprecision(4);
|
||||
ss << "[[" << m(0,0) << "," << m(0,1) << "," << m(0,2) << "],"
|
||||
<< "[" << m(1,0) << "," << m(1,1) << "," << m(1,2) << "],"
|
||||
<< "[" << m(2,0) << "," << m(2,1) << "," << m(2,2) << "]]";
|
||||
return ss.str();
|
||||
};
|
||||
auto log_vec3 = [](const Vec3d &v) {
|
||||
std::ostringstream ss;
|
||||
ss << std::fixed << std::setprecision(4);
|
||||
ss << "(" << v.x() << "," << v.y() << "," << v.z() << ")";
|
||||
return ss.str();
|
||||
};
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] apply_preslice_transforms enter"
|
||||
<< " has_rotation=" << has_rotation
|
||||
<< " has_remap=" << has_remap
|
||||
<< " trafo.linear=" << log_mat(trafo_pre_shift.linear())
|
||||
<< " trafo.translation=" << log_vec3(trafo_pre_shift.translation())
|
||||
<< " volumes=" << model_volumes.size();
|
||||
#endif
|
||||
|
||||
double min_z = std::numeric_limits<double>::max();
|
||||
double min_z = std::numeric_limits<double>::max();
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
int vol_idx = 0;
|
||||
int vol_idx = 0;
|
||||
#endif
|
||||
for (const ModelVolume *mv : model_volumes) {
|
||||
for (const ModelVolume *mv : model_volumes) {
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
if (!mv->is_model_part()) { ++vol_idx; continue; }
|
||||
if (!mv->is_model_part()) { ++vol_idx; continue; }
|
||||
#else
|
||||
if (!mv->is_model_part()) continue;
|
||||
if (!mv->is_model_part()) continue;
|
||||
#endif
|
||||
Transform3d vol_trafo = trafo * mv->get_matrix();
|
||||
const auto &its = mv->mesh().its;
|
||||
Transform3d vol_trafo = trafo * mv->get_matrix();
|
||||
const auto &its = mv->mesh().its;
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
// Per-volume bbox in mesh-frame and post-trafo slicer-frame.
|
||||
Vec3d mesh_min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
Vec3d mesh_max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
|
||||
Vec3d slicer_min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
Vec3d slicer_max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
|
||||
double vol_min_z = std::numeric_limits<double>::max();
|
||||
// Per-volume bbox in mesh-frame and post-trafo slicer-frame.
|
||||
Vec3d mesh_min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
Vec3d mesh_max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
|
||||
Vec3d slicer_min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
|
||||
Vec3d slicer_max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
|
||||
double vol_min_z = std::numeric_limits<double>::max();
|
||||
#endif
|
||||
for (const stl_vertex &v : its.vertices) {
|
||||
Vec3d vm = v.cast<double>();
|
||||
Vec3d pt = vol_trafo * vm;
|
||||
min_z = std::min(min_z, pt.z());
|
||||
for (const stl_vertex &v : its.vertices) {
|
||||
Vec3d vm = v.cast<double>();
|
||||
Vec3d pt = vol_trafo * vm;
|
||||
min_z = std::min(min_z, pt.z());
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
mesh_min = mesh_min.cwiseMin(vm);
|
||||
mesh_max = mesh_max.cwiseMax(vm);
|
||||
slicer_min = slicer_min.cwiseMin(pt);
|
||||
slicer_max = slicer_max.cwiseMax(pt);
|
||||
vol_min_z = std::min(vol_min_z, pt.z());
|
||||
#endif
|
||||
}
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] vol[" << vol_idx
|
||||
<< "] id=" << mv->id().id << " name='" << mv->name << "'"
|
||||
<< " mesh_bbox_min=" << log_vec3(mesh_min) << " mesh_bbox_max=" << log_vec3(mesh_max)
|
||||
<< " get_matrix.translation=" << log_vec3(mv->get_matrix().translation())
|
||||
<< " slicer_bbox_min=" << log_vec3(slicer_min) << " slicer_bbox_max=" << log_vec3(slicer_max)
|
||||
<< " vol_min_z=" << vol_min_z;
|
||||
++vol_idx;
|
||||
mesh_min = mesh_min.cwiseMin(vm);
|
||||
mesh_max = mesh_max.cwiseMax(vm);
|
||||
slicer_min = slicer_min.cwiseMin(pt);
|
||||
slicer_max = slicer_max.cwiseMax(pt);
|
||||
vol_min_z = std::min(vol_min_z, pt.z());
|
||||
#endif
|
||||
}
|
||||
double belt_z_shift_val = (min_z < 0. && min_z != std::numeric_limits<double>::max()) ? -min_z : 0.;
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] combined min_z=" << min_z
|
||||
<< " z_shift_val=" << belt_z_shift_val;
|
||||
#endif
|
||||
if (belt_z_shift_val > 0.) {
|
||||
Transform3d z_shift = Transform3d::Identity();
|
||||
z_shift.matrix()(2, 3) = belt_z_shift_val;
|
||||
trafo = z_shift * trafo;
|
||||
}
|
||||
if (out_belt_min_z) {
|
||||
double new_val = (min_z != std::numeric_limits<double>::max()) ? min_z : 0.;
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] write m_belt_min_z tid=" << std::this_thread::get_id()
|
||||
<< " target=" << out_belt_min_z << " old=" << *out_belt_min_z << " new=" << new_val;
|
||||
#endif
|
||||
*out_belt_min_z = new_val;
|
||||
}
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] apply_to_trafo exit"
|
||||
<< " final_trafo.linear=" << log_mat(trafo.linear())
|
||||
<< " final_trafo.translation=" << log_vec3(trafo.translation());
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] vol[" << vol_idx
|
||||
<< "] id=" << mv->id().id << " name='" << mv->name << "'"
|
||||
<< " mesh_bbox_min=" << log_vec3(mesh_min) << " mesh_bbox_max=" << log_vec3(mesh_max)
|
||||
<< " get_matrix.translation=" << log_vec3(mv->get_matrix().translation())
|
||||
<< " slicer_bbox_min=" << log_vec3(slicer_min) << " slicer_bbox_max=" << log_vec3(slicer_max)
|
||||
<< " vol_min_z=" << vol_min_z;
|
||||
++vol_idx;
|
||||
#endif
|
||||
}
|
||||
const double z_shift_val = (min_z < 0. && min_z != std::numeric_limits<double>::max()) ? -min_z : 0.;
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] combined min_z=" << min_z
|
||||
<< " z_shift_val=" << z_shift_val;
|
||||
#endif
|
||||
if (z_shift_val > 0.) {
|
||||
Transform3d z_shift = Transform3d::Identity();
|
||||
z_shift.matrix()(2, 3) = z_shift_val;
|
||||
trafo = z_shift * trafo;
|
||||
}
|
||||
// out_belt_min_z is only meaningful in belt mode; the standalone-remap path
|
||||
// never reported it.
|
||||
if (out_belt_min_z && config.belt_printer.value) {
|
||||
const double new_val = (min_z != std::numeric_limits<double>::max()) ? min_z : 0.;
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] write m_belt_min_z tid=" << std::this_thread::get_id()
|
||||
<< " target=" << out_belt_min_z << " old=" << *out_belt_min_z << " new=" << new_val;
|
||||
#endif
|
||||
*out_belt_min_z = new_val;
|
||||
}
|
||||
#ifdef SLIC3R_BELT_DIAGNOSTIC_LOG
|
||||
BOOST_LOG_TRIVIAL(trace) << "[BELT-DEBUG] apply_preslice_transforms exit"
|
||||
<< " final_trafo.linear=" << log_mat(trafo.linear())
|
||||
<< " final_trafo.translation=" << log_vec3(trafo.translation());
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -6,36 +6,31 @@
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Model.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Belt printer pre-slice transform strategy.
|
||||
// Belt printer / pre-slice transform strategy.
|
||||
//
|
||||
// Encapsulates the pre-remap, rotation, and Z-shift transforms that are
|
||||
// applied to model geometry before slicing on belt printers. (Shear & scale
|
||||
// are applied to the g-code, not the mesh.) Used by PrintObjectSlice.cpp to
|
||||
// isolate belt-specific logic from the slicing pipeline.
|
||||
// Composes, in order, the pre-slice mesh transforms applied before slicing:
|
||||
// 1. Pre-slice axis remap (standalone — works without belt mode)
|
||||
// 2. Belt rotation (the sole mesh-side belt transform; shear & scale are a
|
||||
// g-code-side stage, see MachineFrameTransform)
|
||||
// 3. Per-object Z-shift that lifts the mesh above the build plate
|
||||
//
|
||||
// Isolates this belt/remap-specific logic from the generic slicing pipeline in
|
||||
// PrintObjectSlice.cpp.
|
||||
class BeltSliceStrategy
|
||||
{
|
||||
public:
|
||||
// Create a strategy if belt_printer is enabled; returns nullptr otherwise.
|
||||
static std::unique_ptr<BeltSliceStrategy> create(const PrintConfig &config);
|
||||
|
||||
// Apply belt-specific transforms (rotation + z-shift) to the slicing trafo.
|
||||
// Pre-slice remap is handled separately (standalone feature).
|
||||
// has_remap: whether pre-slice remap was already applied (affects z-shift detection).
|
||||
void apply_to_trafo(Transform3d &trafo,
|
||||
const ModelVolumePtrs &model_volumes,
|
||||
bool has_remap,
|
||||
double *out_belt_min_z) const;
|
||||
|
||||
private:
|
||||
explicit BeltSliceStrategy(const PrintConfig &config);
|
||||
|
||||
bool m_has_rotation = false;
|
||||
Matrix3d m_rotation = Matrix3d::Identity();
|
||||
// Apply the pre-slice remap + belt rotation + Z-shift to `trafo` in place.
|
||||
// No-op when neither a remap nor a belt rotation is configured.
|
||||
//
|
||||
// out_belt_min_z (if non-null) receives the minimum mesh Z after the
|
||||
// transforms, but only in belt-printer mode — the standalone-remap path
|
||||
// never reported it.
|
||||
static void apply_preslice_transforms(Transform3d &trafo,
|
||||
const PrintConfig &config,
|
||||
const ModelVolumePtrs &model_volumes,
|
||||
double *out_belt_min_z = nullptr);
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -173,35 +173,10 @@ static std::vector<VolumeSlices> slice_volumes_inner(
|
||||
params_base.closing_radius = print_object_config.slice_closing_radius.value;
|
||||
params_base.extra_offset = 0;
|
||||
params_base.trafo = object_trafo;
|
||||
// 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-specific transforms (shear, scale, z-shift) via strategy.
|
||||
auto belt_strategy = BeltSliceStrategy::create(print_config);
|
||||
if (belt_strategy)
|
||||
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.
|
||||
// Compose per-volume mv->get_matrix() so assembly volumes contribute their
|
||||
// actual object-space positions — see the matching note in BeltSliceStrategy.
|
||||
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;
|
||||
Transform3d vol_trafo = params_base.trafo * mv->get_matrix();
|
||||
for (const stl_vertex &v : mv->mesh().its.vertices) {
|
||||
Vec3d pt = vol_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;
|
||||
}
|
||||
}
|
||||
// Pre-slice mesh transforms: axis remap (standalone — works without belt
|
||||
// mode), belt rotation, and the per-object Z-shift. Owned by BeltSliceStrategy
|
||||
// so this belt/remap-specific logic stays out of the generic slicing pipeline.
|
||||
BeltSliceStrategy::apply_preslice_transforms(params_base.trafo, print_config, model_volumes, out_belt_min_z);
|
||||
//BBS: 0.0025mm is safe enough to simplify the data to speed slicing up for high-resolution model.
|
||||
//Also has on influence on arc fitting which has default resolution 0.0125mm.
|
||||
params_base.resolution = print_config.resolution <= 0.001 ? 0.0f : 0.0025;
|
||||
@@ -981,7 +956,7 @@ void PrintObject::slice()
|
||||
|
||||
// Per-object Z-shift compensation, applied regardless of global mode.
|
||||
//
|
||||
// BeltSliceStrategy::apply_to_trafo lifts the mesh by max(0, -m_belt_min_z)
|
||||
// BeltSliceStrategy::apply_preslice_transforms lifts the mesh by max(0, -m_belt_min_z)
|
||||
// so the slicer can slice with slicer_z >= 0. BeltBackTransform inverts
|
||||
// build_forward_transform() which DOES NOT include this per-object
|
||||
// Z-shift (it's not known until vertex scan time). Result: G-code
|
||||
|
||||
Reference in New Issue
Block a user