diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 4b434aa5ae..4fc8875c9a 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -323,6 +323,9 @@ class SliceMeshStorage std::shared_ptr lightning_generator; //!< Pre-computed structure for Lightning type infill RetractionAndWipeConfig retraction_wipe_config; //!< Per-Object retraction and wipe settings. + bool override_extruder_retract_settings = true; //!< The 'per-object' retraction and wipe settings are currently always filled, even if not overridden. + //!< This has potential conflicts with per-extruder retract/wipe settings. + //!< So, only override the settings on a per-object basis if all extruder retract/wipe settings are the same. /*! * \brief Creates a storage space for slice results of a mesh. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index fcba3b052b..3ba0dd8617 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -12,7 +12,9 @@ #include #include +#include #include +#include #include #include "Application.h" @@ -333,7 +335,32 @@ void FffGcodeWriter::setConfigFanSpeedLayerTime() } } -static void retractionAndWipeConfigFromSettings(const Settings& settings, RetractionAndWipeConfig* config) +static bool retractConfigIsSame(const RetractionConfig& a, const RetractionConfig& b) +{ + return a.distance == b.distance && a.prime_volume == b.prime_volume && a.speed == b.speed && a.primeSpeed == b.primeSpeed && a.zHop == b.zHop + && a.retraction_min_travel_distance == b.retraction_min_travel_distance && a.retraction_extrusion_window == b.retraction_extrusion_window + && a.retraction_count_max == b.retraction_count_max; +} + +static bool switchRetractConfigIsSame(const RetractionAndWipeConfig& a, const RetractionAndWipeConfig& b) +{ + return retractConfigIsSame(a.extruder_switch_retraction_config, b.extruder_switch_retraction_config) + && a.retraction_hop_after_extruder_switch == b.retraction_hop_after_extruder_switch && a.switch_extruder_extra_prime_amount == b.switch_extruder_extra_prime_amount; +} + +static bool wipeConfigIsSame(const WipeScriptConfig& a, const WipeScriptConfig& b) +{ + return retractConfigIsSame(a.retraction_config, b.retraction_config) && a.retraction_enable == b.retraction_enable && a.pause == b.pause && a.hop_enable == b.hop_enable + && a.hop_amount == b.hop_amount && a.hop_speed == b.hop_speed && a.brush_pos_x == b.brush_pos_x && a.repeat_count == b.repeat_count && a.move_distance == b.move_distance + && a.move_speed == b.move_speed && a.max_extrusion_mm3 == b.max_extrusion_mm3 && a.clean_between_layers == b.clean_between_layers; +} + +static bool retractAndWipeConfigIsSame(const RetractionAndWipeConfig& a, const RetractionAndWipeConfig& b) +{ + return retractConfigIsSame(a.retraction_config, b.retraction_config) && switchRetractConfigIsSame(a, b) && wipeConfigIsSame(a.wipe_config, b.wipe_config); +} + +static void retractionConfigFromSettings(const Settings& settings, RetractionAndWipeConfig* config) { RetractionConfig& retraction_config = config->retraction_config; retraction_config.distance = (settings.get("retraction_enable")) ? settings.get("retraction_amount") : 0; // Retraction distance in mm. @@ -344,7 +371,10 @@ static void retractionAndWipeConfigFromSettings(const Settings& settings, Retrac retraction_config.retraction_min_travel_distance = settings.get("retraction_min_travel"); retraction_config.retraction_extrusion_window = settings.get("retraction_extrusion_window"); // Window to count retractions in in mm of extruded filament. retraction_config.retraction_count_max = settings.get("retraction_count_max"); +} +static void switchRetractionConfigFromSettings(const Settings& settings, RetractionAndWipeConfig* config) +{ config->retraction_hop_after_extruder_switch = settings.get("retraction_hop_after_extruder_switch"); config->switch_extruder_extra_prime_amount = settings.get("switch_extruder_extra_prime_amount"); RetractionConfig& switch_retraction_config = config->extruder_switch_retraction_config; @@ -357,7 +387,10 @@ static void retractionAndWipeConfigFromSettings(const Settings& settings, Retrac switch_retraction_config.retraction_extrusion_window = 99999.9; // So that extruder switch retractions won't affect the retraction buffer (extruded_volume_at_previous_n_retractions). switch_retraction_config.retraction_count_max = 9999999; // Extruder switch retraction is never limited. +} +static void wipeScriptConfigFromSettings(const Settings& settings, RetractionAndWipeConfig* config) +{ WipeScriptConfig& wipe_config = config->wipe_config; wipe_config.retraction_enable = settings.get("wipe_retraction_enable"); @@ -383,17 +416,34 @@ static void retractionAndWipeConfigFromSettings(const Settings& settings, Retrac wipe_config.clean_between_layers = settings.get("clean_between_layers"); } +static void retractionAndWipeConfigFromSettings(const Settings& settings, RetractionAndWipeConfig* config) +{ + retractionConfigFromSettings(settings, config); + switchRetractionConfigFromSettings(settings, config); + wipeScriptConfigFromSettings(settings, config); +} + void FffGcodeWriter::setConfigRetractionAndWipe(SliceDataStorage& storage) { Scene& scene = Application::getInstance().current_slice_->scene; - for (size_t extruder_index = 0; extruder_index < scene.extruders.size(); extruder_index++) + for (auto [train, retraction_wipe_config] : ranges::views::zip(scene.extruders, storage.retraction_wipe_config_per_extruder)) { - ExtruderTrain& train = scene.extruders[extruder_index]; - retractionAndWipeConfigFromSettings(train.settings_, &storage.retraction_wipe_config_per_extruder[extruder_index]); + retractionAndWipeConfigFromSettings(train.settings_, &retraction_wipe_config); } + // The 'per-object' retraction and wipe settings are currently always filled, even if not overridden. + // This has potential conflicts with per-extruder retract/wipe settings. + // So, only override the settings on a per-object basis if all extruder retract/wipe settings are the same. + const auto& compare_with_first = storage.retraction_wipe_config_per_extruder[0]; + const bool mesh_overrides_extruder_retraction_and_wipe = ranges::all_of( + storage.retraction_wipe_config_per_extruder, + [&compare_with_first](const auto& config) + { + return retractAndWipeConfigIsSame(compare_with_first, config); + }); for (std::shared_ptr& mesh : storage.meshes) { retractionAndWipeConfigFromSettings(mesh->settings, &mesh->retraction_wipe_config); + mesh->override_extruder_retract_settings = mesh_overrides_extruder_retraction_and_wipe; } } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 2b17229c36..f9b881b1dd 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -355,16 +355,16 @@ GCodePath& LayerPlan::addTravel(const Point2LL& p, const bool force_retract, con { const GCodePathConfig& travel_config = configs_storage_.travel_config_per_extruder[getExtruder()]; - const RetractionConfig& retraction_config - = current_mesh_ ? current_mesh_->retraction_wipe_config.retraction_config : storage_.retraction_wipe_config_per_extruder[getExtruder()].retraction_config; + const RetractionConfig& retraction_config = current_mesh_ && current_mesh_->override_extruder_retract_settings + ? current_mesh_->retraction_wipe_config.retraction_config + : storage_.retraction_wipe_config_per_extruder[getExtruder()].retraction_config; GCodePath* path = getLatestPathWithConfig(travel_config, SpaceFillType::None, z_offset); bool combed = false; const ExtruderTrain* extruder = getLastPlannedExtruderTrain(); - const Settings& mesh_or_extruder_settings = current_mesh_ ? current_mesh_->settings : extruder->settings_; - + const Settings& mesh_or_extruder_settings = current_mesh_ && current_mesh_->override_extruder_retract_settings ? current_mesh_->settings : extruder->settings_; const bool is_first_travel_of_extruder_after_switch = extruder_plans_.back().paths_.size() == 1 && (extruder_plans_.size() > 1 || last_extruder_previous_layer_ != getExtruder()); @@ -2268,7 +2268,6 @@ void LayerPlan::writeGCode(GCodeExport& gcode) } } - gcode.setZ(z_); std::optional last_extrusion_config = std::nullopt; // used to check whether we need to insert a TYPE comment in the gcode. @@ -2284,8 +2283,9 @@ void LayerPlan::writeGCode(GCodeExport& gcode) { ExtruderPlan& extruder_plan = extruder_plans_[extruder_plan_idx]; - const RetractionAndWipeConfig* retraction_config - = current_mesh ? ¤t_mesh->retraction_wipe_config : &storage_.retraction_wipe_config_per_extruder[extruder_plan.extruder_nr_]; + const RetractionAndWipeConfig* retraction_config = current_mesh && current_mesh->override_extruder_retract_settings + ? ¤t_mesh->retraction_wipe_config + : &storage_.retraction_wipe_config_per_extruder[extruder_plan.extruder_nr_]; coord_t z_hop_height = retraction_config->retraction_config.zHop; if (extruder_nr != extruder_plan.extruder_nr_) @@ -2695,8 +2695,9 @@ void LayerPlan::writeGCode(GCodeExport& gcode) if (extruder.settings_.get("cool_lift_head") && extruder_plan.extra_time_ > 0.0) { gcode.writeComment("Small layer, adding delay"); - const RetractionAndWipeConfig& actual_retraction_config - = current_mesh ? current_mesh->retraction_wipe_config : storage_.retraction_wipe_config_per_extruder[gcode.getExtruderNr()]; + const RetractionAndWipeConfig& actual_retraction_config = current_mesh && current_mesh->override_extruder_retract_settings + ? current_mesh->retraction_wipe_config + : storage_.retraction_wipe_config_per_extruder[gcode.getExtruderNr()]; gcode.writeRetraction(actual_retraction_config.retraction_config); if (extruder_plan_idx == extruder_plans_.size() - 1 || ! extruder.settings_.get("machine_extruder_end_pos_abs")) { // only do the z-hop if it's the last extruder plan; otherwise it's already at the switching bay area