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