mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-26 19:39:14 +00:00
strategy incremental
This commit is contained in:
@@ -4345,6 +4345,21 @@ void Print::_plan_belt_purge()
|
||||
const bool use_flush_matrix = m_config.purge_in_prime_tower && m_config.single_extruder_multi_material;
|
||||
const float flush_multiplier = (float) m_config.flush_multiplier.get_at(0);
|
||||
|
||||
// Diagnostic: the prism only absorbs purge at toolchange layers whose
|
||||
// print_z coincides with one of its own layers. Compare the prism's layer
|
||||
// print_z range to the toolchange print_z range and count how many
|
||||
// toolchange layers actually land on a prism layer. This distinguishes a
|
||||
// range/grid-alignment failure (no coverage) from a capacity shortfall
|
||||
// (covered but not enough cross-section).
|
||||
const PrintObject *diag_prism = nullptr;
|
||||
for (const PrintObject *po : m_objects)
|
||||
if (po->config().belt_purge_tower_object.value && !po->layers().empty()) { diag_prism = po; break; }
|
||||
if (diag_prism != nullptr)
|
||||
BOOST_LOG_TRIVIAL(warning) << "[BELT-DEBUG] purge prism layer range print_z=["
|
||||
<< diag_prism->layers().front()->print_z << ", " << diag_prism->layers().back()->print_z
|
||||
<< "] nlayers=" << diag_prism->layers().size();
|
||||
int tc_layers = 0, tc_layers_covered = 0;
|
||||
|
||||
float total_leftover = 0.f;
|
||||
float worst_layer_leftover = 0.f;
|
||||
double worst_layer_z = 0.;
|
||||
@@ -4352,9 +4367,16 @@ void Print::_plan_belt_purge()
|
||||
unsigned int current_extruder_id = m_wipe_tower_data.tool_ordering.first_extruder();
|
||||
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) {
|
||||
float layer_leftover = 0.f;
|
||||
bool layer_has_tc = false;
|
||||
for (const unsigned int extruder_id : layer_tools.extruders) {
|
||||
if (extruder_id == current_extruder_id)
|
||||
continue;
|
||||
if (!layer_has_tc) {
|
||||
layer_has_tc = true;
|
||||
++tc_layers;
|
||||
if (diag_prism != nullptr && diag_prism->get_layer_at_printz(layer_tools.print_z, EPSILON) != nullptr)
|
||||
++tc_layers_covered;
|
||||
}
|
||||
float volume_to_wipe = use_flush_matrix ?
|
||||
wipe_volumes[current_extruder_id][extruder_id] * flush_multiplier :
|
||||
(float) m_config.prime_volume;
|
||||
@@ -4379,6 +4401,11 @@ void Print::_plan_belt_purge()
|
||||
this->throw_if_canceled();
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(warning) << "[BELT-DEBUG] purge coverage: " << tc_layers_covered << "/" << tc_layers
|
||||
<< " toolchange layers land on a prism layer"
|
||||
<< (tc_layers > 0 && tc_layers_covered == 0 ? " (RANGE/GRID MISALIGNMENT — prism absorbs nothing)" :
|
||||
tc_layers_covered < tc_layers ? " (partial coverage)" : " (full coverage)");
|
||||
|
||||
if (total_leftover > 1.f) {
|
||||
this->active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::CRITICAL,
|
||||
|
||||
@@ -9041,12 +9041,19 @@ bool Plater::priv::ensure_belt_purge_tower()
|
||||
}
|
||||
const double v_layer = double(filaments.size() - 1) * max_flush;
|
||||
|
||||
// One tilted slicing plane cuts a width x (height/sin) rectangle out of
|
||||
// the prism interior; one layer slab absorbs that area x layer height.
|
||||
const double eta = 0.85; // perimeters/infill packing safety factor
|
||||
double height = v_layer * sin_t / (width * layer_h * eta);
|
||||
// Height from the per-layer purge demand. A tilted slicing plane cuts a
|
||||
// width x (height/sin) rectangle out of the bar, so one layer slab absorbs
|
||||
// width * (height/sin) * layer_height of purge. Solve for the height that
|
||||
// holds the worst-case per-layer purge, with:
|
||||
// eta - infill/perimeter packing (not all of the cross-section is solid)
|
||||
// safety - margin for the tilt ramp at the bar ends and layer-grid
|
||||
// alignment slop, where a layer cuts less than the full section
|
||||
// and a minimum so the tower is a real printable body rather than a sliver.
|
||||
const double eta = 0.85;
|
||||
const double safety = 1.6;
|
||||
const double printable_height = printer_config.has("printable_height") ? printer_config.opt_float("printable_height") : 250.;
|
||||
height = std::clamp(height, 2. * layer_h, std::max(2. * layer_h, printable_height));
|
||||
double height = safety * v_layer * sin_t / (width * layer_h * eta);
|
||||
height = std::clamp(height, 8.0, std::max(8.0, printable_height));
|
||||
|
||||
// --- Idempotence (input-keyed) ----------------------------------------
|
||||
// Key on the generation inputs, NOT the prism's resulting bbox: plate
|
||||
@@ -9068,28 +9075,31 @@ bool Plater::priv::ensure_belt_purge_tower()
|
||||
return false; // already up to date — do not touch the model
|
||||
|
||||
// --- Position ----------------------------------------------------------
|
||||
// Lay the bar along the belt, anchored at the parts' belt-axis minimum so
|
||||
// it leads the print at the belt entry. A tilted slicing plane through a
|
||||
// part of height z reaches belt position y + z*cot(theta), so extend the
|
||||
// trailing end to cover the tallest part's upper toolchanges plus the
|
||||
// prism's own tilt span.
|
||||
// Default belt-printer placement (per user request):
|
||||
// - belt-travel axis: anchored at the parts' belt-axis MINIMUM (the belt
|
||||
// entry / parts' min Y for an X-rotation belt) so the tower leads in.
|
||||
// - across-belt axis: parked right up against the bed's MAXIMUM edge
|
||||
// (max X for an X-rotation belt), out of the way of the parts.
|
||||
// The bar extends from the parts' belt minimum past the parts; a tilted
|
||||
// slicing plane through a part of height z reaches belt position
|
||||
// y + z*cot(theta), so the trailing end covers the tallest part's upper
|
||||
// toolchanges plus the bar's own tilt span.
|
||||
const double margin = 5.;
|
||||
const double belt_start = belt_min - margin; // anchored at parts' belt minimum
|
||||
const double belt_start = belt_min; // parts' belt-axis minimum
|
||||
const double belt_end = belt_max + (z_max + height) * cot_t + margin; // trailing tilt allowance
|
||||
const double length = std::max(belt_end - belt_start, 10.);
|
||||
const double belt_center = 0.5 * (belt_start + belt_end);
|
||||
|
||||
// Lateral placement: just beside the parts (the -lateral side by default,
|
||||
// flipping to the +lateral side if that would fall off the bed).
|
||||
// Across-belt: flush against the bed's maximum edge (small inset), falling
|
||||
// back to just past the parts if the bed shape is unavailable.
|
||||
const Vec3d plate_origin = plate->get_origin();
|
||||
const double gap = 5.;
|
||||
double lat_center = lat_min - gap - 0.5 * width;
|
||||
const double inset = 1.;
|
||||
double lat_center = lat_max + 5. + 0.5 * width;
|
||||
if (const auto *bed_opt = printer_config.option<ConfigOptionPoints>("printable_area");
|
||||
bed_opt != nullptr && !bed_opt->values.empty()) {
|
||||
const BoundingBoxf bed_ext = get_extents(bed_opt->values);
|
||||
const double bed_lat_min = plate_origin[belt_is_y ? 0 : 1] + (belt_is_y ? bed_ext.min.x() : bed_ext.min.y());
|
||||
if (lat_center - 0.5 * width < bed_lat_min)
|
||||
lat_center = lat_max + gap + 0.5 * width; // not enough room on the -lateral side
|
||||
const BoundingBoxf bed_ext = get_extents(bed_opt->values);
|
||||
const double bed_lat_max = plate_origin[belt_is_y ? 0 : 1] + (belt_is_y ? bed_ext.max.x() : bed_ext.max.y());
|
||||
lat_center = bed_lat_max - inset - 0.5 * width;
|
||||
}
|
||||
|
||||
// Orient the bar: long axis = belt travel, width = lateral, height = Z.
|
||||
|
||||
Reference in New Issue
Block a user