From 5e4e049c1f60d8fef670ddd53b84f0679cc21f5a Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 1 Mar 2018 20:57:15 -0600 Subject: [PATCH 01/10] Add definition for Printrbot Simple Maker's Kit 1405 The Printrbot Simple Maker's Kit, model 1405, was a low-cost FDM printer without a heated bed and a 10x10cm print area. The print area can be extended to 185x100mm with the "Printrbot Simple XL Upgrade with Spool Rack for Maker's Kit 1405". More information can be found at http://printrbot.com/project/simple-makers/ --- .../printrbot_simple_makers_kit.def.json | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 resources/definitions/printrbot_simple_makers_kit.def.json diff --git a/resources/definitions/printrbot_simple_makers_kit.def.json b/resources/definitions/printrbot_simple_makers_kit.def.json new file mode 100644 index 0000000000..61aecd9240 --- /dev/null +++ b/resources/definitions/printrbot_simple_makers_kit.def.json @@ -0,0 +1,39 @@ +{ + "version": 2, + "name": "Printrbot Simple Maker's Kit (1405)", + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Timur Tabi", + "manufacturer": "Printrbot", + "file_formats": "text/x-gcode", + "preferred_material": "*pla*" + }, + + "overrides": { + "machine_name": { "default_value": "Printrbot Simple Maker's Kit (1405)" }, + "machine_heated_bed": { "default_value": false }, + "machine_width": { "default_value": 100 }, + "machine_depth": { "default_value": 100 }, + "machine_height": { "default_value": 115 }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "machine_head_with_fans_polygon": { + "default_value": [ + [-40, 1000], + [-40, -10], + [60, 1000], + [60, -10] + ] + }, + "gantry_height": { "default_value": 1000 }, + "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, + + "machine_start_gcode": { + "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence" + }, + "machine_end_gcode": { + "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" + } + } +} From 3cefacdfccf78222959b8d76ad70502969dd4cfa Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 09:28:33 +0100 Subject: [PATCH 02/10] Remove root_material_nod is None check in MaterialManager CURA-5056 This will no longer happen. --- cura/Machines/MaterialManager.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 61b8bcd8e6..0a82fcc764 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -101,13 +101,6 @@ class MaterialManager(QObject): # GUID -> material group list self._guid_material_groups_map = defaultdict(list) for root_material_id, material_group in self._material_group_map.items(): - # This can happen when we are updating with incomplete data. - if material_group.root_material_node is None: - Logger.log("e", "Missing root material node for [%s]. Probably caused by update using incomplete data." - " Check all related signals for further debugging.", - material_group.name) - self._update_timer.start() - return guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) From 7ebd83f81527f157d679bd564a013a1811b2888f Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 10:21:10 +0100 Subject: [PATCH 03/10] CURA-4400 get setting type from definition instead of whole stack improves speed of this call by a factor of 10 --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index f3f34f4c3d..96124a3514 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -281,7 +281,7 @@ class StartSliceJob(Job): default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition) result = {} for key in stack.getAllKeys(): - setting_type = stack.getProperty(key, "type") + setting_type = stack.definition.getProperty(key, "type") value = stack.getProperty(key, "value") if setting_type == "extruder" and value == -1: # replace with the default value From dc427488a26fe829f8d55ca186d1b19ac02fee75 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:29:48 +0100 Subject: [PATCH 04/10] Fix extruder position check in project loading CURA-5056 The field is now "position" instead of "extruder" --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 3c627a7655..c943fcd879 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -754,15 +754,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_containers = self._container_registry.findInstanceContainers(name = quality_changes_name, type = "quality_changes") for container in quality_changes_containers: - extruder_definition_id = container.getMetaDataEntry("extruder") - if not extruder_definition_id: + extruder_position = container.getMetaDataEntry("position") + if extruder_position is None: quality_changes_info.global_info.container = container else: - extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] - position = extruder_definition_metadata["position"] - if position not in quality_changes_info.extruder_info_dict: - quality_changes_info.extruder_info_dict[position] = ContainerInfo(None, None, None) - container_info = quality_changes_info.extruder_info_dict[position] + if extruder_position not in quality_changes_info.extruder_info_dict: + quality_changes_info.extruder_info_dict[extruder_position] = ContainerInfo(None, None, None) + container_info = quality_changes_info.extruder_info_dict[extruder_position] container_info.container = container # If there is no quality changes for any extruder, create one. From 86afd6f5ff3d8d8f77d325ee80068c0fc08a90ac Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:32:53 +0100 Subject: [PATCH 05/10] Do not overwrite existing metadata with in material deserializeMetadata() CURA-5056 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 8 ++--- .../XmlMaterialProfile/XmlMaterialProfile.py | 36 +++++++------------ 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index c943fcd879..19e6b89f07 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -265,13 +265,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): for material_container_file in material_container_files: container_id = self._stripFileToId(material_container_file) - from hashlib import sha1 - hex_container_id = sha1(container_id.encode('utf-8')).hexdigest() - serialized = archive.open(material_container_file).read().decode("utf-8") - metadata_list = xml_material_profile.deserializeMetadata(serialized, hex_container_id) - reverse_map = {metadata["id"].replace(hex_container_id, container_id): container_id.replace(hex_container_id, container_id) - for metadata in metadata_list} + metadata_list = xml_material_profile.deserializeMetadata(serialized, container_id) + reverse_map = {metadata["id"]: container_id for metadata in metadata_list} reverse_material_id_dict.update(reverse_map) material_labels.append(self._getMaterialLabelFromSerialized(serialized)) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 333e2546b0..8b17721794 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -838,15 +838,11 @@ class XmlMaterialProfile(InstanceContainer): if machine_compatibility: new_material_id = container_id + "_" + machine_id - # The child or derived material container may already exist. This can happen when a material in a - # project file and the a material in Cura have the same ID. - # In the case if a derived material already exists, override that material container because if - # the data in the parent material has been changed, the derived ones should be updated too. - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id) - if found_materials: - new_material_metadata = found_materials[0] - else: - new_material_metadata = {} + # Do not look for existing container/container metadata with the same ID although they may exist. + # In project loading and perhaps some other places, we only want to get information (metadata) + # from a file without changing the current state of the system. If we overwrite the existing + # metadata here, deserializeMetadata() will not be safe for retrieving information. + new_material_metadata = {} new_material_metadata.update(base_metadata) new_material_metadata["id"] = new_material_id @@ -854,8 +850,7 @@ class XmlMaterialProfile(InstanceContainer): new_material_metadata["machine_manufacturer"] = machine_manufacturer new_material_metadata["definition"] = machine_id - if len(found_materials) == 0: #This is a new material. - result_metadata.append(new_material_metadata) + result_metadata.append(new_material_metadata) buildplates = machine.iterfind("./um:buildplate", cls.__namespaces) buildplate_map = {} @@ -866,12 +861,12 @@ class XmlMaterialProfile(InstanceContainer): if buildplate_id is None: continue - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) - if not variant_containers: + variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) + if not variant_metadata: # It is not really properly defined what "ID" is so also search for variants by name. - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) + variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) - if not variant_containers: + if not variant_metadata: continue settings = buildplate.iterfind("./um:setting", cls.__namespaces) @@ -900,12 +895,8 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_specific_material_id = container_id + "_" + machine_id + "_" + hotend_name.replace(" ", "_") - # Same as machine compatibility, keep the derived material containers consistent with the parent material - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_specific_material_id) - if found_materials: - new_hotend_material_metadata = found_materials[0] - else: - new_hotend_material_metadata = {} + # Same as above, do not overwrite existing metadata. + new_hotend_material_metadata = {} new_hotend_material_metadata.update(base_metadata) new_hotend_material_metadata["variant_name"] = hotend_name @@ -917,8 +908,7 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_material_metadata["buildplate_compatible"] = buildplate_map["buildplate_compatible"] new_hotend_material_metadata["buildplate_recommended"] = buildplate_map["buildplate_recommended"] - if len(found_materials) == 0: - result_metadata.append(new_hotend_material_metadata) + result_metadata.append(new_hotend_material_metadata) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue From cff1e8639dd2b0b12c628be7d513ee530cb8cf6a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:47:58 +0100 Subject: [PATCH 06/10] Fix preferred material PLA for printrbot simple makers kit CURA-5089 --- resources/definitions/printrbot_simple_makers_kit.def.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/definitions/printrbot_simple_makers_kit.def.json b/resources/definitions/printrbot_simple_makers_kit.def.json index 61aecd9240..e2afd57826 100644 --- a/resources/definitions/printrbot_simple_makers_kit.def.json +++ b/resources/definitions/printrbot_simple_makers_kit.def.json @@ -6,8 +6,7 @@ "visible": true, "author": "Timur Tabi", "manufacturer": "Printrbot", - "file_formats": "text/x-gcode", - "preferred_material": "*pla*" + "file_formats": "text/x-gcode" }, "overrides": { From 4a16d04dd79fe8639f8381d44297e0bf3f74e8de Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 14 Mar 2018 10:50:54 +0100 Subject: [PATCH 07/10] CURA-5053 Changed printer type checking "Still hard coded but at least doesn't use `elif` because `elif`/`else if` should not exist in any programming language." - Grumpy Pedants & Ian >:[ --- .../PrinterOutput/NetworkedPrinterOutputDevice.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index a4934b7f74..eefbd9ae12 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -56,12 +56,15 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._connection_state_before_timeout = None # type: Optional[ConnectionState] printer_type = self._properties.get(b"machine", b"").decode("utf-8") - if printer_type.startswith("9511"): - self._printer_type = "ultimaker3_extended" - elif printer_type.startswith("9066"): - self._printer_type = "ultimaker3" - else: - self._printer_type = "unknown" + printer_type_identifiers = { + "9066": "ultimaker3", + "9511": "ultimaker3_extended" + } + self._printer_type = "Unknown" + for key, value in printer_type_identifiers.items(): + if printer_type.startswith(key): + self._printer_type = value + break def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs) -> None: raise NotImplementedError("requestWrite needs to be implemented") From f5f8bf19ecdd0e463b8eb3626639637cfd76e8d8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 11:05:32 +0100 Subject: [PATCH 08/10] Fix QML warnings --- resources/qml/SidebarHeader.qml | 7 ++++++- resources/qml/WorkspaceSummaryDialog.qml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 74e189789d..dcb351e866 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -347,7 +347,8 @@ Column id: materialSelection property var activeExtruder: Cura.MachineManager.activeStack - property var currentRootMaterialName: activeExtruder.material.name + property var hasActiveExtruder: activeExtruder != null + property var currentRootMaterialName: hasActiveExtruder ? activeExtruder.material.name : "" text: currentRootMaterialName tooltip: currentRootMaterialName @@ -366,6 +367,10 @@ Column property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported function isMaterialSupported () { + if (!hasActiveExtruder) + { + return false; + } return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible") == "True" } } diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index 12eba13dd9..cf19e45fdd 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -101,7 +101,7 @@ UM.Dialog } Label { - text: Cura.MachineManager.activeMachine.definition.name + text: (Cura.MachineManager.activeMachine == null) ? "" : Cura.MachineManager.activeMachine.definition.name width: (parent.width / 3) | 0 } } From 9f40e3925dcb02028fee554a78cdadf52ac4f47e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 11:07:38 +0100 Subject: [PATCH 09/10] CURA-5090 added timer to SettingInheritanceManager._update --- cura/Settings/SettingInheritanceManager.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cura/Settings/SettingInheritanceManager.py b/cura/Settings/SettingInheritanceManager.py index 0d4cd02cdb..e317b20f68 100644 --- a/cura/Settings/SettingInheritanceManager.py +++ b/cura/Settings/SettingInheritanceManager.py @@ -1,7 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal +from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal from UM.FlameProfiler import pyqtSlot from UM.Application import Application from UM.Logger import Logger @@ -30,6 +30,11 @@ class SettingInheritanceManager(QObject): ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) self._onActiveExtruderChanged() + self._update_timer = QTimer() + self._update_timer.setInterval(500) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) + settingsWithIntheritanceChanged = pyqtSignal() ## Get the keys of all children settings with an override. @@ -226,9 +231,7 @@ class SettingInheritanceManager(QObject): self._onActiveExtruderChanged() def _onContainersChanged(self, container): - # TODO: Multiple container changes in sequence now cause quite a few recalculations. - # This isn't that big of an issue, but it could be in the future. - self._update() + self._update_timer.start() @staticmethod def createSettingInheritanceManager(engine=None, script_engine=None): From 8dd2243399b509858c7b0753c4cb11a94ca4cf3e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 14 Mar 2018 11:32:36 +0100 Subject: [PATCH 10/10] Fixed stupid mistake that made all snapshots be taken from the back of model --- cura/Snapshot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Snapshot.py b/cura/Snapshot.py index afc8818116..1f2a24aecd 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -66,7 +66,7 @@ class Snapshot: size = max(bbox.width, bbox.height, bbox.depth * 0.5) # Looking from this direction (x, y, z) in OGL coordinates - looking_from_offset = Vector(1, 1, -2) + looking_from_offset = Vector(-1, 1, 2) if size > 0: # determine the watch distance depending on the size looking_from_offset = looking_from_offset * size * 1.3