strategy incremental

This commit is contained in:
harrierpigeon
2026-08-08 16:35:54 -05:00
parent ec4e9717d3
commit 854dae8dd2
2 changed files with 56 additions and 19 deletions
+27
View File
@@ -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 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); 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 total_leftover = 0.f;
float worst_layer_leftover = 0.f; float worst_layer_leftover = 0.f;
double worst_layer_z = 0.; 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(); 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()) { for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) {
float layer_leftover = 0.f; float layer_leftover = 0.f;
bool layer_has_tc = false;
for (const unsigned int extruder_id : layer_tools.extruders) { for (const unsigned int extruder_id : layer_tools.extruders) {
if (extruder_id == current_extruder_id) if (extruder_id == current_extruder_id)
continue; 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 ? float volume_to_wipe = use_flush_matrix ?
wipe_volumes[current_extruder_id][extruder_id] * flush_multiplier : wipe_volumes[current_extruder_id][extruder_id] * flush_multiplier :
(float) m_config.prime_volume; (float) m_config.prime_volume;
@@ -4379,6 +4401,11 @@ void Print::_plan_belt_purge()
this->throw_if_canceled(); 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) { if (total_leftover > 1.f) {
this->active_step_add_warning( this->active_step_add_warning(
PrintStateBase::WarningLevel::CRITICAL, PrintStateBase::WarningLevel::CRITICAL,
+28 -18
View File
@@ -9041,12 +9041,19 @@ bool Plater::priv::ensure_belt_purge_tower()
} }
const double v_layer = double(filaments.size() - 1) * max_flush; const double v_layer = double(filaments.size() - 1) * max_flush;
// One tilted slicing plane cuts a width x (height/sin) rectangle out of // Height from the per-layer purge demand. A tilted slicing plane cuts a
// the prism interior; one layer slab absorbs that area x layer height. // width x (height/sin) rectangle out of the bar, so one layer slab absorbs
const double eta = 0.85; // perimeters/infill packing safety factor // width * (height/sin) * layer_height of purge. Solve for the height that
double height = v_layer * sin_t / (width * layer_h * eta); // 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.; 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) ---------------------------------------- // --- Idempotence (input-keyed) ----------------------------------------
// Key on the generation inputs, NOT the prism's resulting bbox: plate // 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 return false; // already up to date — do not touch the model
// --- Position ---------------------------------------------------------- // --- Position ----------------------------------------------------------
// Lay the bar along the belt, anchored at the parts' belt-axis minimum so // Default belt-printer placement (per user request):
// it leads the print at the belt entry. A tilted slicing plane through a // - belt-travel axis: anchored at the parts' belt-axis MINIMUM (the belt
// part of height z reaches belt position y + z*cot(theta), so extend the // entry / parts' min Y for an X-rotation belt) so the tower leads in.
// trailing end to cover the tallest part's upper toolchanges plus the // - across-belt axis: parked right up against the bed's MAXIMUM edge
// prism's own tilt span. // (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 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 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 length = std::max(belt_end - belt_start, 10.);
const double belt_center = 0.5 * (belt_start + belt_end); const double belt_center = 0.5 * (belt_start + belt_end);
// Lateral placement: just beside the parts (the -lateral side by default, // Across-belt: flush against the bed's maximum edge (small inset), falling
// flipping to the +lateral side if that would fall off the bed). // back to just past the parts if the bed shape is unavailable.
const Vec3d plate_origin = plate->get_origin(); const Vec3d plate_origin = plate->get_origin();
const double gap = 5.; const double inset = 1.;
double lat_center = lat_min - gap - 0.5 * width; double lat_center = lat_max + 5. + 0.5 * width;
if (const auto *bed_opt = printer_config.option<ConfigOptionPoints>("printable_area"); if (const auto *bed_opt = printer_config.option<ConfigOptionPoints>("printable_area");
bed_opt != nullptr && !bed_opt->values.empty()) { bed_opt != nullptr && !bed_opt->values.empty()) {
const BoundingBoxf bed_ext = get_extents(bed_opt->values); 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()); const double bed_lat_max = plate_origin[belt_is_y ? 0 : 1] + (belt_is_y ? bed_ext.max.x() : bed_ext.max.y());
if (lat_center - 0.5 * width < bed_lat_min) lat_center = bed_lat_max - inset - 0.5 * width;
lat_center = lat_max + gap + 0.5 * width; // not enough room on the -lateral side
} }
// Orient the bar: long axis = belt travel, width = lateral, height = Z. // Orient the bar: long axis = belt travel, width = lateral, height = Z.