From 2828f45e8993fb1d03ac9350aa8edc2530139b9f Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 10 Aug 2020 14:49:41 +0200 Subject: [PATCH 1/6] Add optional machine_extruder_count when creating a machine If the machine_extruder_count is not taken into consideration on machine creation, calling the extruderList of that machine will return an incomplete list of extruders (since it considers the default machine_extruder_count). This causes problems in machines with settable number of extruders where the default machine_extruder_count is 1 while the machine may have more than 1 extruders. The problem becomes especially visible when opening a project file with e.g. a CFFF with multiple extruders, because when the machine is created we do not know yet how many extruders the printer actually has. CURA-7646 --- cura/Settings/CuraStackBuilder.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index aadfd15f1a..77d723cc72 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -16,13 +16,13 @@ from .ExtruderStack import ExtruderStack class CuraStackBuilder: """Contains helper functions to create new machines.""" - @classmethod - def createMachine(cls, name: str, definition_id: str) -> Optional[GlobalStack]: + def createMachine(cls, name: str, definition_id: str, machine_extruder_count: Optional[int] = None) -> Optional[GlobalStack]: """Create a new instance of a machine. :param name: The name of the new machine. :param definition_id: The ID of the machine definition to use. + :param machine_extruder_count: The number of extruders in the machine. :return: The new global stack or None if an error occurred. """ @@ -66,7 +66,14 @@ class CuraStackBuilder: Logger.logException("e", "Failed to create an extruder stack for position {pos}: {err}".format(pos = position, err = str(e))) return None - for new_extruder in new_global_stack.extruderList: # Only register the extruders if we're sure that all of them are correct. + # If given, set the machine_extruder_count when creating the machine, or else the extruderList used bellow will + # not return the correct extruder list (since by default, the machine_extruder_count is 1) in machines with + # settable number of extruders. See CURA-7646. + if machine_extruder_count and 0 <= machine_extruder_count <= len(extruder_dict): + new_global_stack.setProperty("machine_extruder_count", "value", machine_extruder_count) + + # Only register the extruders if we're sure that all of them are correct. + for new_extruder in new_global_stack.extruderList: registry.addContainer(new_extruder) # Register the global stack after the extruder stacks are created. This prevents the registry from adding another From b9d5f0dc152cdf2e6548e72c0c4dd46d250b008b Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 10 Aug 2020 14:56:37 +0200 Subject: [PATCH 2/6] Take the machine_extruder_count into consideration when opening project CURA-7646 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 9abab88e6a..54a0b17bda 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -663,7 +663,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # We need to create a new machine machine_name = self._container_registry.uniqueName(self._machine_info.name) - global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id) + # Printers with modifiable number of extruders (such as CFFF) will specify a machine_extruder_count in their + # quality_changes file. If that's the case, take the extruder count into account when creating the machine + # or else the extruderList will return only the first extruder, leading to missing non-global settings in + # the other extruders. See CURA-7646 + machine_extruder_count = self._getMachineExtruderCount() # type: Optional[int] + global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id, machine_extruder_count) if global_stack: # Only switch if creating the machine was successful. extruder_stack_dict = {str(position): extruder for position, extruder in enumerate(global_stack.extruderList)} @@ -918,6 +923,24 @@ class ThreeMFWorkspaceReader(WorkspaceReader): self._machine_info.quality_changes_info.name = quality_changes_name + def _getMachineExtruderCount(self) -> Optional[int]: + """ + Extracts the machine extruder count from the definition_changes file of the printer. If it is not specified in + the file, None is returned instead. + + :return: The count of the machine's extruders + """ + machine_extruder_count = None + if self._machine_info.definition_changes_info \ + and "values" in self._machine_info.definition_changes_info.parser \ + and "machine_extruder_count" in self._machine_info.definition_changes_info.parser["values"]: + try: + machine_extruder_count = int(self._machine_info.definition_changes_info.parser["values"]["machine_extruder_count"]) + except ValueError: + Logger.log("w", "'machine_extruder_count' in file '{file_name}' is not a number." + .format(file_name = self._machine_info.definition_changes_info.file_name)) + return machine_extruder_count + def _createNewQualityChanges(self, quality_type: str, intent_category: Optional[str], name: str, global_stack: GlobalStack, extruder_stack: Optional[ExtruderStack]) -> InstanceContainer: """Helper class to create a new quality changes profile. From 61cc8c9a95ba78e660b045035dcf18fbfb945dd5 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 10 Aug 2020 14:58:59 +0200 Subject: [PATCH 3/6] Remove reference to JIRA ticket in comments CURA-7646 --- cura/Settings/CuraStackBuilder.py | 2 +- plugins/3MFReader/ThreeMFWorkspaceReader.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 77d723cc72..efc447b2cf 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -68,7 +68,7 @@ class CuraStackBuilder: # If given, set the machine_extruder_count when creating the machine, or else the extruderList used bellow will # not return the correct extruder list (since by default, the machine_extruder_count is 1) in machines with - # settable number of extruders. See CURA-7646. + # settable number of extruders. if machine_extruder_count and 0 <= machine_extruder_count <= len(extruder_dict): new_global_stack.setProperty("machine_extruder_count", "value", machine_extruder_count) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 54a0b17bda..49173d4864 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -666,7 +666,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Printers with modifiable number of extruders (such as CFFF) will specify a machine_extruder_count in their # quality_changes file. If that's the case, take the extruder count into account when creating the machine # or else the extruderList will return only the first extruder, leading to missing non-global settings in - # the other extruders. See CURA-7646 + # the other extruders. machine_extruder_count = self._getMachineExtruderCount() # type: Optional[int] global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id, machine_extruder_count) if global_stack: # Only switch if creating the machine was successful. From f8a15ea29e9cc0cbff23805b33a5d0f3de0fb775 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 10 Aug 2020 15:00:08 +0200 Subject: [PATCH 4/6] Display only the relevant materials when opening a project Ignore the materials of the extruders that are not visible when opening a project file with a CFFF. CURA-7646 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 49173d4864..b775d0055c 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -502,6 +502,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Now we know which material is in which extruder. Let's use that to sort the material_labels according to # their extruder position material_labels = [material_name for pos, material_name in sorted(materials_in_extruders_dict.items())] + machine_extruder_count = self._getMachineExtruderCount() + if machine_extruder_count: + material_labels = material_labels[:machine_extruder_count] num_visible_settings = 0 try: From 0feeccff85c586f5983054e48490404d966db7b5 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 10 Aug 2020 15:30:55 +0200 Subject: [PATCH 5/6] Appease mypy complaints for AttributeErrors CURA-7646 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index b775d0055c..0c1bd0a9a2 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -934,7 +934,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): :return: The count of the machine's extruders """ machine_extruder_count = None - if self._machine_info.definition_changes_info \ + if self._machine_info \ + and self._machine_info.definition_changes_info \ and "values" in self._machine_info.definition_changes_info.parser \ and "machine_extruder_count" in self._machine_info.definition_changes_info.parser["values"]: try: From 01d5e846aa62c12a709f91d66df54f029f4bf323 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Tue, 11 Aug 2020 12:37:34 +0200 Subject: [PATCH 6/6] Document possible theoretical issue when loading a project file The issue will happen only if the machine_extruder_count is a formula. In this case, the project loading will not work properly if "Create new" printer is selected, as the settings of all extruders but the first one will not be applied. Workaround in this case will be to load the project again and select to update the existing printer, in which case all settings will load properly. CURA-7646 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 0c1bd0a9a2..6ed35fe72c 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -939,6 +939,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader): and "values" in self._machine_info.definition_changes_info.parser \ and "machine_extruder_count" in self._machine_info.definition_changes_info.parser["values"]: try: + # Theoretically, if the machine_extruder_count is a setting formula (e.g. "=3"), this will produce a + # value error and the project file loading will load the settings in the first extruder only. + # This is not expected to happen though, since all machine definitions define the machine_extruder_count + # as an integer. machine_extruder_count = int(self._machine_info.definition_changes_info.parser["values"]["machine_extruder_count"]) except ValueError: Logger.log("w", "'machine_extruder_count' in file '{file_name}' is not a number."