From 9b5eb76478876551492bceee06fe8989930a6519 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Mon, 20 Jul 2026 17:26:38 +0800 Subject: [PATCH] Misc updates and clean up - WipeTower: use filament_ramming_volumetric_speed(_nc) for ramming, falling back to max_vol_speed only when nil; gate precool temps on enable_pre_heating - ToolOrderUtils: disable the inter-layer forecast in the per-nozzle base reorder so H2D/H2C ordering is unchanged - PrintConfig: stop stripping filament_prime_volume in handle_legacy; document that prime_volume drives the Type2 wipe tower and filament_prime_volume the Type1 one - GCodeProcessor: exclude post-print end-gcode M400 dwells from the M73 estimate and drop the dead air-filtration state - Trim verbose BambuStudio source-location comments across the port --- src/libslic3r/GCode/GCodeProcessor.cpp | 36 +++-------------- src/libslic3r/GCode/GCodeProcessor.hpp | 11 ++---- src/libslic3r/GCode/ToolOrderUtils.cpp | 6 ++- src/libslic3r/GCode/WipeTower.cpp | 53 ++++++++------------------ src/libslic3r/GCode/WipeTower.hpp | 6 --- src/libslic3r/Print.cpp | 33 +++++++++------- src/libslic3r/PrintConfig.cpp | 7 ++-- src/libslic3r/PrintConfig.hpp | 1 - 8 files changed, 53 insertions(+), 100 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 996761c26f..cc53cd0e51 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1529,15 +1529,7 @@ void GCodeProcessor::run_post_process() tag.remove_suffix(1); tag.remove_prefix(1); // strip leading ';' if (tag == Machine_Start_GCode_End_Tag) { m_machine_start_gcode_end_line_id = line_id; return; } - if (tag == Machine_End_GCode_Start_Tag) { - m_machine_end_gcode_start_line_id = line_id; - // End gcode M400 delays (air purification, timelapse, sound) are post-print - // by definition. Skip them so M73 reports print completion time. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/GCodeProcessor.cpp — - // BBS drops leftover in calculate_time(is_final=true), achieving the same. - m_skip_end_gcode_delays = true; - return; - } + if (tag == Machine_End_GCode_Start_Tag) { m_machine_end_gcode_start_line_id = line_id; return; } } // filament-change commands: T, ;VT, M1020 S, each optionally " H" @@ -2932,8 +2924,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_preheat_steps = 1; m_result.backtrace_enabled = config.ooze_prevention && m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && filament_count > 1)); - m_support_air_filtration = config.support_air_filtration.value; - assert(config.nozzle_volume.size() == config.nozzle_diameter.size()); m_nozzle_volume.resize(config.nozzle_volume.size()); for (size_t idx = 0; idx < config.nozzle_volume.size(); ++idx) @@ -3087,10 +3077,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) const ConfigOptionInt *nozzle_HRC = config.option("nozzle_hrc"); if (nozzle_HRC != nullptr) m_result.nozzle_hrc = nozzle_HRC->value; - const ConfigOptionBool *support_air_filt = config.option("support_air_filtration"); - if (support_air_filt != nullptr) - m_support_air_filtration = support_air_filt->value; - const ConfigOptionInts* physical_extruder_map = config.option("physical_extruder_map"); if (physical_extruder_map != nullptr) { m_physical_extruder_map = physical_extruder_map->values; @@ -3508,7 +3494,6 @@ void GCodeProcessor::reset() m_extruder_blocks.clear(); m_machine_start_gcode_end_line_id = (unsigned int) (-1); m_machine_end_gcode_start_line_id = (unsigned int) (-1); - m_support_air_filtration = false; m_skip_end_gcode_delays = false; m_remaining_volume = std::vector(MAXIMUM_EXTRUDER_NUMBER, 0.f); @@ -4237,10 +4222,9 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers return; } - // End gcode marker: skip M400 S/P delays after this point so M73 reports - // print completion time, not post-print filtration/cooldown time. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/GCodeProcessor.cpp — - // BBS drops leftover in calculate_time(is_final=true), achieving the same. + // End gcode marker: skip post-print M400 S/P dwells after this point so the M73 estimate reports + // print-completion time, not post-print filtration/cooldown. BBS drops the same remainder in + // calculate_time(is_final). if (comment == Machine_End_GCode_Start_Tag) { m_skip_end_gcode_delays = true; return; @@ -6428,18 +6412,10 @@ void GCodeProcessor::process_M400(const GCodeReader::GCodeLine& line) float value_p = 0.0; if (line.has_value('S', value_s) || line.has_value('P', value_p)) { value_s += value_p * 0.001; - - - // End gcode M400 delays (air purification M400 S180, timelapse M400 S5, - // sound M400 S1) are post-print by definition. Skip them so M73 reports - // print completion time, not post-print filtration/cooldown time. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/GCodeProcessor.cpp — - // BBS drops leftover in calculate_time(is_final=true), achieving the same - // effect of excluding end gcode delays from M73 total. We skip at the - // source instead, leaving calculate_time unchanged for all printers. + // Skip post-print end-gcode dwells so they don't inflate the M73 estimate (see + // m_skip_end_gcode_delays). Only omits dwell time — no state is updated here. if (m_skip_end_gcode_delays) return; - simulate_st_synchronize(value_s); } } diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index aa10bb7ec1..f5bec9e826 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -1109,14 +1109,9 @@ class Print; std::vector m_extruder_blocks; unsigned int m_machine_start_gcode_end_line_id{ (unsigned int) (-1) }; unsigned int m_machine_end_gcode_start_line_id{ (unsigned int) (-1) }; - // End gcode M400 delays (air purification, timelapse, sound) are post-print - // by definition. M73 should report print completion time, not post-print time. - // m_skip_end_gcode_delays is set when MACHINE_END_GCODE_START tag is encountered - // during the streaming parse (process_tags), telling process_M400 to skip timed - // delays in the end gcode scope. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/GCodeProcessor.cpp — - // BBS drops leftover in calculate_time(is_final=true), achieving the same effect. - bool m_support_air_filtration{ false }; + // Set when the MACHINE_END_GCODE_START tag is seen during the streaming parse; tells + // process_M400 to skip post-print end-gcode dwells (air purification, timelapse, sound) + // so they don't inflate the M73 estimate. BBS excludes them in calculate_time(is_final). bool m_skip_end_gcode_delays{ false }; // Tracks, during the stream, which filament sits in each physical nozzle and which nozzle each // extruder currently carries. Written by both branches of the two-arg process_filament_change diff --git a/src/libslic3r/GCode/ToolOrderUtils.cpp b/src/libslic3r/GCode/ToolOrderUtils.cpp index 1cf4dae1dd..4e2934d967 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.cpp +++ b/src/libslic3r/GCode/ToolOrderUtils.cpp @@ -1098,8 +1098,10 @@ namespace Slic3r // This avoids expensive inter-layer transitions (e.g. ending layer with F2 when // next layer starts with F3, costing flush[F2→F3], instead of ending with F3 // which gives flush[F3→F3]=0). Limited to ≤5 filaments due to O(N!×M!) complexity. - // Matches the multi-extruder path behavior (ToolOrderUtils.cpp:1227). - bool use_forcast = (filament_used.size() <= max_n_with_forcast && filament_used_next_layer.size() <= max_n_with_forcast); + // The per-nozzle base reorder does not use the inter-layer forecast. This function drives + // BBL multi-extruder grouping cost and H2C ordering, so keeping it false avoids perturbing + // existing H2D/H2C output. + bool use_forcast = false; float tmp_cost = 0; std::vector sequence; uint128_t hash_key = filament_list_to_hash_key(filament_used, filament_used_next_layer, curr_filament_id, use_forcast); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 2e93e9b352..06bca292d4 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -1610,27 +1610,31 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) m_filpar[idx].max_e_speed = (max_vol_speed / filament_area()); // Vortek H2C: carousel-specific ramming, precool, and reverse travel parameters - // Matches BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp L1878-1932 { // Ramming speed: .first = extruder change, .second = nozzle change (carousel) - float ramming_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx)); - if (config.filament_max_volumetric_speed.is_nil(idx) || ramming_vol_speed < EPSILON) + // Use the dedicated ramming volumetric speed, falling back to max_vol_speed only when + // the setting is nil/-1. + float ramming_vol_speed = float(config.filament_ramming_volumetric_speed.get_at(idx)); + if (config.filament_ramming_volumetric_speed.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed.get_at(idx), -1.)) ramming_vol_speed = max_vol_speed; m_filpar[idx].max_e_ramming_speed.first = (ramming_vol_speed / filament_area()); - float ramming_vol_speed_nc = ramming_vol_speed; // default: same as extruder change - if (!config.filament_ramming_volumetric_speed_nc.is_nil(idx) - && !is_approx(config.filament_ramming_volumetric_speed_nc.get_at(idx), -1.)) - ramming_vol_speed_nc = float(config.filament_ramming_volumetric_speed_nc.get_at(idx)); + float ramming_vol_speed_nc = float(config.filament_ramming_volumetric_speed_nc.get_at(idx)); + if (config.filament_ramming_volumetric_speed_nc.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed_nc.get_at(idx), -1.)) + ramming_vol_speed_nc = max_vol_speed; m_filpar[idx].max_e_ramming_speed.second = (ramming_vol_speed_nc / filament_area()); } { // Precool target temp: .first = extruder change, .second = nozzle change (carousel) + // Precool is only active when enable_pre_heating is on; otherwise no precool temp/timing is + // applied and the downstream precool_t stays 0, matching printers with pre-heating disabled. m_filpar[idx].precool_target_temp = {0, 0}; - if (!config.filament_pre_cooling_temperature.is_nil(idx)) - m_filpar[idx].precool_target_temp.first = config.filament_pre_cooling_temperature.get_at(idx); - if (!config.filament_pre_cooling_temperature_nc.is_nil(idx)) - m_filpar[idx].precool_target_temp.second = config.filament_pre_cooling_temperature_nc.get_at(idx); + if (config.enable_pre_heating.value) { + if (!config.filament_pre_cooling_temperature.is_nil(idx) && config.filament_pre_cooling_temperature.get_at(idx) != 0) + m_filpar[idx].precool_target_temp.first = config.filament_pre_cooling_temperature.get_at(idx); + if (!config.filament_pre_cooling_temperature_nc.is_nil(idx) && config.filament_pre_cooling_temperature_nc.get_at(idx) != 0) + m_filpar[idx].precool_target_temp.second = config.filament_pre_cooling_temperature_nc.get_at(idx); + } } { // Precool timing: (nozzle_temp - precool_temp) / hotend_cooling_rate @@ -2600,8 +2604,6 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; depth += nozzle_change_depth; } - // Vortek H2C override: carousel rotation (same extruder, different nozzle) also needs ramming depth - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp plan_toolchange() L2862 is_need_ramming() if (nozzle_change_depth == 0 && !m_filament_nozzle_map.empty() && old_tool < m_filament_nozzle_map.size() && new_tool < m_filament_nozzle_map.size() @@ -2764,7 +2766,6 @@ bool WipeTower::is_petg_filament(int filament_id) const return m_filpar[filament_id].material == "PETG"; } -// Matches BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp L3080-3085 bool WipeTower::is_need_reverse_travel(int filament_id, bool extruder_change) const { if (extruder_change) @@ -2896,11 +2897,6 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol && is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) { m_nozzle_change_result = nozzle_change_new(m_current_tool, new_tool, solid_nozzlechange); } - // Vortek H2C override: also trigger nozzle_change for carousel rotations within same extruder. - // Original Orca code above only checks m_filament_map (extruder-level). For H2C carousel, - // filaments on the same extruder but different nozzles also need ramming. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp tool_change_new() L3244 - // BBS uses is_need_ramming() = !are_filaments_same_nozzle() for nozzle-level gating. if (m_nozzle_change_result.gcode.empty() && !m_filament_nozzle_map.empty() && m_current_tool < m_filament_nozzle_map.size() && new_tool < m_filament_nozzle_map.size() @@ -3072,11 +3068,7 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, } float nz_extrusion_flow = nozzle_change_extrusion_flow(m_layer_height); - // Vortek H2C: carousel barrier inside nozzle change zone (emit M632/M633 ONLY for carousel = !extruder_change) - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp ramming() L3421-3429 bool extruder_change = !is_in_same_extruder(old_filament_id, new_filament_id); - // Vortek H2C: use carousel-specific ramming speed when available - // Matches BBS: ramming() L3435-3436 — max_e_ramming_speed.first (ext change) / .second (carousel) float max_e_ramming = extruder_change ? m_filpar[m_current_tool].max_e_ramming_speed.first : m_filpar[m_current_tool].max_e_ramming_speed.second; @@ -3098,7 +3090,6 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, if (!extruder_change && m_is_multiple_nozzle) { writer.append("M632 S" + std::to_string(new_filament_id) + " M N\n"); - // BBS L3425-3428: precool departing hotend + fan on inside barrier // Use m_physical_extruder_map for heater index (matches format_line_M104 in add_M104_by_requirement) if (m_filpar[m_current_tool].precool_target_temp.second != 0) { int logical_ext = m_filament_map.empty() ? 0 : m_filament_map[m_current_tool] - 1; @@ -3136,10 +3127,6 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, nozzle_change_line_count = solid_infill ? std::numeric_limits::max() : nozzle_change_line_count; m_left_to_right = true; - // Vortek H2C: per_cooling_max_speed — clamp ramming speed by cooldown time - // so departing nozzle reaches precool_target_temp before carousel rotation. - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp ramming() L3449-3462 - // BBS: "nozzle change does not require forcing a cooldown" — only extruder changes need this. if (extruder_change) { float ramming_length = nozzle_change_line_count * (xr - xl); int extruder_id = m_filament_map.empty() ? 0 : m_filament_map[m_current_tool] - 1; @@ -3188,16 +3175,14 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, block->last_nozzle_change_id = old_filament_id; NozzleChangeResult result; - // Vortek H2C: re-arm carousel barrier + reverse travel (BBS ramming() L3493-3535) if (!extruder_change && m_is_multiple_nozzle) { writer.append("M632 S" + std::to_string(new_filament_id) + " M N\n"); } if (is_need_reverse_travel(m_current_tool, extruder_change)) { - // BBS L3499-3526: reverse travel without extrusion back through ramming zone bool left_to_right = !m_left_to_right; int tpu_line_count = real_nozzle_change_line_count; - float reverse_speed = nozzle_change_speed * 2; // BBS L3502 + float reverse_speed = nozzle_change_speed * 2; // reverse travel runs at double the nozzle-change speed float rt_time = extruder_change ? m_filpar[m_current_tool].ramming_travel_time.first : m_filpar[m_current_tool].ramming_travel_time.second; float need_reverse_travel_dis = rt_time * reverse_speed / 60.f; @@ -3256,7 +3241,6 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, result.origin_start_pos = initial_position; result.end_pos = writer.pos_rotated(); result.gcode = writer.gcode(); - // Matches BBS: result.is_extruder_change = extruder_change (ramming() L3544) result.is_extruder_change = extruder_change; return result; } @@ -3697,7 +3681,6 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat buffer += '\n'; return buffer; }; - // Matches BBS: toolchange_wipe_new L4039 — add_M104_by_requirement fires for BOTH carousel and extruder changes. // m_is_multiple_nozzle gate needed because Orca calls toolchange_wipe_new for ALL printers (BBS has it H2C-only). bool should_heating = m_is_multiple_nozzle && m_filpar[m_current_tool].filament_cooling_before_tower > EPSILON && !solid_tool_toolchange && !is_first_layer(); @@ -3880,8 +3863,6 @@ bool WipeTower::is_in_same_extruder(int filament_id_1, int filament_id_2) return m_filament_map[filament_id_1] == m_filament_map[filament_id_2]; } -// Vortek H2C: format BBS-compatible NOZZLE_CHANGE_START/END tag with OF/NF/ON/NN payload. -// Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp format_nozzle_change_line() L3388 std::string WipeTower::format_nozzle_change_tag(bool start, int old_filament_id, int new_filament_id) const { const std::string &tag = start ? GCodeProcessor::Nozzle_Change_Start_Tag : GCodeProcessor::Nozzle_Change_End_Tag; @@ -4092,8 +4073,6 @@ void WipeTower::plan_tower_new() nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width; depth += nozzle_change_depth; } - // Vortek H2C override: carousel rotation also needs ramming depth - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp plan_tower_new() uses is_need_ramming() if (nozzle_change_depth == 0 && !m_filament_nozzle_map.empty() && toolchange.old_tool < (int)m_filament_nozzle_map.size() && toolchange.new_tool < (int)m_filament_nozzle_map.size() diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 4de7f30545..508765824e 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -58,7 +58,6 @@ public: Vec2f origin_start_pos; // not rotated std::vector wipe_path; - // Matches BBS: BambuStudio/src/libslic3r/GCode/WipeTower.hpp NozzleChangeResult::is_extruder_change bool is_extruder_change{true}; }; @@ -312,7 +311,6 @@ public: void set_filament_map(const std::vector &filament_map) { m_filament_map = filament_map; } // Vortek H2C: filament_id → physical nozzle_id for carousel rotation detection - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.hpp set_nozzle_group_result() void set_filament_nozzle_map(const std::vector &nozzle_map) { m_filament_nozzle_map = nozzle_map; } void set_has_tpu_filament(bool has_tpu) { m_has_tpu_filament = has_tpu; } @@ -361,8 +359,6 @@ public: // Distance (in mm of filament) that a hotend is allowed to pre-cool before the // tower is reached; drives the prime-tower heating-during-wipe model (multi-nozzle only). float filament_cooling_before_tower = 0.f; - // Matches BBS: BambuStudio/src/libslic3r/GCode/WipeTower.hpp L335-339 - // Carousel-specific ramming, precool, and reverse travel parameters. // .first = extruder change, .second = nozzle change (carousel) std::pair max_e_ramming_speed{0.f, 0.f}; std::pair ramming_travel_time{0.f, 0.f}; @@ -409,7 +405,6 @@ public: int get_filament_category(int filament_id); bool is_in_same_extruder(int filament_id_1, int filament_id_2); // Vortek H2C: format BBS-compatible NOZZLE_CHANGE_START/END tag with OF/NF/ON/NN payload - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp format_nozzle_change_line() std::string format_nozzle_change_tag(bool start, int old_filament_id, int new_filament_id) const; void reset_block_status(); int get_wall_filament_for_all_layer(); @@ -572,7 +567,6 @@ private: bool is_tpu_filament(int filament_id) const; bool is_petg_filament(int filament_id) const; - // Matches BBS: BambuStudio/src/libslic3r/GCode/WipeTower.cpp L3080-3085 bool is_need_reverse_travel(int filament_id, bool extruder_change) const; // BBS diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 90d028b3d9..1c9ffdd0c8 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -4018,7 +4018,6 @@ void Print::_make_wipe_tower() wipe_tower.set_has_tpu_filament(this->has_tpu_filament()); wipe_tower.set_filament_map(this->get_filament_maps()); // Vortek H2C: pass nozzle-level map for carousel rotation detection in tool_change_new() - // Reference to BBS: BambuStudio/src/libslic3r/GCode/WipeTower.hpp set_nozzle_group_result() wipe_tower.set_filament_nozzle_map(this->get_filament_nozzle_maps()); // Feed the has_filament_switcher device flag (develop-only dynamic key, read defensively from // the full config — no shipping profile sets it) and the shared printable bed used by the PETG @@ -4055,12 +4054,14 @@ void Print::_make_wipe_tower() multi_extruder_flush.emplace_back(wipe_volumes); } - // Reference to BBS: BambuStudio/src/libslic3r/Print.cpp _make_wipe_tower() // Use NozzleStatusRecorder for per-carousel-slot tracking (BBS pattern). // The original Orca code tracked per-extruder (2 slots), which collapsed all // carousel filaments into one slot and caused massive redundant AMS flushing. auto group_result = get_layered_nozzle_group_result(); MultiNozzleUtils::NozzleStatusRecorder nozzle_recorder; + // Fallback (group_result == null) per-physical-nozzle tracking, matching the original + // pre-port behavior: remembers the last filament loaded in each physical nozzle slot. + std::vector nozzle_cur_filament_ids(nozzle_nums, (unsigned int) -1); std::vectorfilament_maps = get_filament_maps(); int layer_idx = -1; @@ -4071,6 +4072,9 @@ void Print::_make_wipe_tower() auto nozzle = group_result->get_nozzle_for_filament(current_filament_id, layer_idx); if (nozzle) nozzle_recorder.set_nozzle_status(nozzle->group_id, current_filament_id, nozzle->extruder_id); + } else { + size_t cur_nozzle_id = filament_maps[current_filament_id] - 1; + nozzle_cur_filament_ids[cur_nozzle_id] = current_filament_id; } for (auto& layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers @@ -4088,7 +4092,6 @@ void Print::_make_wipe_tower() float volume_to_purge = 0; - // Reference to BBS: BambuStudio/src/libslic3r/Print.cpp L3361-3392 // Per-carousel-slot purge tracking via NozzleStatusRecorder if (group_result) { auto nozzle_info = group_result->get_nozzle_for_filament(filament_id, layer_idx); @@ -4111,15 +4114,21 @@ void Print::_make_wipe_tower() nozzle_recorder.set_nozzle_status(nozzle_id, filament_id, extruder_id); } } else { - // Fallback: original Orca per-extruder path (non-carousel printers) + // Fallback: original Orca per-physical-nozzle path (non-carousel printers). + // Flush source is the last filament that occupied THIS nozzle, guarded so the + // first use of a nozzle incurs no flush. int nozzle_id = filament_maps[filament_id] - 1; - volume_to_purge = multi_extruder_flush[nozzle_id][current_filament_id][filament_id]; - float flush_multiplier = (m_config.prime_volume_mode == PrimeVolumeMode::pvmFast) - ? m_config.flush_multiplier_fast.get_at(nozzle_id) - : m_config.flush_multiplier.get_at(nozzle_id); - volume_to_purge *= flush_multiplier; - volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions( - *this, current_filament_id, filament_id, volume_to_purge); + unsigned int pre_filament_id = nozzle_cur_filament_ids[nozzle_id]; + if (pre_filament_id != (unsigned int) -1 && pre_filament_id != filament_id) { + volume_to_purge = multi_extruder_flush[nozzle_id][pre_filament_id][filament_id]; + float flush_multiplier = (m_config.prime_volume_mode == PrimeVolumeMode::pvmFast) + ? m_config.flush_multiplier_fast.get_at(nozzle_id) + : m_config.flush_multiplier.get_at(nozzle_id); + volume_to_purge *= flush_multiplier; + volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions( + *this, current_filament_id, filament_id, volume_to_purge); + } + nozzle_cur_filament_ids[nozzle_id] = filament_id; } //During the filament change, the extruder will extrude an extra length of grab_length for the corresponding detection, so the purge can reduce this length. @@ -4127,10 +4136,8 @@ void Print::_make_wipe_tower() float grab_purge_volume = m_config.grab_length.get_at(grab_extruder_id) * 2.4; //(diameter/2)^2*PI=2.4 volume_to_purge = std::max(0.f, volume_to_purge - grab_purge_volume); - // Reference to BBS: BambuStudio/src/libslic3r/Print.cpp L3381-3387 // Select prime volume per-filament: nozzle change (carousel rotation) uses // filament_prime_volume_nc, filament change (same nozzle slot) uses filament_prime_volume. - // BBS passes both to plan_toolchange (7 args), we select the right one here (6 args). float wipe_volume_ec = filament_id < m_config.filament_prime_volume.values.size() ? m_config.filament_prime_volume.values[filament_id] : (float) m_config.prime_volume; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index e28781b1f1..38e07cd534 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7384,7 +7384,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("The flush multiplier used in fast purge mode."); def->set_default_value(new ConfigOptionFloats{1.2}); - // BBS + // Orca: used by the generic (Type2) wipe tower; also the fallback for filament_prime_volume on Type1. def = this->add("prime_volume", coFloat); def->label = L("Prime volume"); def->tooltip = L("This is the volume of material to prime the extruder with on the tower."); @@ -8030,7 +8030,8 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionBool(false)); - // Reference to BBS: BambuStudio/src/libslic3r/PrintConfig.cpp L2617-2624 + // Used by the Type1 wipe tower: filament_prime_volume on a filament change, + // filament_prime_volume_nc on a hotend/nozzle change. Type2 uses prime_volume instead. def = this->add("filament_prime_volume", coFloats); def->label = L("Filament change"); def->tooltip = L("The volume of material required to prime the extruder on the tower, excluding a hotend change."); @@ -9059,7 +9060,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va "retraction_distance_when_cut", "internal_bridge_support_thickness", "top_area_threshold", "reduce_wall_solid_infill","filament_load_time","filament_unload_time", "smooth_coefficient", "overhang_totally_speed", "silent_mode", - "overhang_speed_classic", "filament_prime_volume", + "overhang_speed_classic", "anisotropic_surfaces", // superseded by top_surface_fill_order / bottom_surface_fill_order }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index cc7cb0273d..73811e3ecb 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1841,7 +1841,6 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( // BBS: wipe tower is only used for priming ((ConfigOptionFloat, prime_volume)) // Nozzle-change (nc) prime volume + pre-heat delta - // Reference to BBS: BambuStudio/src/libslic3r/PrintConfig.hpp L1524-1525 ((ConfigOptionFloats, filament_prime_volume)) ((ConfigOptionFloats, filament_prime_volume_nc)) ((ConfigOptionFloatsNullable, filament_preheat_temperature_delta))