From 69077de9e09821a8dc50bb8fddce804126c6c50f Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:24:34 +0200 Subject: [PATCH 1/9] Only take used extruders in extruderValues() --- cura/BuildVolume.py | 29 ++++++++++++++++++++++- cura/Settings/CuraFormulaFunctions.py | 9 ++++--- resources/definitions/fdmprinter.def.json | 17 +++++++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 742d1872cb5..eeb4d957573 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -166,6 +166,7 @@ def _onSceneChangeTimerFinished(self): if active_extruder_changed is not None: node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild) node.decoratorsChanged.disconnect(self._updateNodeListeners) + self._updateUsedExtruders() self.rebuild() self._scene_objects = new_scene_objects @@ -202,7 +203,7 @@ def _updateNodeListeners(self, node: SceneNode): per_mesh_stack.propertyChanged.connect(self._onSettingPropertyChanged) active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal") if active_extruder_changed is not None: - active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild) + active_extruder_changed.connect(self._nodeActiveExtruderChanged) def setWidth(self, width: float) -> None: self._width = width @@ -687,6 +688,7 @@ def _onStackChangeTimerFinished(self) -> None: self._depth = self._global_container_stack.getProperty("machine_depth", "value") self._shape = self._global_container_stack.getProperty("machine_shape", "value") + self._updateUsedExtruders() self._updateDisallowedAreas() self._updateRaftThickness() self._extra_z_clearance = self._calculateExtraZClearance(ExtruderManager.getInstance().getUsedExtruderStacks()) @@ -713,6 +715,7 @@ def _onSettingChangeTimerFinished(self) -> None: update_disallowed_areas = False update_raft_thickness = False update_extra_z_clearance = True + update_used_extruders = False for setting_key in self._changed_settings_since_last_rebuild: if setting_key in ["print_sequence", "support_mesh", "infill_mesh", "cutting_mesh", "anti_overhang_mesh"]: @@ -746,12 +749,17 @@ def _onSettingChangeTimerFinished(self) -> None: if setting_key in self._raft_settings: update_raft_thickness = True + update_used_extruders = True if setting_key in self._extra_z_settings: update_extra_z_clearance = True if setting_key in self._limit_to_extruder_settings: update_disallowed_areas = True + update_used_extruders = True + + if setting_key in self._extruder_settings: + update_used_extruders = True rebuild_me = update_extra_z_clearance or update_disallowed_areas or update_raft_thickness @@ -765,6 +773,9 @@ def _onSettingChangeTimerFinished(self) -> None: if update_extra_z_clearance: self._extra_z_clearance = self._calculateExtraZClearance(ExtruderManager.getInstance().getUsedExtruderStacks()) + if update_used_extruders: + self._updateUsedExtruders() + if rebuild_me: self.rebuild() @@ -791,6 +802,22 @@ def _updateMachineSizeProperties(self) -> None: self._depth = self._global_container_stack.getProperty("machine_depth", "value") self._shape = self._global_container_stack.getProperty("machine_shape", "value") + def _updateUsedExtruders(self): + Logger.info("Updating used extruders") + global_container_stack = self._application.getGlobalContainerStack() + if not global_container_stack: + return + used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks() + for extruder in global_container_stack.extruderList: + used = extruder in used_extruders + Logger.info(f"- {extruder.getId()}: {used}") + changed = (used == extruder.getProperty("extruder_used", "value")) + extruder.setProperty("extruder_used", "value", used) + + def _nodeActiveExtruderChanged(self): + self._updateDisallowedAreasAndRebuild() + self._updateUsedExtruders() + def _updateDisallowedAreasAndRebuild(self): """Calls :py:meth:`cura.BuildVolume._updateDisallowedAreas` and makes sure the changes appear in the scene. diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index 93a4de28ec4..30d30317988 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -67,16 +67,19 @@ def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = N global_stack = machine_manager.activeMachine - result = [] + enabled_extruders = [] + used_extruders = [] for extruder in extruder_manager.getActiveExtruderStacks(): if not extruder.isEnabled: continue # only include values from extruders that are "active" for the current machine instance if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context): continue - result.append(extruder) + enabled_extruders.append(extruder) + if extruder.getProperty("extruder_used", "value"): + used_extruders.append(extruder) - return result + return used_extruders if used_extruders else enabled_extruders # Gets all extruder values as a list for the given property. def getValuesInAllExtruders(self, property_key: str, diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 571d5012126..758481ed12c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -289,6 +289,17 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "extruder_used": + { + "default_value": true, + "description": "Is this extruder used for printing. This setting is controlled by Cura automatically.", + "label": "Extruder Used", + "settable_globally": false, + "settable_per_extruder": true, + "settable_per_mesh": false, + "settable_per_meshgroup": false, + "type": "bool" + }, "machine_nozzle_tip_outer_diameter": { "label": "Outer Nozzle Diameter", @@ -2482,7 +2493,8 @@ "maximum_value_warning": "285", "enabled": "machine_heated_build_volume", "settable_per_mesh": false, - "settable_per_extruder": false + "settable_per_extruder": false, + "depends_on_settings": ["extruder_used"] }, "material_print_temperature": { @@ -2595,7 +2607,8 @@ "enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false + "settable_per_meshgroup": false, + "depends_on_settings": ["extruder_used"] }, "material_bed_temperature_layer_0": { From 1fab5b865a5af658501fc8a66c6b63321b7ed395 Mon Sep 17 00:00:00 2001 From: Frederic98 Date: Fri, 20 Sep 2024 07:25:44 +0000 Subject: [PATCH 2/9] Applied printer-linter format --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 758481ed12c..171b3fd4e8e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2494,7 +2494,7 @@ "enabled": "machine_heated_build_volume", "settable_per_mesh": false, "settable_per_extruder": false, - "depends_on_settings": ["extruder_used"] + "depends_on_settings": [ "extruder_used" ] }, "material_print_temperature": { @@ -2608,7 +2608,7 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false, - "depends_on_settings": ["extruder_used"] + "depends_on_settings": [ "extruder_used" ] }, "material_bed_temperature_layer_0": { From c482ced1c9f3509dfdd48a67e40dfe7eef267006 Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:25:53 +0200 Subject: [PATCH 3/9] Remove prime tower brim from used extruder check. The `prime_tower_brim_enable` setting does not make a brim anymore, but a flared base, and does not use the `skirt_brim_extruder_nr`. --- cura/Settings/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 3ce83d27e30..230858fe796 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -282,8 +282,8 @@ def getUsedExtruderStacks(self) -> List["ExtruderStack"]: adhesion_type = global_stack.getProperty("adhesion_type", "value") if adhesion_type == "skirt" and (global_stack.getProperty("skirt_line_count", "value") > 0 or global_stack.getProperty("skirt_brim_minimal_length", "value") > 0): used_adhesion_extruders.add("skirt_brim_extruder_nr") # There's a skirt. - if (adhesion_type == "brim" or global_stack.getProperty("prime_tower_brim_enable", "value")) and (global_stack.getProperty("brim_line_count", "value") > 0 or global_stack.getProperty("skirt_brim_minimal_length", "value") > 0): - used_adhesion_extruders.add("skirt_brim_extruder_nr") # There's a brim or prime tower brim. + if adhesion_type == "brim" and (global_stack.getProperty("brim_line_count", "value") > 0 or global_stack.getProperty("skirt_brim_minimal_length", "value") > 0): + used_adhesion_extruders.add("skirt_brim_extruder_nr") # There's a brim. if adhesion_type == "raft": used_adhesion_extruders.add("raft_base_extruder_nr") if global_stack.getProperty("raft_interface_layers", "value") > 0: From 97f35d8fe184d4615b3ae5f5d971052e7af2dc87 Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:04:48 +0200 Subject: [PATCH 4/9] Store `extruder_used` in the extruder's definitionChanges. To stop receiving the "discard or keep changes" popup. Same as `extruder_enabled_count`. --- cura/BuildVolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index eeb4d957573..f7b5a7108ed 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -812,7 +812,7 @@ def _updateUsedExtruders(self): used = extruder in used_extruders Logger.info(f"- {extruder.getId()}: {used}") changed = (used == extruder.getProperty("extruder_used", "value")) - extruder.setProperty("extruder_used", "value", used) + extruder.definitionChanges.setProperty("extruder_used", "value", used) def _nodeActiveExtruderChanged(self): self._updateDisallowedAreasAndRebuild() From 1bce2155646abfcf1bf6d09398fb36dd6addad26 Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:11:41 +0200 Subject: [PATCH 5/9] Remove debugging logs --- cura/BuildVolume.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index f7b5a7108ed..37c4c61a7ce 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -803,15 +803,12 @@ def _updateMachineSizeProperties(self) -> None: self._shape = self._global_container_stack.getProperty("machine_shape", "value") def _updateUsedExtruders(self): - Logger.info("Updating used extruders") global_container_stack = self._application.getGlobalContainerStack() if not global_container_stack: return used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks() for extruder in global_container_stack.extruderList: used = extruder in used_extruders - Logger.info(f"- {extruder.getId()}: {used}") - changed = (used == extruder.getProperty("extruder_used", "value")) extruder.definitionChanges.setProperty("extruder_used", "value", used) def _nodeActiveExtruderChanged(self): From b7f3108491d4d8be309ffa98a17a45fc5542f6fb Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:31:05 +0200 Subject: [PATCH 6/9] Fix setting relationships to update UI properly. --- cura/BuildVolume.py | 1 + resources/definitions/fdmextruder.def.json | 11 +++++++++++ resources/definitions/fdmprinter.def.json | 18 +++++++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 37c4c61a7ce..e9e1544afd3 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -810,6 +810,7 @@ def _updateUsedExtruders(self): for extruder in global_container_stack.extruderList: used = extruder in used_extruders extruder.definitionChanges.setProperty("extruder_used", "value", used) + global_container_stack.definitionChanges.setProperty("extruders_used", "value", [extruder.position for extruder in used_extruders]) def _nodeActiveExtruderChanged(self): self._updateDisallowedAreasAndRebuild() diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index a0fffeeaec0..c45256fb8ad 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -27,6 +27,17 @@ "settable_per_meshgroup": false, "type": "extruder" }, + "extruder_used": + { + "default_value": true, + "description": "Is this extruder used for printing. This setting is controlled by Cura automatically.", + "label": "Extruder Used", + "settable_globally": false, + "settable_per_extruder": true, + "settable_per_mesh": false, + "settable_per_meshgroup": false, + "type": "bool" + }, "extruder_prime_pos_z": { "default_value": 0, diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 171b3fd4e8e..92ab524741d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -289,16 +289,16 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, - "extruder_used": + "extruders_used": { - "default_value": true, - "description": "Is this extruder used for printing. This setting is controlled by Cura automatically.", - "label": "Extruder Used", - "settable_globally": false, - "settable_per_extruder": true, + "default_value": [], + "description": "A list of extruder positions that are used. This setting is controlled by Cura automatically.", + "label": "Extruders Used", + "settable_globally": true, + "settable_per_extruder": false, "settable_per_mesh": false, "settable_per_meshgroup": false, - "type": "bool" + "type": "[int]" }, "machine_nozzle_tip_outer_diameter": { @@ -2494,7 +2494,7 @@ "enabled": "machine_heated_build_volume", "settable_per_mesh": false, "settable_per_extruder": false, - "depends_on_settings": [ "extruder_used" ] + "depends_on_settings": [ "extruders_used" ] }, "material_print_temperature": { @@ -2608,7 +2608,7 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false, - "depends_on_settings": [ "extruder_used" ] + "depends_on_settings": [ "extruders_used" ] }, "material_bed_temperature_layer_0": { From af11d85ac95cbd564e877b262b0f58c238b7048c Mon Sep 17 00:00:00 2001 From: Frederic98 Date: Thu, 26 Sep 2024 09:36:40 +0000 Subject: [PATCH 7/9] Applied printer-linter format --- resources/definitions/fdmextruder.def.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index c45256fb8ad..cc445482e7e 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -27,17 +27,6 @@ "settable_per_meshgroup": false, "type": "extruder" }, - "extruder_used": - { - "default_value": true, - "description": "Is this extruder used for printing. This setting is controlled by Cura automatically.", - "label": "Extruder Used", - "settable_globally": false, - "settable_per_extruder": true, - "settable_per_mesh": false, - "settable_per_meshgroup": false, - "type": "bool" - }, "extruder_prime_pos_z": { "default_value": 0, @@ -50,6 +39,17 @@ "type": "float", "unit": "mm" }, + "extruder_used": + { + "default_value": true, + "description": "Is this extruder used for printing. This setting is controlled by Cura automatically.", + "label": "Extruder Used", + "settable_globally": false, + "settable_per_extruder": true, + "settable_per_mesh": false, + "settable_per_meshgroup": false, + "type": "bool" + }, "machine_extruder_cooling_fan_number": { "default_value": 0, From aac3077f9d04a2d3c0574fb98bdb4bae31044227 Mon Sep 17 00:00:00 2001 From: Frederic98 <13856291+Frederic98@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:19:20 +0200 Subject: [PATCH 8/9] Add filtering to `extruderValues()` --- cura/Settings/CuraFormulaFunctions.py | 26 ++++++++++++++++------- resources/definitions/fdmprinter.def.json | 24 +++++++++++++++------ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index 30d30317988..517226ef066 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Any, List, Optional, TYPE_CHECKING +from typing import Any, List, Optional, Union, TYPE_CHECKING from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext from UM.Settings.SettingFunction import SettingFunction @@ -61,14 +61,20 @@ def getValueInExtruder(self, extruder_position: int, property_key: str, return value - def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = None) -> List[str]: + def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = None, + where: Union[str, List[str]] = None, where_not: Union[str, List[str]] = None) -> List[str]: machine_manager = self._application.getMachineManager() extruder_manager = self._application.getExtruderManager() global_stack = machine_manager.activeMachine + if isinstance(where, str): + where = [where] + if isinstance(where_not, str): + where_not = [where_not] + enabled_extruders = [] - used_extruders = [] + filtered_extruders = [] for extruder in extruder_manager.getActiveExtruderStacks(): if not extruder.isEnabled: continue @@ -76,18 +82,22 @@ def _getActiveExtruders(self, context: Optional["PropertyEvaluationContext"] = N if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context): continue enabled_extruders.append(extruder) - if extruder.getProperty("extruder_used", "value"): - used_extruders.append(extruder) + if where and not all(extruder.getProperty(key, "value", context=context) for key in where): + continue + if where_not and any(extruder.getProperty(key, "value", context=context) for key in where_not): + continue + filtered_extruders.append(extruder) - return used_extruders if used_extruders else enabled_extruders + return filtered_extruders if filtered_extruders else enabled_extruders # Gets all extruder values as a list for the given property. def getValuesInAllExtruders(self, property_key: str, - context: Optional["PropertyEvaluationContext"] = None) -> List[Any]: + context: Optional["PropertyEvaluationContext"] = None, + *, where: str = None, where_not: str = None) -> List[Any]: global_stack = self._application.getMachineManager().activeMachine result = [] - for extruder in self._getActiveExtruders(context): + for extruder in self._getActiveExtruders(context, where=where, where_not=where_not): value = extruder.getRawProperty(property_key, "value", context = context) if value is None: diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 92ab524741d..17683b48b07 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -300,6 +300,18 @@ "settable_per_meshgroup": false, "type": "[int]" }, + "extruder_used": + { + "default_value": true, + "description": "Is this extruder used? This setting is controlled by Cura automatically.", + "label": "Extruder Used", + "settable_globally": false, + "settable_per_extruder": true, + "settable_per_mesh": false, + "settable_per_meshgroup": false, + "type": "bool", + "force_depends_on_settings": ["extruders_used"] + }, "machine_nozzle_tip_outer_diameter": { "label": "Outer Nozzle Diameter", @@ -2487,14 +2499,13 @@ "unit": "\u00b0C", "type": "float", "default_value": 0, - "resolve": "min(extruderValues('build_volume_temperature'))", + "resolve": "min(extruderValues('build_volume_temperature', where='extruder_used'))", "minimum_value": "-273.15", "minimum_value_warning": "0", "maximum_value_warning": "285", "enabled": "machine_heated_build_volume", "settable_per_mesh": false, - "settable_per_extruder": false, - "depends_on_settings": [ "extruders_used" ] + "settable_per_extruder": false }, "material_print_temperature": { @@ -2580,7 +2591,7 @@ "description": "The default temperature used for the heated build plate. This should be the \"base\" temperature of a build plate. All other print temperatures should use offsets based on this value", "unit": "\u00b0C", "type": "float", - "resolve": "max(extruderValues('default_material_bed_temperature'))", + "resolve": "max(extruderValues('default_material_bed_temperature', where='extruder_used'))", "default_value": 60, "minimum_value": "-273.15", "minimum_value_warning": "build_volume_temperature", @@ -2599,7 +2610,7 @@ "type": "float", "default_value": 60, "value": "default_material_bed_temperature", - "resolve": "max(extruderValues('material_bed_temperature'))", + "resolve": "max(extruderValues('material_bed_temperature', where='extruder_used'))", "minimum_value": "-273.15", "minimum_value_warning": "build_volume_temperature", "maximum_value_warning": "130", @@ -2607,8 +2618,7 @@ "enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "depends_on_settings": [ "extruders_used" ] + "settable_per_meshgroup": false }, "material_bed_temperature_layer_0": { From 3eb89d52b20a892bf9837396b10f0f67dd3b47ff Mon Sep 17 00:00:00 2001 From: Frederic98 Date: Fri, 27 Sep 2024 14:22:50 +0000 Subject: [PATCH 9/9] Applied printer-linter format --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 17683b48b07..f65a5a727fb 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -310,7 +310,7 @@ "settable_per_mesh": false, "settable_per_meshgroup": false, "type": "bool", - "force_depends_on_settings": ["extruders_used"] + "force_depends_on_settings": [ "extruders_used" ] }, "machine_nozzle_tip_outer_diameter": {