From 13fd588451a29de4dccfc5da33d122663ea3712b Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 14 Jun 2016 15:47:29 +0200 Subject: [PATCH 01/80] =?UTF-8?q?JSON=20fix:=20unit=20of=20jerk:=20mm/s?= =?UTF-8?q?=C2=B3=20=3D=3D>=20mm/s=20(CURA-1646)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/definitions/fdmprinter.def.json | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6e6474053f..5ede74aac7 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1512,7 +1512,7 @@ "jerk_print": { "label": "Print Jerk", "description": "The maximal allowed jerk of the print head when starting to move or when changing direction.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1524,7 +1524,7 @@ "jerk_infill": { "label": "Infill Jerk", "description": "The jerk with which infill is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1537,7 +1537,7 @@ "jerk_wall": { "label": "Wall Jerk", "description": "The jerk with which the walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1550,7 +1550,7 @@ "jerk_wall_0": { "label": "Outer Wall Jerk", "description": "The jerk with which the outermost walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1563,7 +1563,7 @@ "jerk_wall_x": { "label": "Inner Wall Jerk", "description": "The jerk with which all inner walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1578,7 +1578,7 @@ "jerk_topbottom": { "label": "Top/Bottom Jerk", "description": "The jerk with which top/bottom layers are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1591,7 +1591,7 @@ "jerk_support": { "label": "Support Jerk", "description": "The jerk with which the support structure is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1605,7 +1605,7 @@ "jerk_support_infill": { "label": "Support Infill Jerk", "description": "The jerk with which the infill of support is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_support", @@ -1619,7 +1619,7 @@ "jerk_support_roof": { "label": "Support Roof Jerk", "description": "The jerk with which the roofs of support are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_support", @@ -1635,7 +1635,7 @@ "jerk_prime_tower": { "label": "Prime Tower Jerk", "description": "The jerk with which the prime tower is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1650,7 +1650,7 @@ "jerk_travel": { "label": "Travel Jerk", "description": "The jerk with which travel moves are made.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 30, "minimum_value": "0.1", @@ -1663,7 +1663,7 @@ "jerk_layer_0": { "label": "Initial Layer Jerk", "description": "The print jerk for the initial layer.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_print", @@ -1676,7 +1676,7 @@ "jerk_skirt": { "label": "Skirt Jerk", "description": "The jerk with which the skirt and brim are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "minimum_value": "0.1", @@ -2599,7 +2599,7 @@ "raft_jerk": { "label": "Raft Print Jerk", "description": "The jerk with which the raft is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "minimum_value": "0.1", @@ -2612,7 +2612,7 @@ "raft_surface_jerk": { "label": "Raft Top Print Jerk", "description": "The jerk with which the top raft layers are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", @@ -2625,7 +2625,7 @@ "raft_interface_jerk": { "label": "Raft Middle Print Jerk", "description": "The jerk with which the middle raft layer is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", @@ -2638,7 +2638,7 @@ "raft_base_jerk": { "label": "Raft Base Print Jerk", "description": "The jerk with which the base raft layer is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", From 12915870017588aa3d3f56956e1c639eba18fe2f Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 14 Jun 2016 17:06:46 +0200 Subject: [PATCH 02/80] JSON feat: firmware acceleration and jerk settings for ultimaker printers (CURA-1646) --- resources/definitions/fdmprinter.def.json | 131 ++++++++++++++++++ resources/definitions/ultimaker2.def.json | 15 ++ .../ultimaker_original_plus.def.json | 3 + 3 files changed, 149 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 5ede74aac7..f7acaf36b7 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -303,6 +303,137 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false + }, + + "machine_max_feedrate_x": { + "label": "Maximum Speed X", + "description": "The maximum speed for the motor of the X-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 500, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_y": { + "label": "Maximum Speed Y", + "description": "The maximum speed for the motor of the Y-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 500, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_z": { + "label": "Maximum Speed Z", + "description": "The maximum speed for the motor of the Z-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 5, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_e": { + "label": "Maximum Feedrate", + "description": "The maximum speed of the filament.", + "unit": "mm/s", + "type": "float", + "default_value": 25, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_x": { + "label": "Maximum Acceleration X", + "description": "Maximum acceleration for the motor of the X-direction", + "unit": "mm/s²", + "type": "float", + "default_value": 9000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_y": { + "label": "Maximum Acceleration Y", + "description": "Maximum acceleration for the motor of the Y-direction.", + "unit": "mm/s²", + "type": "float", + "default_value": 9000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_z": { + "label": "Maximum Acceleration Z", + "description": "Maximum acceleration for the motor of the Z-direction.", + "unit": "mm/s²", + "type": "float", + "default_value": 100, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_e": { + "label": "Maximum Filament Acceleration", + "description": "Maximum acceleration for the motor of the filament.", + "unit": "mm/s²", + "type": "float", + "default_value": 10000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_acceleration": { + "label": "Default Acceleration", + "description": "The default acceleration of print head movement.", + "unit": "mm/s²", + "type": "float", + "default_value": 4000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_xy": { + "label": "Default X-Y Jerk", + "description": "Default jerk for movement in the horizontal plane.", + "unit": "mm/s", + "type": "float", + "default_value": 20.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_z": { + "label": "Default Z Jerk", + "description": "Default jerk for the motor of the Z-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 0.4, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_e": { + "label": "Default Filament Jerk", + "description": "Default jerk for the motor of the filament.", + "unit": "mm/s", + "type": "float", + "default_value": 5.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_minimum_feedrate": { + "label": "Minimum Feedrate", + "description": "The minimal movement speed of the print head.", + "unit": "mm/s", + "type": "float", + "default_value": 0.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } }, diff --git a/resources/definitions/ultimaker2.def.json b/resources/definitions/ultimaker2.def.json index 7b2222e5b3..a1ffcc8226 100644 --- a/resources/definitions/ultimaker2.def.json +++ b/resources/definitions/ultimaker2.def.json @@ -86,6 +86,21 @@ "material_bed_temperature": { "enabled": "False" }, + "machine_max_feedrate_x": { + "default_value": 300 + }, + "machine_max_feedrate_y": { + "default_value": 300 + }, + "machine_max_feedrate_z": { + "default_value": 40 + }, + "machine_max_feedrate_e": { + "default_value": 45 + }, + "machine_acceleration": { + "default_value": 3000 + }, "material_diameter": { "enabled": "False" }, diff --git a/resources/definitions/ultimaker_original_plus.def.json b/resources/definitions/ultimaker_original_plus.def.json index 830050beb0..e4bb24ec6f 100644 --- a/resources/definitions/ultimaker_original_plus.def.json +++ b/resources/definitions/ultimaker_original_plus.def.json @@ -21,6 +21,9 @@ "overrides": { "machine_heated_bed": { "default_value": true + }, + "machine_max_feedrate_z": { + "default_value": 30 } } } From c67d2faac36ff369c6777a429230f3b665260f93 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sun, 3 Jul 2016 14:39:16 +0200 Subject: [PATCH 03/80] CuraEngineBackend: Keep the last 200 lines of logged messages Don't know how much lines we will need exactly, but I think 200 are enough for the moment. Contributes to CURA-1775 --- plugins/CuraEngineBackend/CuraEngineBackend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index c91e414a13..4ab7857376 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -89,6 +89,7 @@ class CuraEngineBackend(Backend): self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness. self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers. + self._backend_log_max_lines = 200 # Maximal count of lines to buffer self._error_message = None #Pop-up message that shows errors. self.backendQuit.connect(self._onBackendQuit) From b5aa7c35455c6e37d7dfc1bcb96af1e296bdd2d8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 12 Jul 2016 10:34:58 +0200 Subject: [PATCH 04/80] Remove the extruder id from settingoverride decorator if the machine does not have multi extrusion CURA-1876 & CURA-1768 --- plugins/PerObjectSettingsTool/PerObjectSettingsTool.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 8b51852c15..b5c4c0f22c 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -3,10 +3,12 @@ from UM.Tool import Tool from UM.Scene.Selection import Selection +from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Application import Application from UM.Preferences import Preferences from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator + ## This tool allows the user to add & change settings per node in the scene. # The settings per object are kept in a ContainerStack, which is linked to a node by decorator. class PerObjectSettingsTool(Tool): @@ -69,6 +71,11 @@ class PerObjectSettingsTool(Tool): global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: self._multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1 + if not self._multi_extrusion: + # Ensure that all extruder data is reset + root_node = Application.getInstance().getController().getScene().getRoot() + for node in DepthFirstIterator(root_node): + node.callDecoration("setActiveExtruder", global_container_stack.getId()) self._updateEnabled() def _updateEnabled(self): From ae4beeb0ed71a64d55f7a482690ec153856a3e7e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 12 Jul 2016 10:53:50 +0200 Subject: [PATCH 05/80] Remove container stack and user profile for extruders when removing a printer CURA-1896 --- cura/Settings/ExtruderManager.py | 13 ++++++++++++- cura/Settings/MachineManager.py | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 5062fc93b4..775596104b 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -221,7 +221,18 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - ## Generates extruders for a specific machine. + ## Removes the container stack and user profile for the extruders for a specific machine. + # + # \param machine_id The machine to remove the extruders for. + def removeMachineExtruders(self, machine_id): + for extruder in self.getMachineExtruders(machine_id): + current_settings_id = extruder.getId() + "_current_settings" + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id) + for container in containers: + UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId()) + UM.Settings.ContainerRegistry.getInstance().removeContainer(extruder.getId()) + + ## Returns extruders for a specific machine. # # \param machine_id The machine to get the extruders of. def getMachineExtruders(self, machine_id): diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f670bf2bf2..cb761032d8 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -635,6 +635,11 @@ class MachineManager(QObject): # If the machine that is being removed is the currently active machine, set another machine as the active machine. activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) + stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) + if not stacks: + return + ExtruderManager.getInstance().removeMachineExtruders(stacks[0].getBottom().getId()) + current_settings_id = machine_id + "_current_settings" containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id) for container in containers: From 64ecb114b86f663ea096054e108db43b1867bfd6 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 12 Jul 2016 12:10:07 +0200 Subject: [PATCH 06/80] Store the Quality profile for the 'global' and extruders in the gcode. Read in all of the quality profile during import. Contributes to CURA-1727 GCode Profile reading/writing: Broken and needs update --- cura/ProfileReader.py | 2 +- cura/Settings/CuraContainerRegistry.py | 45 +++++++++++------ .../CuraProfileReader/CuraProfileReader.py | 1 - .../GCodeProfileReader/GCodeProfileReader.py | 49 ++++++++++++------- plugins/GCodeWriter/GCodeWriter.py | 33 ++++++++----- 5 files changed, 84 insertions(+), 46 deletions(-) diff --git a/cura/ProfileReader.py b/cura/ProfileReader.py index 36bb2c7177..266abd50a4 100644 --- a/cura/ProfileReader.py +++ b/cura/ProfileReader.py @@ -12,6 +12,6 @@ class ProfileReader(PluginObject): ## Read profile data from a file and return a filled profile. # - # \return \type{Profile} The profile that was obtained from the file. + # \return \type{Profile|Profile[]} The profile that was obtained from the file or a list of Profiles. def read(self, file_name): raise NotImplementedError("Profile reader plug-in was not correctly implemented. The read function was not implemented.") \ No newline at end of file diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index af7ca2e87e..990143f7bb 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -133,32 +133,45 @@ class CuraContainerRegistry(ContainerRegistry): for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: - profile = profile_reader.read(file_name) #Try to open the file with the profile reader. + profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from {0}: {1}", file_name, str(e))} - if profile: #Success! - profile.setReadOnly(False) - - new_name = self.createUniqueName("quality", "", os.path.splitext(os.path.basename(file_name))[0], - catalog.i18nc("@label", "Custom profile")) - profile.setName(new_name) - profile._id = new_name - - if self._machineHasOwnQualities(): - profile.setDefinition(self._activeDefinition()) - if self._machineHasOwnMaterials(): - profile.addMetaDataEntry("material", self._activeMaterialId()) + if profile_or_list: # Success! + name_seed = os.path.splitext(os.path.basename(file_name))[0] + if type(profile_or_list) is not list: + profile = profile_or_list + self._configureProfile(profile, name_seed) + return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: - profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0]) - ContainerRegistry.getInstance().addContainer(profile) + for profile in profile_or_list: + self._configureProfile(profile, name_seed) - return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } + if len(profile_or_list) == 1: + return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())} + else: + profile_names = ", ".join([profile.getName() for profile in profile_or_list]) + return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)} + def _configureProfile(self, profile, name_seed): + profile.setReadOnly(False) + + new_name = self.createUniqueName("quality", "", name_seed, catalog.i18nc("@label", "Custom profile")) + profile.setName(new_name) + profile._id = new_name + + if self._machineHasOwnQualities(): + profile.setDefinition(self._activeDefinition()) + if self._machineHasOwnMaterials(): + profile.addMetaDataEntry("material", self._activeMaterialId()) + else: + profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0]) + ContainerRegistry.getInstance().addContainer(profile) + ## Gets a list of profile writer plugins # \return List of tuples of (plugin_id, meta_data). def _getIOPlugins(self, io_type): diff --git a/plugins/CuraProfileReader/CuraProfileReader.py b/plugins/CuraProfileReader/CuraProfileReader.py index b9c1f208ea..261e68a26b 100644 --- a/plugins/CuraProfileReader/CuraProfileReader.py +++ b/plugins/CuraProfileReader/CuraProfileReader.py @@ -3,7 +3,6 @@ import os.path -from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Logger import Logger from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make. from cura.ProfileReader import ProfileReader diff --git a/plugins/GCodeProfileReader/GCodeProfileReader.py b/plugins/GCodeProfileReader/GCodeProfileReader.py index 1e649b7dd4..24c92d08e9 100644 --- a/plugins/GCodeProfileReader/GCodeProfileReader.py +++ b/plugins/GCodeProfileReader/GCodeProfileReader.py @@ -1,10 +1,9 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -import os import re #Regular expressions for parsing escape characters in the settings. +import json -from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Settings.InstanceContainer import InstanceContainer from UM.Logger import Logger from UM.i18n import i18nCatalog @@ -22,7 +21,7 @@ class GCodeProfileReader(ProfileReader): # It can only read settings with the same version as the version it was # written with. If the file format is changed in a way that breaks reverse # compatibility, increment this version number! - version = 2 + version = 3 ## Dictionary that defines how characters are escaped when embedded in # g-code. @@ -66,21 +65,37 @@ class GCodeProfileReader(ProfileReader): Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e)) return None - # Un-escape the serialized profile. - pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys())) - - # Perform the replacement with a regular expression. - serialized = pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], serialized) + serialized = unescapeGcodeComment(serialized) Logger.log("i", "Serialized the following from %s: %s" %(file_name, repr(serialized))) - # Create an empty profile - the id and name will be changed by the ContainerRegistry - profile = InstanceContainer("") - try: - profile.deserialize(serialized) - except Exception as e: # Not a valid g-code file. - Logger.log("e", "Unable to serialise the profile: %s", str(e)) - return None + json_data = json.loads(serialized) - profile.addMetaDataEntry("type", "quality") + profile_strings = [json_data["global_quality"]] + profile_strings.extend(json_data.get("extruder_quality", [])) - return profile + return [readQualityProfileFromString(profile_string) for profile_string in profile_strings] + +## Unescape a string which has been escaped for use in a gcode comment. +# +# \param string The string to unescape. +# \return \type{str} The unscaped string. +def unescapeGcodeComment(string): + # Un-escape the serialized profile. + pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys())) + + # Perform the replacement with a regular expression. + return pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], string) + +## Read in a profile from a serialized string. +# +# \param profile_string The profile data in serialized form. +# \return \type{Profile} the resulting Profile object or None if it could not be read. +def readQualityProfileFromString(profile_string): + # Create an empty profile - the id and name will be changed by the ContainerRegistry + profile = InstanceContainer("") + try: + profile.deserialize(profile_string) + except Exception as e: # Not a valid g-code file. + Logger.log("e", "Unable to serialise the profile: %s", str(e)) + return None + return profile diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index 4eb1f89134..ea21e33109 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -4,8 +4,11 @@ from UM.Mesh.MeshWriter import MeshWriter from UM.Logger import Logger from UM.Application import Application -from UM.Settings.InstanceContainer import InstanceContainer #To create a complete setting profile to store in the g-code. + +from cura.Settings.ExtruderManager import ExtruderManager + import re #For escaping characters in the settings. +import json ## Writes g-code to a file. # @@ -23,7 +26,7 @@ class GCodeWriter(MeshWriter): # It can only read settings with the same version as the version it was # written with. If the file format is changed in a way that breaks reverse # compatibility, increment this version number! - version = 2 + version = 3 ## Dictionary that defines how characters are escaped when embedded in # g-code. @@ -64,25 +67,33 @@ class GCodeWriter(MeshWriter): # # \param settings A container stack to serialise. # \return A serialised string of the settings. - def _serialiseSettings(self, settings): + def _serialiseSettings(self, stack): prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line. prefix_length = len(prefix) - global_stack = Application.getInstance().getGlobalContainerStack() - container_with_profile = global_stack.findContainer({"type": "quality"}) + container_with_profile = stack.findContainer({"type": "quality"}) serialized = container_with_profile.serialize() + data = {"global_quality": serialized} + + manager = ExtruderManager.getInstance() + for extruder in manager.getMachineExtruders(stack.getBottom().getId()): + extruder_quality = extruder.findContainer({"type": "quality"}) + extruder_serialized = extruder_quality.serialize() + data.setdefault("extruder_quality", []).append(extruder_serialized) + + json_string = json.dumps(data) + # Escape characters that have a special meaning in g-code comments. pattern = re.compile("|".join(GCodeWriter.escape_characters.keys())) + # Perform the replacement with a regular expression. - serialized = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], serialized) + escaped_string = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], json_string) # Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix. result = "" # Lines have 80 characters, so the payload of each line is 80 - prefix. - for pos in range(0, len(serialized), 80 - prefix_length): - result += prefix + serialized[pos : pos + 80 - prefix_length] + "\n" - serialized = result - - return serialized \ No newline at end of file + for pos in range(0, len(escaped_string), 80 - prefix_length): + result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n" + return result From 08213890fb6ff45498bd8e601e234ce33957a47d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 12 Jul 2016 13:09:53 +0200 Subject: [PATCH 07/80] Remove reliance on "_current_settings" postfix when removing user profile containers CURA-1896 --- cura/Settings/ExtruderManager.py | 6 +++--- cura/Settings/MachineManager.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 775596104b..132608693f 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -207,12 +207,13 @@ class ExtruderManager(QObject): #And leave it at the default quality. container_stack.addContainer(quality) - user_profile = container_registry.findInstanceContainers(id = extruder_stack_id + "_current_settings") + user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id) if user_profile: #There was already a user profile, loaded from settings. user_profile = user_profile[0] else: user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") #Add an empty user profile. user_profile.addMetaDataEntry("type", "user") + user_profile.addMetaDataEntry("extruder", extruder_stack_id) user_profile.setDefinition(machine_definition) container_registry.addContainer(user_profile) container_stack.addContainer(user_profile) @@ -226,8 +227,7 @@ class ExtruderManager(QObject): # \param machine_id The machine to remove the extruders for. def removeMachineExtruders(self, machine_id): for extruder in self.getMachineExtruders(machine_id): - current_settings_id = extruder.getId() + "_current_settings" - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id) + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", extruder = extruder.getId()) for container in containers: UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId()) UM.Settings.ContainerRegistry.getInstance().removeContainer(extruder.getId()) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index cb761032d8..0a3e1fbaab 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -640,8 +640,7 @@ class MachineManager(QObject): return ExtruderManager.getInstance().removeMachineExtruders(stacks[0].getBottom().getId()) - current_settings_id = machine_id + "_current_settings" - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id) + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id) for container in containers: UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId()) UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id) From f63acc98b84363bef75f774127b2934efb686efe Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 12 Jul 2016 13:47:25 +0200 Subject: [PATCH 08/80] Fix setting enabling for support roof Support roof settings should not be enabled if support roof is enabled but support itself isn't enabled. --- resources/definitions/fdmprinter.def.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 37ff42127e..0007d8616f 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1218,7 +1218,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_print", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -1420,7 +1420,7 @@ "maximum_value_warning": "10000", "default_value": 3000, "value": "acceleration_print", - "enabled": "acceleration_enabled and support_roof_enable", + "enabled": "acceleration_enabled and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -1448,7 +1448,7 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "acceleration_enabled and support_roof_enable", + "enabled": "acceleration_enabled and support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -1608,7 +1608,7 @@ "maximum_value_warning": "50", "default_value": 20, "value": "jerk_print", - "enabled": "jerk_enabled and support_roof_enable", + "enabled": "jerk_enabled and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -1636,7 +1636,7 @@ "minimum_value": "0.1", "minimum_value_warning": "5", "maximum_value_warning": "50", - "enabled": "jerk_enabled and support_roof_enable", + "enabled": "jerk_enabled and support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2125,7 +2125,7 @@ "default_value": 1, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": true }, "support_roof_density": @@ -2137,7 +2137,7 @@ "default_value": 100, "minimum_value": "0", "maximum_value_warning": "100", - "enabled":"support_roof_enable", + "enabled":"support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -2151,7 +2151,7 @@ "default_value": 0.4, "minimum_value": "0", "value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2171,7 +2171,7 @@ "zigzag": "Zig Zag" }, "default_value": "concentric", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false }, From 94acf810d0419bd02de245815cd400b7b67e7ca1 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 12 Jul 2016 14:38:39 +0200 Subject: [PATCH 09/80] JSON fix: redo all commits (squashed) which got undone in merge Merge branch 'feature_firmware_travel_settings' c755479b1bc0e6c5d40a0bd0675cd04a2a1c66a2 overwrote fdmprinter.def.json with the feature branch version, rather than merging it with the master version. This commit is just fdmprinter.def.json as it was at 2c09fc4a6723239cd744b4aa9f28007dea5852fd --- resources/definitions/fdmprinter.def.json | 334 ++++++++++++++-------- 1 file changed, 222 insertions(+), 112 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 0007d8616f..d8c335f0b3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -29,19 +29,19 @@ { "machine_show_variants": { + "label": "Show machine variants", "description": "Whether to show the different variants of this machine, which are described in separate json files.", "default_value": false, "type": "bool", - "label": "Show machine variants", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_start_gcode": { + "label": "Start GCode", "description": "Gcode commands to be executed at the very start - separated by \\n.", "default_value": "G28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\n;Prime the extruder\nG92 E0\nG1 F200 E3\nG92 E0", - "label": "Start GCode", "type": "str", "settable_per_mesh": false, "settable_per_extruder": false, @@ -49,9 +49,9 @@ }, "machine_end_gcode": { + "label": "End GCode", "description": "Gcode commands to be executed at the very end - separated by \\n.", "default_value": "M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84", - "label": "End GCode", "type": "str", "settable_per_mesh": false, "settable_per_extruder": false, @@ -79,49 +79,49 @@ }, "material_print_temp_prepend": { + "label": "Include material temperatures", "description": "Whether to include nozzle temperature commands at the start of the gcode. When the start_gcode already contains nozzle temperature commands Cura frontend will automatically disable this setting.", "default_value": true, "type": "bool", - "label": "Wait for material heatup", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_width": { + "label": "Machine width", "description": "The width (X-direction) of the printable area.", "default_value": 100, "type": "float", - "label": "Machine width", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_depth": { + "label": "Machine depth", "description": "The depth (Y-direction) of the printable area.", "default_value": 100, "type": "float", - "label": "Machine depth", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_height": { + "label": "Machine height", "description": "The height (Z-direction) of the printable area.", "default_value": 100, "type": "float", - "label": "Machine height", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_heated_bed": { + "label": "Has heated bed", "description": "Whether the machine has a heated bed present.", "default_value": false, - "label": "Has heated bed", "type": "bool", "settable_per_mesh": false, "settable_per_extruder": false, @@ -129,28 +129,28 @@ }, "machine_center_is_zero": { + "label": "Is center origin", "description": "Whether the X/Y coordinates of the zero position of the printer is at the center of the printable area.", "default_value": false, "type": "bool", - "label": "Is center origin", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_extruder_count": { + "label": "Number extruders", "description": "Number of extruder trains. An extruder train is the combination of a feeder, bowden tube, and nozzle.", "default_value": 1, "type": "int", - "label": "Number extruders", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_nozzle_tip_outer_diameter": { - "description": "The outer diameter of the tip of the nozzle.", "label": "Outer nozzle diameter", + "description": "The outer diameter of the tip of the nozzle.", "default_value": 1, "type": "float", "settable_per_mesh": false, @@ -160,74 +160,87 @@ }, "machine_nozzle_head_distance": { + "label": "Nozzle length", "description": "The height difference between the tip of the nozzle and the lowest part of the print head.", "default_value": 3, "type": "float", - "label": "Nozzle length", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_nozzle_expansion_angle": { + "label": "Nozzle angle", "description": "The angle between the horizontal plane and the conical part right above the tip of the nozzle.", "default_value": 45, "type": "int", - "label": "Nozzle angle", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_heat_zone_length": { + "label": "Heat zone length", "description": "The distance from the tip of the nozzle in which heat from the nozzle is transfered to the filament.", "default_value": 16, "type": "float", - "label": "Heat zone length", "settable_per_mesh": false, "settable_per_extruder": true, "settable_per_meshgroup": false }, "machine_nozzle_heat_up_speed": { + "label": "Heat up speed", "description": "The speed (°C/s) by which the nozzle heats up averaged over the window of normal printing temperatures and the standby temperature.", "default_value": 2.0, + "unit": "°C/s", "type": "float", - "label": "Heat up speed", "settable_per_mesh": false, "settable_per_extruder": true }, "machine_nozzle_cool_down_speed": { + "label": "Cool down speed", "description": "The speed (°C/s) by which the nozzle cools down averaged over the window of normal printing temperatures and the standby temperature.", "default_value": 2.0, + "unit": "°C/s", + "type": "float", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_min_cool_heat_time_window": + { + "label": "Minimal Time Standby Temperature", + "description": "The minimal time an extruder has to be inactive before the nozzle is cooled. Only when an extruder is not used for longer than this time will it be allowed to cool down to the standby temperature.", + "default_value": 50.0, + "unit": "s", "type": "float", - "label": "Cool down speed", "settable_per_mesh": false, "settable_per_extruder": true }, "machine_gcode_flavor": { + "label": "Gcode flavour", "description": "The type of gcode to be generated.", "default_value": "RepRap", "type": "str", - "label": "Gcode flavour", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_disallowed_areas": { + "label": "Disallowed areas", "description": "A list of polygons with areas the print head is not allowed to enter.", "type": "polygons", "default_value": [], - "label": "Disallowed areas", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_head_polygon": { + "label": "Machine head polygon", "description": "A 2D silhouette of the print head (fan caps excluded).", "type": "polygon", "default_value": @@ -249,13 +262,13 @@ 1 ] ], - "label": "Machine head polygon", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "machine_head_with_fans_polygon": { + "label": "Machine head & Fan polygon", "description": "A 2D silhouette of the print head (fan caps included).", "type": "polygon", "default_value": @@ -277,16 +290,15 @@ -10 ] ], - "label": "Machine head & Fan polygon", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false }, "gantry_height": { + "label": "Gantry height", "description": "The height difference between the tip of the nozzle and the gantry system (X and Y axes).", "default_value": 99999999999, - "label": "Gantry height", "type": "float", "settable_per_mesh": false, "settable_per_extruder": false, @@ -313,6 +325,51 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false + }, + "extruder_prime_pos_x": + { + "label": "Extruder Prime X Position", + "description": "The X coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_y": + { + "label": "Extruder Prime Y Position", + "description": "The Y coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_z": + { + "label": "Extruder Prime Z Position", + "description": "The Z coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_abs": + { + "label": "Absolute Extruder Prime Position", + "description": "Make the extruder prime position absolute rather than relative to the last-known location of the head.", + "type": "bool", + "default_value": false, + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -408,7 +465,7 @@ }, "skin_line_width": { - "label": "Top/bottom Line Width", + "label": "Top/Bottom Line Width", "description": "Width of a single top/bottom line.", "unit": "mm", "minimum_value": "0.0001", @@ -535,6 +592,7 @@ "default_value": 0.8, "minimum_value": "0", "minimum_value_warning": "0.6", + "maximum_value_warning": "machine_height", "type": "float", "settable_per_mesh": true, "children": @@ -546,7 +604,7 @@ "unit": "mm", "default_value": 0.8, "minimum_value": "0", - "maximum_value_warning": "100", + "maximum_value_warning": "machine_height", "type": "float", "value": "top_bottom_thickness", "settable_per_mesh": true, @@ -574,6 +632,7 @@ "minimum_value": "0", "type": "float", "value": "top_bottom_thickness", + "maximum_value_warning": "machine_height", "settable_per_mesh": true, "children": { @@ -924,7 +983,8 @@ "description": "Retract the filament when the nozzle is moving over a non-printed area. ", "type": "bool", "default_value": true, - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_amount": { "label": "Retraction Distance", @@ -935,7 +995,8 @@ "minimum_value_warning": "-0.0001", "maximum_value_warning": "10.0", "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_speed": { "label": "Retraction Speed", @@ -947,7 +1008,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", - "settable_per_mesh": true, + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "retraction_retract_speed": { "label": "Retraction Retract Speed", @@ -960,7 +1022,8 @@ "maximum_value_warning": "100", "enabled": "retraction_enable", "value": "retraction_speed", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_prime_speed": { "label": "Retraction Prime Speed", @@ -973,7 +1036,8 @@ "maximum_value_warning": "100", "enabled": "retraction_enable", "value": "retraction_speed", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -986,7 +1050,8 @@ "minimum_value_warning": "-0.0001", "maximum_value_warning": "5.0", "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_min_travel": { "label": "Retraction Minimum Travel", @@ -998,7 +1063,8 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_count_max": { "label": "Maximum Retraction Count", @@ -1008,7 +1074,8 @@ "maximum_value_warning": "100", "type": "int", "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "retraction_extrusion_window": { "label": "Minimum Extrusion Distance Window", @@ -1020,18 +1087,40 @@ "maximum_value_warning": "retraction_amount * 2", "value": "retraction_amount", "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true }, - "retraction_hop": { - "label": "Z Hop when Retracting", + "retraction_hop_enabled": { + "label": "Z Hop when Retracted", "description": "Whenever a retraction is done, the build plate is lowered to create clearance between the nozzle and the print. It prevents the nozzle from hitting the print during travel moves, reducing the chance to knock the print from the build plate.", - "unit": "mm", - "type": "float", - "default_value": 0, - "minimum_value_warning": "-0.0001", - "maximum_value_warning": "10", + "type": "bool", + "default_value": false, "enabled": "retraction_enable", - "settable_per_mesh": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "children": { + "retraction_hop_only_when_collides": { + "label": "Z Hop Only Over Printed Parts", + "description": "Only perform a Z Hop when moving over printed parts which cannot be avoided by horizontal motion by Avoid Printed Parts when Traveling.", + "type": "bool", + "default_value": false, + "enabled": "retraction_enable and retraction_hop_enabled and travel_avoid_other_parts", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "retraction_hop": { + "label": "Z Hop Height", + "description": "The height difference when performing a Z Hop.", + "unit": "mm", + "type": "float", + "default_value": 1, + "minimum_value_warning": "-0.0001", + "maximum_value_warning": "10", + "enabled": "retraction_enable and retraction_hop_enabled", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "material_standby_temperature": { @@ -1103,16 +1192,12 @@ } } }, - "switch_extruder_retraction_hop": - { - "label": "Nozzle Switch Z Hop", - "description": "Whenever the machine switches to another nozzle, the build plate is lowered to create clearance between the nozzle and the print. It prevents the nozzle which has been unused for a while from oozing material on the outside of the print.", - "type": "float", - "unit": "mm", - "default_value": 1, - "minimum_value_warning": "-0.0001", - "maximum_value_warning": "10", - "enabled": "retraction_enable", + "retraction_hop_after_extruder_switch": { + "label": "Z Hop After Extruder Switch", + "description": "After the machine switched from one extruder to the other, the build plate is lowered to create clearance between the nozzle and the print. This prevents the nozzle from leaving oozed material on the outside of a print.", + "type": "bool", + "default_value": true, + "enabled": "retraction_hop_enabled", "settable_per_mesh": false, "settable_per_extruder": true } @@ -1218,7 +1303,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_print", - "enabled": "support_roof_enable and support_enable", + "enabled": "support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -1420,7 +1505,7 @@ "maximum_value_warning": "10000", "default_value": 3000, "value": "acceleration_print", - "enabled": "acceleration_enabled and support_enable", + "enabled": "acceleration_enabled and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -1448,7 +1533,7 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "acceleration_enabled and support_roof_enable and support_enable", + "enabled": "acceleration_enabled and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -1513,7 +1598,7 @@ "jerk_enabled": { "label": "Enable Jerk Control", - "description": "Enables adjusting the jerk of print head when the X or Y axis halts or starts to move. Increasing the jerk can reduce printing time at the cost of print quality.", + "description": "Enables adjusting the jerk of print head when the velocity in the X or Y axis changes. Increasing the jerk can reduce printing time at the cost of print quality.", "type": "bool", "default_value": false, "settable_per_mesh": false, @@ -1521,7 +1606,7 @@ }, "jerk_print": { "label": "Print Jerk", - "description": "The maximal allowed jerk of the print head when starting to move or when changing direction.", + "description": "The maximum instantaneous velocity change of the print head.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1533,7 +1618,7 @@ "children": { "jerk_infill": { "label": "Infill Jerk", - "description": "The jerk with which infill is printed.", + "description": "The maximum instantaneous velocity change with which infill is printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1546,7 +1631,7 @@ }, "jerk_wall": { "label": "Wall Jerk", - "description": "The jerk with which the walls are printed.", + "description": "The maximum instantaneous velocity change with which the walls are printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1559,7 +1644,7 @@ "children": { "jerk_wall_0": { "label": "Outer Wall Jerk", - "description": "The jerk with which the outermost walls are printed.", + "description": "The maximum instantaneous velocity change with which the outermost walls are printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1572,7 +1657,7 @@ }, "jerk_wall_x": { "label": "Inner Wall Jerk", - "description": "The jerk with which all inner walls are printed.", + "description": "The maximum instantaneous velocity change with which all inner walls are printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1587,7 +1672,7 @@ }, "jerk_topbottom": { "label": "Top/Bottom Jerk", - "description": "The jerk with which top/bottom layers are printed.", + "description": "The maximum instantaneous velocity change with which top/bottom layers are printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1600,7 +1685,7 @@ }, "jerk_support": { "label": "Support Jerk", - "description": "The jerk with which the support structure is printed.", + "description": "The maximum instantaneous velocity change with which the support structure is printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1608,13 +1693,13 @@ "maximum_value_warning": "50", "default_value": 20, "value": "jerk_print", - "enabled": "jerk_enabled and support_enable", + "enabled": "jerk_enabled and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { "jerk_support_infill": { "label": "Support Infill Jerk", - "description": "The jerk with which the infill of support is printed.", + "description": "The maximum instantaneous velocity change with which the infill of support is printed.", "unit": "mm/s³", "type": "float", "default_value": 20, @@ -1628,7 +1713,7 @@ }, "jerk_support_roof": { "label": "Support Roof Jerk", - "description": "The jerk with which the roofs of support are printed.", + "description": "The maximum instantaneous velocity change with which the roofs of support are printed.", "unit": "mm/s³", "type": "float", "default_value": 20, @@ -1636,7 +1721,7 @@ "minimum_value": "0.1", "minimum_value_warning": "5", "maximum_value_warning": "50", - "enabled": "jerk_enabled and support_roof_enable and support_enable", + "enabled": "jerk_enabled and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -1644,7 +1729,7 @@ }, "jerk_prime_tower": { "label": "Prime Tower Jerk", - "description": "The jerk with which the prime tower is printed.", + "description": "The maximum instantaneous velocity change with which the prime tower is printed.", "unit": "mm/s³", "type": "float", "minimum_value": "0.1", @@ -1659,7 +1744,7 @@ }, "jerk_travel": { "label": "Travel Jerk", - "description": "The jerk with which travel moves are made.", + "description": "The maximum instantaneous velocity change with which travel moves are made.", "unit": "mm/s³", "type": "float", "default_value": 30, @@ -1672,7 +1757,7 @@ }, "jerk_layer_0": { "label": "Initial Layer Jerk", - "description": "The print jerk for the initial layer.", + "description": "The print maximum instantaneous velocity change for the initial layer.", "unit": "mm/s³", "type": "float", "default_value": 20, @@ -1685,7 +1770,7 @@ }, "jerk_skirt": { "label": "Skirt Jerk", - "description": "The jerk with which the skirt and brim are printed.", + "description": "The maximum instantaneous velocity change with which the skirt and brim are printed.", "unit": "mm/s³", "type": "float", "default_value": 20, @@ -1736,7 +1821,7 @@ "description": "The distance between the nozzle and already printed parts when avoiding during travel moves.", "unit": "mm", "type": "float", - "default_value": 1.5, + "default_value": 0.625, "value": "machine_nozzle_tip_outer_diameter / 2 * 1.25", "minimum_value": "0", "maximum_value_warning": "machine_nozzle_tip_outer_diameter * 5", @@ -1812,7 +1897,7 @@ { "label": "Regular/Maximum Fan Speed Threshold", "description": "The layer time which sets the threshold between regular fan speed and maximum fan speed. Layers that print slower than this time use regular fan speed. For faster layers the fan speed gradually increases towards the maximum fan speed.", - "unit": "sec", + "unit": "s", "type": "float", "default_value": 10, "minimum_value": "cool_min_layer_time", @@ -1827,7 +1912,7 @@ "unit": "mm", "type": "float", "default_value": 0.5, - "value": "layer_height_0", + "value": "0 if adhesion_type == \"raft\" else layer_height_0", "minimum_value": "0", "maximum_value_warning": "10.0", "settable_per_mesh": false, @@ -1852,7 +1937,7 @@ { "label": "Minimum Layer Time", "description": "The minimum time spent in a layer. This forces the printer to slow down, to at least spend the time set here in one layer. This allows the printed material to cool down properly before printing the next layer.", - "unit": "sec", + "unit": "s", "type": "float", "default_value": 5, "minimum_value": "0", @@ -2125,7 +2210,7 @@ "default_value": 1, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_roof_enable and support_enable", + "enabled": "support_roof_enable", "settable_per_mesh": true }, "support_roof_density": @@ -2137,7 +2222,7 @@ "default_value": 100, "minimum_value": "0", "maximum_value_warning": "100", - "enabled":"support_roof_enable and support_enable", + "enabled":"support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -2151,7 +2236,7 @@ "default_value": 0.4, "minimum_value": "0", "value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))", - "enabled": "support_roof_enable and support_enable", + "enabled": "support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2171,7 +2256,7 @@ "zigzag": "Zig Zag" }, "default_value": "concentric", - "enabled": "support_roof_enable and support_enable", + "enabled": "support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -2320,7 +2405,7 @@ "description": "If the raft is enabled, this is the extra raft area around the object which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", "unit": "mm", "type": "float", - "default_value": 5, + "default_value": 15, "minimum_value_warning": "0", "maximum_value_warning": "10", "enabled": "adhesion_type == \"raft\"" @@ -2370,6 +2455,7 @@ "unit": "mm", "type": "float", "default_value": 0.1, + "value": "layer_height", "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "adhesion_type == \"raft\"", @@ -2382,7 +2468,8 @@ "description": "Width of the lines in the top surface of the raft. These can be thin lines so that the top of the raft becomes smooth.", "unit": "mm", "type": "float", - "default_value": 0.3, + "default_value": 0.4, + "value": "line_width", "minimum_value": "0.0001", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", @@ -2395,7 +2482,7 @@ "description": "The distance between the raft lines for the top raft layers. The spacing should be equal to the line width, so that the surface is solid.", "unit": "mm", "type": "float", - "default_value": 0.3, + "default_value": 0.4, "minimum_value": "0.0001", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", @@ -2409,7 +2496,8 @@ "description": "Layer thickness of the middle raft layer.", "unit": "mm", "type": "float", - "default_value": 0.27, + "default_value": 0.15, + "value": "layer_height * 1.5", "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", @@ -2422,7 +2510,7 @@ "description": "Width of the lines in the middle raft layer. Making the second layer extrude more causes the lines to stick to the bed.", "unit": "mm", "type": "float", - "default_value": 1, + "default_value": 0.7, "value": "line_width * 2", "minimum_value": "0.0001", "maximum_value_warning": "machine_nozzle_size * 2", @@ -2436,7 +2524,8 @@ "description": "The distance between the raft lines for the middle raft layer. The spacing of the middle should be quite wide, while being dense enough to support the top raft layers.", "unit": "mm", "type": "float", - "default_value": 1.0, + "default_value": 0.9, + "value": "raft_interface_line_width + 0.2", "minimum_value": "0", "maximum_value_warning": "15.0", "enabled": "adhesion_type == \"raft\"", @@ -2450,6 +2539,7 @@ "unit": "mm", "type": "float", "default_value": 0.3, + "value": "layer_height_0 * 1.2", "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", @@ -2462,10 +2552,10 @@ "description": "Width of the lines in the base raft layer. These should be thick lines to assist in bed adhesion.", "unit": "mm", "type": "float", - "default_value": 1, + "default_value": 0.8, "minimum_value": "0.0001", - "value": "line_width * 2", - "maximum_value_warning": "machine_nozzle_size * 2", + "value": "machine_nozzle_size * 2", + "maximum_value_warning": "machine_nozzle_size * 3", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, "settable_per_extruder": true @@ -2476,7 +2566,8 @@ "description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.", "unit": "mm", "type": "float", - "default_value": 3.0, + "default_value": 1.6, + "value": "raft_base_line_width * 2", "minimum_value": "0.0001", "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", @@ -2489,7 +2580,7 @@ "description": "The speed at which the raft is printed.", "unit": "mm/s", "type": "float", - "default_value": 30, + "default_value": 20, "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "200", @@ -2505,7 +2596,7 @@ "description": "The speed at which the top raft layers are printed. These should be printed a bit slower, so that the nozzle can slowly smooth out adjacent surface lines.", "unit": "mm/s", "type": "float", - "default_value": 30, + "default_value": 20, "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "100", @@ -2521,11 +2612,11 @@ "unit": "mm/s", "type": "float", "default_value": 15, + "value": "raft_speed * 0.75", "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "150", "enabled": "adhesion_type == \"raft\"", - "value": "0.5 * raft_speed", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -2540,7 +2631,7 @@ "maximum_value": "299792458000", "maximum_value_warning": "200", "enabled": "adhesion_type == \"raft\"", - "value": "0.5 * raft_speed", + "value": "0.75 * raft_speed", "settable_per_mesh": false, "settable_per_extruder": true } @@ -2734,9 +2825,7 @@ "label": "Platform Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", - "default_value": 0, - "minimum_value": "0", - "maximum_value": "machine_extruder_count - 1", + "default_value": "0", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -2745,9 +2834,7 @@ "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": 0, - "minimum_value": "0", - "maximum_value": "machine_extruder_count - 1", + "default_value": "0", "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false, @@ -2757,10 +2844,9 @@ "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": 0, + "default_value": "0", "value": "support_extruder_nr", - "minimum_value": "0", - "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -2769,10 +2855,9 @@ "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", "type": "extruder", - "default_value": 0, + "default_value": "0", "value": "support_extruder_nr", - "minimum_value": "0", - "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -2781,10 +2866,9 @@ "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roof of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": 0, + "default_value": "0", "value": "support_extruder_nr", - "minimum_value": "0", - "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2976,6 +3060,31 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "infill_mesh": + { + "label": "Infill Mesh", + "description": "Use this mesh to modify the infill of other meshes with which it overlaps. Replaces infill regions of other meshes with regions for this mesh. It's suggested to only print one Wall and no Top/Bottom Skin for this mesh.", + "type": "bool", + "default_value": false, + "settable_per_mesh": true, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": false + }, + "infill_mesh_order": + { + "label": "Infill Mesh Order", + "description": "Determines which infill mesh is inside the infill of another infill mesh. An infill mesh with a higher order will modify the infill of infill meshes with lower order and normal meshes.", + "default_value": 0, + "value": "1 if infill_mesh else 0", + "minimum_value_warning": "1", + "maximum_value_warning": "50", + "type": "int", + "settable_per_mesh": true, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": false + }, "magic_mesh_surface_mode": { "label": "Surface Mode", @@ -3004,7 +3113,7 @@ { "label": "Experimental Modes", "type": "category", - "icon": "category_blackmagic", + "icon": "category_experimental", "description": "experimental!", "children": { @@ -3070,7 +3179,8 @@ "description": "The maximum angle of overhangs after the they have been made printable. At a value of 0° all overhangs are replaced by a piece of model connected to the build plate, 90° will not change the model in any way.", "unit": "°", "type": "float", - "minimum_value": "0", + "minimum_value": "-89", + "minimum_value_warning": "0", "maximum_value": "89", "default_value": 50, "enabled": "conical_overhang_enabled" @@ -3402,7 +3512,7 @@ { "label": "WP Top Delay", "description": "Delay time after an upward move, so that the upward line can harden. Only applies to Wire Printing.", - "unit": "sec", + "unit": "s", "type": "float", "default_value": 0, "minimum_value": "0", @@ -3416,7 +3526,7 @@ { "label": "WP Bottom Delay", "description": "Delay time after a downward move. Only applies to Wire Printing.", - "unit": "sec", + "unit": "s", "type": "float", "default_value": 0, "minimum_value": "0", @@ -3430,7 +3540,7 @@ { "label": "WP Flat Delay", "description": "Delay time between two horizontal segments. Introducing such a delay can cause better adhesion to previous layers at the connection points, while too long delays cause sagging. Only applies to Wire Printing.", - "unit": "sec", + "unit": "s", "type": "float", "default_value": 0.1, "minimum_value": "0", @@ -3560,7 +3670,7 @@ "label": "WP Roof Outer Delay", "description": "Time spent at the outer perimeters of hole which is to become a roof. Longer times can ensure a better connection. Only applies to Wire Printing.", "type": "float", - "unit": "sec", + "unit": "s", "default_value": 0.2, "minimum_value": "0", "maximum_value_warning": "2.0", From 7d2ae57f86e4c53fcaaa3cd936879b5ce779e874 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 14 Jun 2016 15:47:29 +0200 Subject: [PATCH 10/80] =?UTF-8?q?JSON=20fix:=20unit=20of=20jerk:=20mm/s?= =?UTF-8?q?=C2=B3=20=3D=3D>=20mm/s=20(CURA-1646)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/definitions/fdmprinter.def.json | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d8c335f0b3..d353278c58 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1607,7 +1607,7 @@ "jerk_print": { "label": "Print Jerk", "description": "The maximum instantaneous velocity change of the print head.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1619,7 +1619,7 @@ "jerk_infill": { "label": "Infill Jerk", "description": "The maximum instantaneous velocity change with which infill is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1632,7 +1632,7 @@ "jerk_wall": { "label": "Wall Jerk", "description": "The maximum instantaneous velocity change with which the walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1645,7 +1645,7 @@ "jerk_wall_0": { "label": "Outer Wall Jerk", "description": "The maximum instantaneous velocity change with which the outermost walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1658,7 +1658,7 @@ "jerk_wall_x": { "label": "Inner Wall Jerk", "description": "The maximum instantaneous velocity change with which all inner walls are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1673,7 +1673,7 @@ "jerk_topbottom": { "label": "Top/Bottom Jerk", "description": "The maximum instantaneous velocity change with which top/bottom layers are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1686,7 +1686,7 @@ "jerk_support": { "label": "Support Jerk", "description": "The maximum instantaneous velocity change with which the support structure is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1700,7 +1700,7 @@ "jerk_support_infill": { "label": "Support Infill Jerk", "description": "The maximum instantaneous velocity change with which the infill of support is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_support", @@ -1714,7 +1714,7 @@ "jerk_support_roof": { "label": "Support Roof Jerk", "description": "The maximum instantaneous velocity change with which the roofs of support are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_support", @@ -1730,7 +1730,7 @@ "jerk_prime_tower": { "label": "Prime Tower Jerk", "description": "The maximum instantaneous velocity change with which the prime tower is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "minimum_value": "0.1", "minimum_value_warning": "5", @@ -1745,7 +1745,7 @@ "jerk_travel": { "label": "Travel Jerk", "description": "The maximum instantaneous velocity change with which travel moves are made.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 30, "minimum_value": "0.1", @@ -1758,7 +1758,7 @@ "jerk_layer_0": { "label": "Initial Layer Jerk", "description": "The print maximum instantaneous velocity change for the initial layer.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "jerk_print", @@ -1771,7 +1771,7 @@ "jerk_skirt": { "label": "Skirt Jerk", "description": "The maximum instantaneous velocity change with which the skirt and brim are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "minimum_value": "0.1", @@ -2700,7 +2700,7 @@ "raft_jerk": { "label": "Raft Print Jerk", "description": "The jerk with which the raft is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "minimum_value": "0.1", @@ -2713,7 +2713,7 @@ "raft_surface_jerk": { "label": "Raft Top Print Jerk", "description": "The jerk with which the top raft layers are printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", @@ -2726,7 +2726,7 @@ "raft_interface_jerk": { "label": "Raft Middle Print Jerk", "description": "The jerk with which the middle raft layer is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", @@ -2739,7 +2739,7 @@ "raft_base_jerk": { "label": "Raft Base Print Jerk", "description": "The jerk with which the base raft layer is printed.", - "unit": "mm/s³", + "unit": "mm/s", "type": "float", "default_value": 20, "value": "raft_jerk", From 878bf3535662d38c588349834ad96aad5db52976 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 14 Jun 2016 17:06:46 +0200 Subject: [PATCH 11/80] JSON feat: firmware acceleration and jerk settings for ultimaker printers (CURA-1646) --- resources/definitions/fdmprinter.def.json | 130 ++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d353278c58..cb32ef6cad 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -370,6 +370,136 @@ "default_value": false, "settable_per_mesh": false, "settable_per_extruder": true + }, + "machine_max_feedrate_x": { + "label": "Maximum Speed X", + "description": "The maximum speed for the motor of the X-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 500, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_y": { + "label": "Maximum Speed Y", + "description": "The maximum speed for the motor of the Y-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 500, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_z": { + "label": "Maximum Speed Z", + "description": "The maximum speed for the motor of the Z-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 5, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_feedrate_e": { + "label": "Maximum Feedrate", + "description": "The maximum speed of the filament.", + "unit": "mm/s", + "type": "float", + "default_value": 25, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_x": { + "label": "Maximum Acceleration X", + "description": "Maximum acceleration for the motor of the X-direction", + "unit": "mm/s²", + "type": "float", + "default_value": 9000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_y": { + "label": "Maximum Acceleration Y", + "description": "Maximum acceleration for the motor of the Y-direction.", + "unit": "mm/s²", + "type": "float", + "default_value": 9000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_z": { + "label": "Maximum Acceleration Z", + "description": "Maximum acceleration for the motor of the Z-direction.", + "unit": "mm/s²", + "type": "float", + "default_value": 100, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_acceleration_e": { + "label": "Maximum Filament Acceleration", + "description": "Maximum acceleration for the motor of the filament.", + "unit": "mm/s²", + "type": "float", + "default_value": 10000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_acceleration": { + "label": "Default Acceleration", + "description": "The default acceleration of print head movement.", + "unit": "mm/s²", + "type": "float", + "default_value": 4000, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_xy": { + "label": "Default X-Y Jerk", + "description": "Default jerk for movement in the horizontal plane.", + "unit": "mm/s", + "type": "float", + "default_value": 20.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_z": { + "label": "Default Z Jerk", + "description": "Default jerk for the motor of the Z-direction.", + "unit": "mm/s", + "type": "float", + "default_value": 0.4, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_max_jerk_e": { + "label": "Default Filament Jerk", + "description": "Default jerk for the motor of the filament.", + "unit": "mm/s", + "type": "float", + "default_value": 5.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "machine_minimum_feedrate": { + "label": "Minimum Feedrate", + "description": "The minimal movement speed of the print head.", + "unit": "mm/s", + "type": "float", + "default_value": 0.0, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } }, From dc7ca47be96fa337320abe400575e6fd5437308a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 12 Jul 2016 13:47:25 +0200 Subject: [PATCH 12/80] Fix setting enabling for support roof Support roof settings should not be enabled if support roof is enabled but support itself isn't enabled. --- resources/definitions/fdmprinter.def.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index cb32ef6cad..f6c694849b 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1433,7 +1433,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_print", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -1635,7 +1635,7 @@ "maximum_value_warning": "10000", "default_value": 3000, "value": "acceleration_print", - "enabled": "acceleration_enabled and support_roof_enable", + "enabled": "acceleration_enabled and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -1663,7 +1663,7 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "acceleration_enabled and support_roof_enable", + "enabled": "acceleration_enabled and support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -1823,7 +1823,7 @@ "maximum_value_warning": "50", "default_value": 20, "value": "jerk_print", - "enabled": "jerk_enabled and support_roof_enable", + "enabled": "jerk_enabled and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -1851,7 +1851,7 @@ "minimum_value": "0.1", "minimum_value_warning": "5", "maximum_value_warning": "50", - "enabled": "jerk_enabled and support_roof_enable", + "enabled": "jerk_enabled and support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2340,7 +2340,7 @@ "default_value": 1, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": true }, "support_roof_density": @@ -2352,7 +2352,7 @@ "default_value": 100, "minimum_value": "0", "maximum_value_warning": "100", - "enabled":"support_roof_enable", + "enabled":"support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -2366,7 +2366,7 @@ "default_value": 0.4, "minimum_value": "0", "value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false } @@ -2386,7 +2386,7 @@ "zigzag": "Zig Zag" }, "default_value": "concentric", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": false }, From 779f66967eb24ca9ad09b36ed7a84fc56d3af7df Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 12 Jul 2016 14:48:40 +0200 Subject: [PATCH 13/80] JSON fix: support speed was only enabled when roofs were enabled --- 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 f6c694849b..d24d628fd9 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1433,7 +1433,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_print", - "enabled": "support_roof_enable and support_enable", + "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false, "children": From b622c7ecc87708451a4a9adb32e859b8981362e1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 12 Jul 2016 18:29:40 +0200 Subject: [PATCH 14/80] Initialise variant, material and quality to empty containers of the respective type Before it would be impossible to switch to a valid option once a variant/material/quality had gone to an "empty" state. Now at least it is recoverable. --- cura/Settings/ExtruderManager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 132608693f..556a3c7495 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -145,7 +145,7 @@ class ExtruderManager(QObject): container_stack.addContainer(extruder_definition) #Find the variant to use for this extruder. - variant = container_registry.getEmptyInstanceContainer() + variant = container_registry.findInstanceContainers(id = "empty_variant")[0] if machine_definition.getMetaDataEntry("has_variants"): #First add any variant. Later, overwrite with preference if the preference is valid. variants = container_registry.findInstanceContainers(definition = machine_id, type = "variant") @@ -162,7 +162,7 @@ class ExtruderManager(QObject): container_stack.addContainer(variant) #Find a material to use for this variant. - material = container_registry.getEmptyInstanceContainer() + material = container_registry.findInstanceContainers(id = "empty_material")[0] if machine_definition.getMetaDataEntry("has_materials"): #First add any material. Later, overwrite with preference if the preference is valid. if machine_definition.getMetaDataEntry("has_variant_materials", default = "False") == "True": @@ -191,7 +191,7 @@ class ExtruderManager(QObject): container_stack.addContainer(material) #Find a quality to use for this extruder. - quality = container_registry.getEmptyInstanceContainer() + quality = container_registry.findInstanceContainers(id = "empty_quality")[0] #First add any quality. Later, overwrite with preference if the preference is valid. qualities = container_registry.findInstanceContainers(type = "quality") From 642ea6791bcb25fccc9feec19531703326c477c1 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Wed, 13 Jul 2016 09:27:48 +0200 Subject: [PATCH 15/80] When saving the quality profile data, also incorporate any user settings/changes. Contributes to CURA-1727 GCode Profile reading/writing: Broken and needs update --- cura/CuraApplication.py | 9 +++++++-- cura/Settings/MachineManager.py | 2 +- plugins/GCodeWriter/GCodeWriter.py | 22 ++++++++++++++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c96bea352b..850657c33f 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -126,6 +126,7 @@ class CuraApplication(QtApplication): ) self._machine_action_manager = MachineActionManager.MachineActionManager() + self._machine_manager = None # This is initialized on demand. super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) @@ -399,8 +400,7 @@ class CuraApplication(QtApplication): # Initialise extruder so as to listen to global container stack changes before the first global container stack is set. cura.Settings.ExtruderManager.getInstance() - qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", - cura.Settings.MachineManager.createMachineManager) + qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) @@ -419,6 +419,11 @@ class CuraApplication(QtApplication): self.exec_() + def getMachineManager(self, *args): + if self._machine_manager is None: + self._machine_manager = cura.Settings.MachineManager.createMachineManager() + return self._machine_manager + ## Get the machine action manager # We ignore any *args given to this, as we also register the machine manager as qml singleton. # It wants to give this function an engine and script engine, but we don't care about that. diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0a3e1fbaab..1d353729b1 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -692,7 +692,7 @@ class MachineManager(QObject): return containers[0].getBottom().getId() @staticmethod - def createMachineManager(engine, script_engine): + def createMachineManager(engine=None, script_engine=None): return MachineManager() def _updateVariantContainer(self, definition): diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index ea21e33109..25d0a10c62 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -4,7 +4,9 @@ from UM.Mesh.MeshWriter import MeshWriter from UM.Logger import Logger from UM.Application import Application +import UM.Settings.ContainerRegistry +from cura.CuraApplication import CuraApplication from cura.Settings.ExtruderManager import ExtruderManager import re #For escaping characters in the settings. @@ -72,14 +74,30 @@ class GCodeWriter(MeshWriter): prefix_length = len(prefix) container_with_profile = stack.findContainer({"type": "quality"}) - serialized = container_with_profile.serialize() + machine_manager = CuraApplication.getInstance().getMachineManager() + + # Duplicate the current quality profile and update it with any user settings. + flat_quality_id = machine_manager.duplicateContainer(container_with_profile.getId()) + flat_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = flat_quality_id)[0] + user_settings = stack.getTop() + for key in user_settings.getAllKeys(): + flat_quality.setProperty(key, "value", user_settings.getProperty(key, "value")) + + serialized = flat_quality.serialize() data = {"global_quality": serialized} manager = ExtruderManager.getInstance() for extruder in manager.getMachineExtruders(stack.getBottom().getId()): extruder_quality = extruder.findContainer({"type": "quality"}) - extruder_serialized = extruder_quality.serialize() + + flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId()) + flat_extruder_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=flat_extruder_quality_id)[0] + extruder_user_settings = extruder.getTop() + for key in extruder_user_settings.getAllKeys(): + flat_extruder_quality.setProperty(key, "value", extruder_user_settings.getProperty(key, "value")) + + extruder_serialized = flat_extruder_quality.serialize() data.setdefault("extruder_quality", []).append(extruder_serialized) json_string = json.dumps(data) From b0137016f7baccc9d2956620f133e9788cb02e22 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 09:46:23 +0200 Subject: [PATCH 16/80] Fixed formating of documentation CURA-1898 --- cura/Settings/ExtruderManager.py | 45 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 132608693f..dfc43f54b7 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -95,21 +95,21 @@ class ExtruderManager(QObject): container_registry = UM.Settings.ContainerRegistry.getInstance() if container_registry: - #Add the extruder trains that don't exist yet. + # Add the extruder trains that don't exist yet. for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()): position = extruder_definition.getMetaDataEntry("position", None) if not position: UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) - if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet. + if not container_registry.findContainerStacks(machine = machine_id, position = position): # Doesn't exist yet. self.createExtruderTrain(extruder_definition, machine_definition, position) changed = True - #Gets the extruder trains that we just created as well as any that still existed. + # Gets the extruder trains that we just created as well as any that still existed. extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId()) for extruder_train in extruder_trains: self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train - #Ensure that the extruder train stacks are linked to global stack. + # Ensure that the extruder train stacks are linked to global stack. extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) changed = True @@ -124,30 +124,27 @@ class ExtruderManager(QObject): # # The resulting container stack is added to the registry. # - # \param extruder_definition The extruder to create the extruder train - # for. - # \param machine_definition The machine that the extruder train belongs - # to. - # \param position The position of this extruder train in the extruder - # slots of the machine. + # \param extruder_definition The extruder to create the extruder train for. + # \param machine_definition The machine that the extruder train belongs to. + # \param position The position of this extruder train in the extruder slots of the machine. def createExtruderTrain(self, extruder_definition, machine_definition, position): - #Cache some things. + # Cache some things. container_registry = UM.Settings.ContainerRegistry.getInstance() machine_id = machine_definition.getId() - #Create a container stack for this extruder. + # Create a container stack for this extruder. extruder_stack_id = container_registry.uniqueName(extruder_definition.getId()) container_stack = UM.Settings.ContainerStack(extruder_stack_id) - container_stack.setName(extruder_definition.getName()) #Take over the display name to display the stack with. + container_stack.setName(extruder_definition.getName()) # Take over the display name to display the stack with. container_stack.addMetaDataEntry("type", "extruder_train") container_stack.addMetaDataEntry("machine", machine_definition.getId()) container_stack.addMetaDataEntry("position", position) container_stack.addContainer(extruder_definition) - #Find the variant to use for this extruder. + # Find the variant to use for this extruder. variant = container_registry.getEmptyInstanceContainer() if machine_definition.getMetaDataEntry("has_variants"): - #First add any variant. Later, overwrite with preference if the preference is valid. + # First add any variant. Later, overwrite with preference if the preference is valid. variants = container_registry.findInstanceContainers(definition = machine_id, type = "variant") if len(variants) >= 1: variant = variants[0] @@ -158,13 +155,13 @@ class ExtruderManager(QObject): variant = preferred_variants[0] else: UM.Logger.log("w", "The preferred variant \"%s\" of machine %s doesn't exist or is not a variant profile.", preferred_variant_id, machine_id) - #And leave it at the default variant. + # And leave it at the default variant. container_stack.addContainer(variant) - #Find a material to use for this variant. + # Find a material to use for this variant. material = container_registry.getEmptyInstanceContainer() if machine_definition.getMetaDataEntry("has_materials"): - #First add any material. Later, overwrite with preference if the preference is valid. + # First add any material. Later, overwrite with preference if the preference is valid. if machine_definition.getMetaDataEntry("has_variant_materials", default = "False") == "True": materials = container_registry.findInstanceContainers(type = "material", definition = machine_id, variant = variant.getId()) else: @@ -187,13 +184,13 @@ class ExtruderManager(QObject): material = preferred_materials[0] else: UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id) - #And leave it at the default material. + # And leave it at the default material. container_stack.addContainer(material) - #Find a quality to use for this extruder. + # Find a quality to use for this extruder. quality = container_registry.getEmptyInstanceContainer() - #First add any quality. Later, overwrite with preference if the preference is valid. + # First add any quality. Later, overwrite with preference if the preference is valid. qualities = container_registry.findInstanceContainers(type = "quality") if len(qualities) >= 1: quality = qualities[0] @@ -204,14 +201,14 @@ class ExtruderManager(QObject): quality = preferred_quality[0] else: UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality_id, machine_id) - #And leave it at the default quality. + # And leave it at the default quality. container_stack.addContainer(quality) user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id) - if user_profile: #There was already a user profile, loaded from settings. + if user_profile: # There was already a user profile, loaded from settings. user_profile = user_profile[0] else: - user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") #Add an empty user profile. + user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") # Add an empty user profile. user_profile.addMetaDataEntry("type", "user") user_profile.addMetaDataEntry("extruder", extruder_stack_id) user_profile.setDefinition(machine_definition) From 9eade0707b9434b1f1ca824ffe20d7256deba197 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 13 Jul 2016 11:14:15 +0200 Subject: [PATCH 17/80] Added prime locations to machine_disallowed_areas. CURA-1811 --- cura/BuildVolume.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index b438365f78..901a8182ef 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -1,6 +1,7 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. +from cura.Settings.ExtruderManager import ExtruderManager from UM.i18n import i18nCatalog from UM.Scene.SceneNode import SceneNode from UM.Application import Application @@ -19,6 +20,10 @@ catalog = i18nCatalog("cura") import numpy +# Setting for clearance around the prime +PRIME_CLEARANCE = 10 + + ## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas. class BuildVolume(SceneNode): VolumeOutlineColor = Color(12, 169, 227, 255) @@ -215,6 +220,29 @@ class BuildVolume(SceneNode): disallowed_areas = self._active_container_stack.getProperty("machine_disallowed_areas", "value") areas = [] + # Add extruder prime locations as disallowed areas. + # Probably needs some rework after coordinate system change. + machine_definition = self._active_container_stack.getBottom() + current_machine_id = machine_definition.getId() + extruder_manager = ExtruderManager.getInstance() + extruders = extruder_manager.getMachineExtruders(current_machine_id) + machine_width = machine_definition.getProperty("machine_width", "value") + machine_depth = machine_definition.getProperty("machine_depth", "value") + for single_extruder in extruders: + extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value") + extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value") + # TODO: calculate everything in CuraEngine/Firmware/lower left as origin coordinates. + # Here we transform the extruder prime pos (lower left as origin) to Cura coordinates + # (center as origin, y from back to front) + prime_x = extruder_prime_pos_x - machine_width / 2 + prime_y = machine_depth / 2 - extruder_prime_pos_y + disallowed_areas.append([ + [prime_x - PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE], + [prime_x + PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE], + [prime_x + PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE], + [prime_x - PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE], + ]) + skirt_size = self._getSkirtSize(self._active_container_stack) if disallowed_areas: From 726eb97d9ffa199b71d27f94d7f4e8d65818737b Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 11:17:44 +0200 Subject: [PATCH 18/80] Machine_id instead of definition_id is now used to link extruders Contributes to CURA-1898 --- cura/Settings/ExtruderManager.py | 35 +++++++++++----------- cura/Settings/ExtrudersModel.py | 2 +- cura/Settings/MachineManager.py | 2 +- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- plugins/GCodeWriter/GCodeWriter.py | 2 +- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 40798999ec..1d60fe1ff4 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -37,7 +37,7 @@ class ExtruderManager(QObject): if not UM.Application.getInstance().getGlobalContainerStack(): return None #No active machine, so no active extruder. try: - return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)].getId() + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId() except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None @@ -84,37 +84,35 @@ class ExtruderManager(QObject): ## Adds all extruders of a specific machine definition to the extruder # manager. # - # \param machine_definition The machine to add the extruders for. - def addMachineExtruders(self, machine_definition): + # \param machine_definition The machine definition to add the extruders for. + # \param machine_id The machine_id to add the extruders for. + def addMachineExtruders(self, machine_definition, machine_id): changed = False - machine_id = machine_definition.getId() + machine_definition_id = machine_definition.getId() if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = { } changed = True - container_registry = UM.Settings.ContainerRegistry.getInstance() if container_registry: - # Add the extruder trains that don't exist yet. - for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()): + for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition_id): position = extruder_definition.getMetaDataEntry("position", None) if not position: UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) if not container_registry.findContainerStacks(machine = machine_id, position = position): # Doesn't exist yet. - self.createExtruderTrain(extruder_definition, machine_definition, position) + self.createExtruderTrain(extruder_definition, machine_definition, position, machine_id) changed = True # Gets the extruder trains that we just created as well as any that still existed. - extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId()) + extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_id) for extruder_train in extruder_trains: self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train # Ensure that the extruder train stacks are linked to global stack. extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) changed = True - if changed: - self.extrudersChanged.emit(machine_definition) + self.extrudersChanged.emit(machine_id) ## Creates a container stack for an extruder train. # @@ -127,17 +125,18 @@ class ExtruderManager(QObject): # \param extruder_definition The extruder to create the extruder train for. # \param machine_definition The machine that the extruder train belongs to. # \param position The position of this extruder train in the extruder slots of the machine. - def createExtruderTrain(self, extruder_definition, machine_definition, position): + # \param machine_id The id of the "global" stack this extruder is linked to. + def createExtruderTrain(self, extruder_definition, machine_definition, position, machine_id): # Cache some things. container_registry = UM.Settings.ContainerRegistry.getInstance() - machine_id = machine_definition.getId() + machine_definition_id = machine_definition.getId() # Create a container stack for this extruder. extruder_stack_id = container_registry.uniqueName(extruder_definition.getId()) container_stack = UM.Settings.ContainerStack(extruder_stack_id) container_stack.setName(extruder_definition.getName()) # Take over the display name to display the stack with. container_stack.addMetaDataEntry("type", "extruder_train") - container_stack.addMetaDataEntry("machine", machine_definition.getId()) + container_stack.addMetaDataEntry("machine", machine_id) container_stack.addMetaDataEntry("position", position) container_stack.addContainer(extruder_definition) @@ -145,7 +144,7 @@ class ExtruderManager(QObject): variant = container_registry.findInstanceContainers(id = "empty_variant")[0] if machine_definition.getMetaDataEntry("has_variants"): # First add any variant. Later, overwrite with preference if the preference is valid. - variants = container_registry.findInstanceContainers(definition = machine_id, type = "variant") + variants = container_registry.findInstanceContainers(definition = machine_definition_id, type = "variant") if len(variants) >= 1: variant = variants[0] preferred_variant_id = machine_definition.getMetaDataEntry("preferred_variant") @@ -163,9 +162,9 @@ class ExtruderManager(QObject): if machine_definition.getMetaDataEntry("has_materials"): # First add any material. Later, overwrite with preference if the preference is valid. if machine_definition.getMetaDataEntry("has_variant_materials", default = "False") == "True": - materials = container_registry.findInstanceContainers(type = "material", definition = machine_id, variant = variant.getId()) + materials = container_registry.findInstanceContainers(type = "material", definition = machine_definition_id, variant = variant.getId()) else: - materials = container_registry.findInstanceContainers(type = "material", definition = machine_id) + materials = container_registry.findInstanceContainers(type = "material", definition = machine_definition_id) if len(materials) >= 1: material = materials[0] preferred_material_id = machine_definition.getMetaDataEntry("preferred_material") @@ -247,4 +246,4 @@ class ExtruderManager(QObject): def _addCurrentMachineExtruders(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() if global_stack and global_stack.getBottom(): - self.addMachineExtruders(global_stack.getBottom()) + self.addMachineExtruders(global_stack.getBottom(), global_stack.getId()) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 66462296d3..15e80d3f6b 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -115,7 +115,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): changed = True manager = ExtruderManager.getInstance() - for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()): + for extruder in manager.getMachineExtruders(global_container_stack.getId()): extruder_name = extruder.getName() material = extruder.findContainer({ "type": "material" }) if material: diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 1d353729b1..796853ef43 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -292,7 +292,7 @@ class MachineManager(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - ExtruderManager.getInstance().addMachineExtruders(definition) + ExtruderManager.getInstance().addMachineExtruders(definition, new_global_stack.getId()) Application.getInstance().setGlobalContainerStack(new_global_stack) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index cdfcecb6b9..6aa9c4660b 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -129,7 +129,7 @@ class StartSliceJob(Job): self._buildGlobalSettingsMessage(stack) - for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()): + for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getId()): self._buildExtruderMessage(extruder_stack) for group in object_groups: diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index 25d0a10c62..08105b06e8 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -88,7 +88,7 @@ class GCodeWriter(MeshWriter): data = {"global_quality": serialized} manager = ExtruderManager.getInstance() - for extruder in manager.getMachineExtruders(stack.getBottom().getId()): + for extruder in manager.getMachineExtruders(stack.getId()): extruder_quality = extruder.findContainer({"type": "quality"}) flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId()) From c37163059afc89dff4243a03e2aae0f28413c619 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 13 Jul 2016 11:18:45 +0200 Subject: [PATCH 19/80] Update wording to reflect the official HBK is also supported --- .../UMOUpgradeSelectionMachineAction.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UltimakerMachineActions/UMOUpgradeSelectionMachineAction.qml b/plugins/UltimakerMachineActions/UMOUpgradeSelectionMachineAction.qml index 1381daa270..07e317d9a4 100644 --- a/plugins/UltimakerMachineActions/UMOUpgradeSelectionMachineAction.qml +++ b/plugins/UltimakerMachineActions/UMOUpgradeSelectionMachineAction.qml @@ -42,7 +42,7 @@ Cura.MachineAction anchors.top: pageDescription.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height - text: catalog.i18nc("@label", "Self-built heated bed") + text: catalog.i18nc("@label", "Heated bed (official kit or self-built)") checked: manager.hasHeatedBed onClicked: manager.hasHeatedBed ? manager.removeHeatedBed() : manager.addHeatedBed() } From b33c2f9c25bcfe2c320923cf5aa71f530ededbc8 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 13 Jul 2016 12:06:07 +0200 Subject: [PATCH 20/80] Even better fallbacks for unknown subprofiles These fallbacks specify their types so that they can be found with the filters. Contributes to issue CURA-844. --- .../VersionUpgrade/VersionUpgrade21to22/MachineInstance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py b/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py index 197aa9fcb9..664f972615 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py @@ -47,11 +47,11 @@ class MachineInstance: raise UM.VersionUpgrade.InvalidVersionException("The version of this machine instance is wrong. It must be 1.") self._type_name = config.get("general", "type") - self._variant_name = config.get("general", "variant", fallback = "empty") + self._variant_name = config.get("general", "variant", fallback = "empty_variant") self._name = config.get("general", "name", fallback = "") self._key = config.get("general", "key", fallback = None) - self._active_profile_name = config.get("general", "active_profile", fallback = "empty") - self._active_material_name = config.get("general", "material", fallback = "empty") + self._active_profile_name = config.get("general", "active_profile", fallback = "empty_quality") + self._active_material_name = config.get("general", "material", fallback = "empty_material") self._machine_setting_overrides = {} for key, value in config["machine_settings"].items(): From dfd56d049f9763867e6c1ad0d18ea44546b60fd3 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 13:08:14 +0200 Subject: [PATCH 21/80] getActiveExtruderStack now returns stack based on machine_id instead of definiton ID Contributes to CURA-1898 --- cura/Settings/ExtruderManager.py | 12 +++++------- cura/Settings/MachineManager.py | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 1d60fe1ff4..079b01598e 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -35,10 +35,10 @@ class ExtruderManager(QObject): @pyqtProperty(str, notify = activeExtruderChanged) def activeExtruderStackId(self): if not UM.Application.getInstance().getGlobalContainerStack(): - return None #No active machine, so no active extruder. + return None # No active machine, so no active extruder. try: return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId() - except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. + except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None ## The instance of the singleton pattern. @@ -74,11 +74,9 @@ class ExtruderManager(QObject): def getActiveExtruderStack(self): global_container_stack = UM.Application.getInstance().getGlobalContainerStack() if global_container_stack: - global_definition_container = UM.Application.getInstance().getGlobalContainerStack().getBottom() - if global_definition_container: - if global_definition_container.getId() in self._extruder_trains: - if str(self._active_extruder_index) in self._extruder_trains[global_definition_container.getId()]: - return self._extruder_trains[global_definition_container.getId()][str(self._active_extruder_index)] + if global_container_stack.getId() in self._extruder_trains: + if str(self._active_extruder_index) in self._extruder_trains[global_container_stack.getId()]: + return self._extruder_trains[global_container_stack.getId()][str(self._active_extruder_index)] return None ## Adds all extruders of a specific machine definition to the extruder diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 796853ef43..23335e3e63 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -239,7 +239,6 @@ class MachineManager(QObject): if self._active_container_stack and self._active_container_stack != self._global_container_stack: self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) - self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack() if self._active_container_stack: self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged) From ec0e19e175b8b0f184f07e43ce9dbd04e9f95917 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 14:20:41 +0200 Subject: [PATCH 22/80] Removed material profiles field from sliceinfo --- plugins/SliceInfoPlugin/SliceInfo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index d3b93aacac..39a55702ab 100644 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -93,7 +93,6 @@ class SliceInfo(Extension): "printtime": print_information.currentPrintTime.getDisplayString(), "filament": material_used, "language": Preferences.getInstance().getValue("general/language"), - "materials_profiles ": {} } for container in global_container_stack.getContainers(): container_id = container.getId() From 3f1bd5b586125040550024b0bda517d14bfb5868 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 13 Jul 2016 14:16:28 +0200 Subject: [PATCH 23/80] Update changelog with corrections done after release Also make sure to include all CureEngine features listed in the online changelog Contributes to CURA-1688 --- plugins/ChangeLogPlugin/ChangeLog.txt | 69 +++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 48e96ce4b6..fea618bd97 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,6 +1,11 @@ +[2.1.3] + +*Material Profiles +New material profiles for CPE+, PC, Nylon and TPU for the Ultimaker 2+ family. + [2.1.2] -Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings. +Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 200 customizable settings. *Select Multiple Objects You now have the freedom to select and manipulate multiple objects at the same time. @@ -27,22 +32,66 @@ An optimized 64-bit Windows Cura version is now available. This allows you to lo Cura allows you to set a number of lines/layers instead of millimeters. The engine automatically calculates the right settings. *Per-Object Settings -You can now override individual settings for different objects in advanced mode. +Per-object settings allow you to override individual profile settings per object. -*Fuzzy Skin -Prints the outer walls with a jittering motion to give your object a diffused finish. +*Engine Features -*Wire Printing -The object is printed with a mid-air / net-like structure, following the mesh surface. The build plate will move up and down during diagonal segments. Though not visible in layer view, you can view the result in other software, such as Repetier Host or http://chilipeppr.com/tinyg. +*Line Width +Line width settings added per feature: Global, Walls, Top/Bottom, Infill, Skirt, Support. +<<<<<<< HEAD * Conical Support An experimental filament, cost-reduction feature, for support. +======= +*Pattern Settings +Pattern settings improved per feature: Top/Bottom, Infill, Support. + +*Shell + +*Alternate Skin Rotation +Helps to combat the pillowing problem on top layers. + +*Alternate Extra Wall +For better infill adhesion. + +*Horizontal Expansion +Allows to compensate model x,y-size to get a 1:1 result. + +*Travel + +*Avoid Printed Parts +When moving to the next part to print, avoid collisions between the nozzle and other parts which are already printed. + +*Support + +*Stair Step Height +Sets the balance between sturdy and hard to remove support. By setting steps of the stair-like bottom of the support resting on the model. + +*ZigZag +A new, infill type that’s easily breakable, introduced specially for support. + +*Support Roofs +A new sub-feature to reduce scars the support leaves on overhangs. +>>>>>>> 24c8773... Update changelog with corrections done after release *Support Towers Specialized support for tiny overhang areas. -*ZigZag infill -A new, infill type that’s easily breakable, introduced specially for support. +*Special Modes -* Avoid Printed Parts -While combing, the print head moves around printed parts, avoiding collisions with the nozzle and a part that’s already printed. +*Surface Mode +This mode will print the surface of the mesh instead of the enclosed volume. This used to be called ‘Only follow mesh surface’. In addition to the ‘surface mode’ and ‘normal’, a ‘both’ mode has now been added. This ensures all closed volumes are printed as normal and all loose geometry as single walls. + +*Experimental Features + +*Conical Support +An experimental filament, cost-reduction feature, for support. + +*Draft Shield +Prints a protective wall at a set distance around the object that prevents air from hitting the print, reducing warping. + +*Fuzzy Skin +Prints the outer walls with a jittering motion to give your object a diffuse finish. + +*Wire Printing +The object is printed with a mid-air / net-like structure, following the mesh surface. The build plate will move up and down during diagonal segments. Though not visible in layer view, you can view the result in other software, such as Repetier Host or http://chilipeppr.com/tinyg. From 36c185e92140b02ea030fb8668f776891d8764a8 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 13 Jul 2016 14:31:20 +0200 Subject: [PATCH 24/80] Remove stray git conflict markers --- plugins/ChangeLogPlugin/ChangeLog.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index fea618bd97..c989647fbb 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -39,10 +39,6 @@ Per-object settings allow you to override individual profile settings per object *Line Width Line width settings added per feature: Global, Walls, Top/Bottom, Infill, Skirt, Support. -<<<<<<< HEAD -* Conical Support -An experimental filament, cost-reduction feature, for support. -======= *Pattern Settings Pattern settings improved per feature: Top/Bottom, Infill, Support. From f92f0c52c6f0c10bfafd2f511151cea9c567ff23 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 13 Jul 2016 14:33:42 +0200 Subject: [PATCH 25/80] Another stray conflict marker --- plugins/ChangeLogPlugin/ChangeLog.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index c989647fbb..3d6ffd77c9 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -68,7 +68,6 @@ A new, infill type that’s easily breakable, introduced specially for support. *Support Roofs A new sub-feature to reduce scars the support leaves on overhangs. ->>>>>>> 24c8773... Update changelog with corrections done after release *Support Towers Specialized support for tiny overhang areas. From 66a64a7a2bed09fe29a3787b2163dc00f1e1bdb1 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 16:23:49 +0200 Subject: [PATCH 26/80] Removing object from a group is now possible CURA-1891 --- cura/CuraApplication.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 850657c33f..800f2a3b95 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -564,15 +564,17 @@ class CuraApplication(QtApplication): node = Selection.getSelectedObject(0) if node: + group_node = None if node.getParent(): group_node = node.getParent() - if not group_node.callDecoration("isGroup"): - op = RemoveSceneNodeOperation(node) - else: - while group_node.getParent().callDecoration("isGroup"): - group_node = group_node.getParent() - op = RemoveSceneNodeOperation(group_node) + op = RemoveSceneNodeOperation(node) + op.push() + if group_node: + if len(group_node.getChildren()) == 1: + group_node.getChildren()[0].setParent(group_node.getParent()) + op = RemoveSceneNodeOperation(group_node) + op.push() ## Create a number of copies of existing object. @pyqtSlot("quint64", int) From c92b2bc38571aef672369a39c082d20292baebd1 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 13 Jul 2016 17:22:54 +0200 Subject: [PATCH 27/80] Changed order of setting properties CURA-1842 --- resources/qml/Settings/SettingItem.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 5e37288f4a..69272764c9 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -215,8 +215,9 @@ Item { // This ensures that the value in any of the deeper containers need not be removed, which is // needed for the reset button (which deletes the top value) to correctly go back to profile // defaults. - propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) propertyProvider.setPropertyValue("state", "InstanceState.Calculated") + propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) + } } From 2c5644ff08adaeeff4584d270a11fac8dc14351b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 14 Jul 2016 08:55:53 +0200 Subject: [PATCH 28/80] Only show Machine Actions for the currently active machine Many machine actions act on the currently active printer, because they don't have a pointer to the printer selected on the Printer manager. --- resources/qml/Preferences/MachinesPage.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Preferences/MachinesPage.qml b/resources/qml/Preferences/MachinesPage.qml index d4f63d78fc..0dc3bb32eb 100644 --- a/resources/qml/Preferences/MachinesPage.qml +++ b/resources/qml/Preferences/MachinesPage.qml @@ -74,6 +74,7 @@ UM.ManagementPage Flow { id: machineActions + visible: currentItem && currentItem.id == Cura.MachineManager.activeMachineId anchors.left: parent.left anchors.right: parent.right anchors.top: machineName.bottom From 1c37dc2d3d3b8d49be12f936d2bcd2258f915056 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 14 Jul 2016 09:13:12 +0200 Subject: [PATCH 29/80] Better warning values for extruder prime pos Based on the machine dimensions and nozzle position. Contributes to issue CURA-1816. --- resources/definitions/fdmextruder.def.json | 12 ++++++------ resources/definitions/fdmprinter.def.json | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index bb14732493..4e3ee0a84f 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -152,8 +152,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "machine_nozzle_offset_x", + "maximum_value_warning": "machine_width", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -164,8 +164,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "machine_nozzle_offset_y", + "maximum_value_warning": "machine_depth", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -176,8 +176,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "0", + "maximum_value_warning": "machine_height", "settable_per_mesh": false, "settable_per_extruder": true } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d24d628fd9..6c39aaa330 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -333,8 +333,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "0", + "maximum_value_warning": "machine_width", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -345,8 +345,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "0", + "maximum_value_warning": "machine_depth", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -357,8 +357,8 @@ "type": "float", "unit": "mm", "default_value": 0, - "minimum_value_warning": "-1000", - "maximum_value_warning": "1000", + "minimum_value_warning": "0", + "maximum_value_warning": "machine_height", "settable_per_mesh": false, "settable_per_extruder": true }, From 775e7f153b1841fe75c420a89d67709ba12cb222 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 14 Jul 2016 11:26:56 +0200 Subject: [PATCH 30/80] Empty containers now have fdmprinter as definition CURA-1913 --- cura/CuraApplication.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 800f2a3b95..1aa2703e62 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -189,6 +189,11 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().load() + fdmprinter_definition = ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0] + empty_variant_container.setDefinition(fdmprinter_definition) + empty_material_container.setDefinition(fdmprinter_definition) + empty_quality_container.setDefinition(fdmprinter_definition) + Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") From e291a4360f5e7a92bc8ec1524c031234e50dccd5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 14 Jul 2016 17:02:26 +0200 Subject: [PATCH 31/80] Removed definitions from empty instance containers This caused empty profiles to pop up in dropdown. Issue is now fixed in _emptyInstanceContainer where it should be fixed CURA-1913 --- cura/CuraApplication.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1aa2703e62..800f2a3b95 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -189,11 +189,6 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().load() - fdmprinter_definition = ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0] - empty_variant_container.setDefinition(fdmprinter_definition) - empty_material_container.setDefinition(fdmprinter_definition) - empty_quality_container.setDefinition(fdmprinter_definition) - Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") From cd4774565b318faace7371a0d04e67d61ed26f64 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 14 Jul 2016 18:44:29 +0200 Subject: [PATCH 32/80] Add missing copyright notice --- cura/Settings/ContainerSettingsModel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Settings/ContainerSettingsModel.py b/cura/Settings/ContainerSettingsModel.py index 9ec19ed7fb..a0bdb7f41f 100644 --- a/cura/Settings/ContainerSettingsModel.py +++ b/cura/Settings/ContainerSettingsModel.py @@ -1,3 +1,6 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + from UM.Application import Application from UM.Qt.ListModel import ListModel From 528aa2d96195778ea7d245818a558c5ae6619432 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 1 Jul 2016 22:21:48 +0200 Subject: [PATCH 33/80] JSON feat: Gradual Infill Steps and Gradual Infill Step Height (CURA-836) --- resources/definitions/fdmprinter.def.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6c39aaa330..18960b8e08 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1006,6 +1006,28 @@ "value": "layer_height", "settable_per_mesh": true }, + "gradual_infill_steps": + { + "label": "Gradual Infill Steps", + "description": "Number of times to reduce the infill density by half when getting further below top surfaces. Areas which are closer to top surfaces get a higher density, up to the Infill Density.", + "default_value": 0, + "type": "int", + "minimum_value": "0", + "maximum_value_warning": "7", + "settable_per_mesh": true + }, + "gradual_infill_step_height": + { + "label": "Gradual Infill Step Height", + "description": "The height of infill of a given density before switching to half the density.", + "unit": "mm", + "type": "float", + "default_value": 5.0, + "minimum_value": "0.0001", + "maximum_value_warning": "100", + "enabled": "n_infill_steps > 0", + "settable_per_mesh": true + }, "infill_before_walls": { "label": "Infill Before Walls", From 59648569919e5aa44454bd4f302574c1ecf8f957 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Mon, 4 Jul 2016 14:22:14 +0200 Subject: [PATCH 34/80] JSON fix: n_infill_steps ==> gradual_infill_steps (CURA-836) --- 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 18960b8e08..cc855df3fa 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1025,7 +1025,7 @@ "default_value": 5.0, "minimum_value": "0.0001", "maximum_value_warning": "100", - "enabled": "n_infill_steps > 0", + "enabled": "gradual_infill_steps > 0", "settable_per_mesh": true }, "infill_before_walls": From 3e97e008af0c19b8c6b573f012591e967abc9495 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 14 Jul 2016 18:08:16 +0200 Subject: [PATCH 35/80] JSON fix: gradual infill has max value; warning value may be a bit lower (CURA-836) --- resources/definitions/fdmprinter.def.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index cc855df3fa..e108fadeda 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1013,7 +1013,8 @@ "default_value": 0, "type": "int", "minimum_value": "0", - "maximum_value_warning": "7", + "maximum_value_warning": "4", + "maximum_value": "19", "settable_per_mesh": true }, "gradual_infill_step_height": From a7e22e82b6c8f05ac7b539ec82fc25b4376ec94c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 11:20:08 +0200 Subject: [PATCH 36/80] Duplication now works regardles how deeply group nested a node is CURA-1578 --- cura/CuraApplication.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 800f2a3b95..08d46af4df 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -585,18 +585,16 @@ class CuraApplication(QtApplication): node = Selection.getSelectedObject(0) if node: + current_node = node + # Find the topmost group + while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): + current_node = current_node.getParent() + + new_node = copy.deepcopy(current_node) + op = GroupedOperation() for _ in range(count): - if node.getParent() and node.getParent().callDecoration("isGroup"): - new_node = copy.deepcopy(node.getParent()) #Copy the group node. - new_node.callDecoration("recomputeConvexHull") - - op.addOperation(AddSceneNodeOperation(new_node,node.getParent().getParent())) - else: - new_node = copy.deepcopy(node) - new_node.callDecoration("recomputeConvexHull") - op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) - + op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent())) op.push() ## Center object on platform. From 951e7bf629887118ee9a0837974a573106ec4bba Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 11:40:43 +0200 Subject: [PATCH 37/80] Refusing to change material actually prevents material from being changed CURA-1909 --- cura/Settings/MachineManager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 23335e3e63..fe451e74f6 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -126,6 +126,9 @@ class MachineManager(QObject): self._auto_change_material_hotend_flood_time = time.time() self._auto_change_material_hotend_flood_last_choice = button + if button == QMessageBox.No: + return + Logger.log("d", "Setting hotend variant of hotend %d to %s" % (index, hotend_id)) extruder_manager = ExtruderManager.getInstance() @@ -174,6 +177,9 @@ class MachineManager(QObject): self._auto_change_material_hotend_flood_time = time.time() self._auto_change_material_hotend_flood_last_choice = button + if button == QMessageBox.No: + return + Logger.log("d", "Setting material of hotend %d to %s" % (index, material_id)) extruder_manager = ExtruderManager.getInstance() From 806197f56bbde3dc9587ceaad4d489d680324e3a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 12:10:09 +0200 Subject: [PATCH 38/80] Only basename is used for the name CURA-1680 --- cura/PrintInformation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 5432da5dcc..52c53a34a7 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -81,6 +81,9 @@ class PrintInformation(QObject): @pyqtSlot(str) def setJobName(self, name): + # Ensure that we don't use entire path but only filename + name = os.path.basename(name) + # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] From 29457ab11f723bb28d08016971bf3d5c6d3c3f16 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 1 Jul 2016 00:39:04 +0200 Subject: [PATCH 39/80] JSON fix: support roof extruder could be chosen even when roofs weren't enabled (CURA-1723) just putting this commit under that issue so that it will be reviewed... --- 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 6c39aaa330..8cb7f9cb5d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2998,7 +2998,7 @@ "type": "extruder", "default_value": "0", "value": "support_extruder_nr", - "enabled": "support_enable", + "enabled": "support_enable and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false } From 42d400d4369ffb68859f42b16f4d196fdf8c98ba Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 1 Jul 2016 00:56:48 +0200 Subject: [PATCH 40/80] JSON feat: cubic isometric infill (CURA-1723) --- resources/definitions/fdmprinter.def.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8cb7f9cb5d..0fc65b2734 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -904,7 +904,7 @@ "type": "float", "default_value": 2, "minimum_value": "0", - "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else 1))", + "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else (3 if infill_pattern == \"cubic\" else 1)))", "settable_per_mesh": true } } @@ -912,12 +912,13 @@ "infill_pattern": { "label": "Infill Pattern", - "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle and concentric patterns are fully printed every layer.", + "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, cubic, triangle and concentric patterns are fully printed every layer.", "type": "enum", "options": { "grid": "Grid", "lines": "Lines", + "cubic": "Cubic", "triangles": "Triangles", "concentric": "Concentric", "zigzag": "Zig Zag" From 026fd3e2ddf375ae74b42be0332669dc3a9f32b1 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 15 Jul 2016 12:57:37 +0200 Subject: [PATCH 41/80] feat: tetrahedral infill (CURA-1925) --- resources/definitions/fdmprinter.def.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 0fc65b2734..059e2a25e2 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -904,7 +904,7 @@ "type": "float", "default_value": 2, "minimum_value": "0", - "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else (3 if infill_pattern == \"cubic\" else 1)))", + "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" or infill_pattern == \"cubic\" else (4 if infill_pattern == \"tetrahedral\" else 1)))", "settable_per_mesh": true } } @@ -912,14 +912,15 @@ "infill_pattern": { "label": "Infill Pattern", - "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, cubic, triangle and concentric patterns are fully printed every layer.", + "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, cubic, tetrahedral and concentric patterns are fully printed every layer. Cubic and tetrahedral infill change with every layer to provide a more equal distribution of strength over each direction.", "type": "enum", "options": { "grid": "Grid", "lines": "Lines", - "cubic": "Cubic", "triangles": "Triangles", + "cubic": "Cubic", + "tetrahedral": "Tetrahedral", "concentric": "Concentric", "zigzag": "Zig Zag" }, From bd183266c671e18d050ede9567fc9980ac1a3f28 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 13:11:36 +0200 Subject: [PATCH 42/80] Forced size of heatup buttons in checkup CURA-422 --- plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml index 86429ed119..34544dca75 100644 --- a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml +++ b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml @@ -196,8 +196,8 @@ Cura.MachineAction visible: checkupMachineAction.usbConnected Button { + height: 20 text: checkupMachineAction.heatupHotendStarted ? catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") - // onClicked: { if (checkupMachineAction.heatupHotendStarted) @@ -259,6 +259,7 @@ Cura.MachineAction Button { text: checkupMachineAction.heatupBedStarted ?catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") + height: 20 onClicked: { if (checkupMachineAction.heatupBedStarted) From d48b4bf7901b197854b7833df6c265efe207f494 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 13:23:25 +0200 Subject: [PATCH 43/80] Material GUID is now sent to engine for each extruder CURA-1836 --- plugins/CuraEngineBackend/StartSliceJob.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 6aa9c4660b..5b715230e2 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -180,6 +180,12 @@ class StartSliceJob(Job): setting.value = str(stack.getProperty(key, "value")).encode("utf-8") Job.yieldThread() + # ALso send the material GUID as a setting. + material_instance_container = stack.findContainer({"type": "material"}) + if material_instance_container: + setting = message.getMessage("settings").addRepeatedMessage("settings") + setting.name = "material_GUID" + setting.value = str(material_instance_container.getMetaDataEntry("GUID", "")).encode("utf-8") ## Sends all global settings to the engine. # # The settings are taken from the global stack. This does not include any From 942539981b8d9b9464916d1546b2bebc45cbc2c6 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 15 Jul 2016 13:27:50 +0200 Subject: [PATCH 44/80] JSON fix: moved prime location to category platform_adhesion (CURA-1816) --- resources/definitions/fdmextruder.def.json | 34 +++++++++------ resources/definitions/fdmprinter.def.json | 48 +++++++++++----------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 4e3ee0a84f..f602441ff3 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -145,6 +145,28 @@ "settable_per_meshgroup": false, "settable_globally": false }, + "extruder_prime_pos_z": + { + "label": "Extruder Prime Z Position", + "description": "The Z coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "0", + "maximum_value_warning": "machine_height", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } + }, + "platform_adhesion": + { + "label": "Platform Adhesion", + "type": "category", + "icon": "category_adhesion", + "description": "Adhesion", + "children": + { "extruder_prime_pos_x": { "label": "Extruder Prime X Position", @@ -168,18 +190,6 @@ "maximum_value_warning": "machine_depth", "settable_per_mesh": false, "settable_per_extruder": true - }, - "extruder_prime_pos_z": - { - "label": "Extruder Prime Z Position", - "description": "The Z coordinate of the position where the nozzle primes at the start of printing.", - "type": "float", - "unit": "mm", - "default_value": 0, - "minimum_value_warning": "0", - "maximum_value_warning": "machine_height", - "settable_per_mesh": false, - "settable_per_extruder": true } } } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 059e2a25e2..7894507645 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -326,30 +326,6 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, - "extruder_prime_pos_x": - { - "label": "Extruder Prime X Position", - "description": "The X coordinate of the position where the nozzle primes at the start of printing.", - "type": "float", - "unit": "mm", - "default_value": 0, - "minimum_value_warning": "0", - "maximum_value_warning": "machine_width", - "settable_per_mesh": false, - "settable_per_extruder": true - }, - "extruder_prime_pos_y": - { - "label": "Extruder Prime Y Position", - "description": "The Y coordinate of the position where the nozzle primes at the start of printing.", - "type": "float", - "unit": "mm", - "default_value": 0, - "minimum_value_warning": "0", - "maximum_value_warning": "machine_depth", - "settable_per_mesh": false, - "settable_per_extruder": true - }, "extruder_prime_pos_z": { "label": "Extruder Prime Z Position", @@ -2448,6 +2424,30 @@ "description": "Adhesion", "children": { + "extruder_prime_pos_x": + { + "label": "Extruder Prime X Position", + "description": "The X coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "0", + "maximum_value_warning": "machine_width", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_y": + { + "label": "Extruder Prime Y Position", + "description": "The Y coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "0", + "maximum_value_warning": "machine_depth", + "settable_per_mesh": false, + "settable_per_extruder": true + }, "adhesion_type": { "label": "Platform Adhesion Type", From a52095df0e5840c3fc5073b6eb95c1a0d791e490 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 15 Jul 2016 13:32:43 +0200 Subject: [PATCH 45/80] JSON fix: disabled prime location by default (CURA-1816) --- resources/definitions/fdmextruder.def.json | 6 ++++-- resources/definitions/fdmprinter.def.json | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index f602441ff3..7ce44b77b0 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -177,7 +177,8 @@ "minimum_value_warning": "machine_nozzle_offset_x", "maximum_value_warning": "machine_width", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "enabled": false }, "extruder_prime_pos_y": { @@ -189,7 +190,8 @@ "minimum_value_warning": "machine_nozzle_offset_y", "maximum_value_warning": "machine_depth", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "enabled": false } } } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 7894507645..8833c175f3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2434,7 +2434,8 @@ "minimum_value_warning": "0", "maximum_value_warning": "machine_width", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "enabled": false }, "extruder_prime_pos_y": { @@ -2446,7 +2447,8 @@ "minimum_value_warning": "0", "maximum_value_warning": "machine_depth", "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_extruder": true, + "enabled": false }, "adhesion_type": { From 8029139358340f2bd1a58df63cd34a4d2be6d6ef Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Fri, 15 Jul 2016 13:54:56 +0200 Subject: [PATCH 46/80] JSON fix: making max gradual infill steps lower to allow for engine not crashing when setting the infill to a low percentage (CURA-836) --- 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 e108fadeda..724919c07a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1014,7 +1014,7 @@ "type": "int", "minimum_value": "0", "maximum_value_warning": "4", - "maximum_value": "19", + "maximum_value": "17", "settable_per_mesh": true }, "gradual_infill_step_height": From 7a431646540f67fea81473c6d20e4b19c46e568d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 15:49:25 +0200 Subject: [PATCH 47/80] Both material weights & lengths are now exposed CURA-1038 --- cura/PrintInformation.py | 35 +++++++++++++++++++++------- plugins/SliceInfoPlugin/SliceInfo.py | 2 +- resources/qml/JobSpecs.qml | 2 +- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 52c53a34a7..6ba1274a49 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -7,6 +7,8 @@ from UM.Application import Application from UM.Qt.Duration import Duration from UM.Preferences import Preferences +import cura.Settings.ExtruderManager + import math import os.path import unicodedata @@ -44,7 +46,8 @@ class PrintInformation(QObject): self._current_print_time = Duration(None, self) - self._material_amounts = [] + self._material_lengths = [] + self._material_weights = [] self._backend = Application.getInstance().getBackend() if self._backend: @@ -62,11 +65,17 @@ class PrintInformation(QObject): def currentPrintTime(self): return self._current_print_time - materialAmountsChanged = pyqtSignal() + materialLengthsChanged = pyqtSignal() - @pyqtProperty("QVariantList", notify = materialAmountsChanged) - def materialAmounts(self): - return self._material_amounts + @pyqtProperty("QVariantList", notify = materialLengthsChanged) + def materialLengths(self): + return self._material_lengths + + materialWeightsChanged = pyqtSignal() + + @pyqtProperty("QVariantList", notify = materialWeightsChanged) + def materialWeights(self): + return self._material_weights def _onPrintDurationMessage(self, total_time, material_amounts): self._current_print_time.setDuration(total_time) @@ -74,10 +83,18 @@ class PrintInformation(QObject): # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 - self._material_amounts = [] - for amount in material_amounts: - self._material_amounts.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) - self.materialAmountsChanged.emit() + self._material_lengths = [] + self._material_weights = [] + extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId())) + for index, amount in enumerate(material_amounts): + ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some + # list comprehension filtering to solve this for us. + extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0] + density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) + self._material_weights.append(float(amount) * float(density)) + self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) + self.materialLengthsChanged.emit() + self.materialWeightsChanged.emit() @pyqtSlot(str) def setJobName(self, name): diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 39a55702ab..913ad467c5 100644 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -59,7 +59,7 @@ class SliceInfo(Extension): material_radius = 0.5 * global_container_stack.getProperty("material_diameter", "value") # TODO: Send material per extruder instead of mashing it on a pile - material_used = math.pi * material_radius * material_radius * sum(print_information.materialAmounts) #Volume of all materials used + material_used = math.pi * material_radius * material_radius * sum(print_information.materialLengths) #Volume of all materials used # Get model information (bounding boxes, hashes and transformation matrix) models_info = [] diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index db58b5ee4e..40eb9cd250 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -24,7 +24,7 @@ Rectangle { UM.I18nCatalog { id: catalog; name:"cura"} property variant printDuration: PrintInformation.currentPrintTime - property variant printMaterialAmounts: PrintInformation.materialAmounts + property variant printMaterialAmounts: PrintInformation.materialLengths height: childrenRect.height color: "transparent" From dcc3bc8f80c1ecaabd3786aadc507e8289558627 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 15:56:39 +0200 Subject: [PATCH 48/80] Also refactored name of printlength in jobspecs.qml CURA-1836 --- resources/qml/JobSpecs.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 40eb9cd250..8e14241741 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -24,7 +24,8 @@ Rectangle { UM.I18nCatalog { id: catalog; name:"cura"} property variant printDuration: PrintInformation.currentPrintTime - property variant printMaterialAmounts: PrintInformation.materialLengths + property variant printMaterialLengths: PrintInformation.materialLengths + property variant printMaterialWeights: PrintInformation.materialWeights height: childrenRect.height color: "transparent" @@ -195,9 +196,9 @@ Rectangle { text: { var amounts = []; - if(base.printMaterialAmounts) { - for(var index = 0; index < base.printMaterialAmounts.length; index++) { - amounts.push(base.printMaterialAmounts[index].toFixed(2)); + if(base.printMaterialLengths) { + for(var index = 0; index < base.printMaterialLengths.length; index++) { + amounts.push(base.printMaterialLengths[index].toFixed(2)); } } else { amounts = ["0.00"]; From 56efb92f3e58ca88b984c21291a590733afbb087 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 15 Jul 2016 16:04:02 +0200 Subject: [PATCH 49/80] Added additional decoration to UpdateQualityContainerFromUserContainer This allows the usage from QML withouth parameters. CURA-1890 --- cura/Settings/MachineManager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index fe451e74f6..4b3141f900 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -499,6 +499,7 @@ class MachineManager(QObject): self.activeQualityChanged.emit() @pyqtSlot(str) + @pyqtSlot() def updateQualityContainerFromUserContainer(self, quality_id = None): if not self._active_container_stack: return From c2fab4da4728aa95e07f93b6f5cbb79aad28cae8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 18 Jul 2016 10:25:51 +0200 Subject: [PATCH 50/80] Print information handles single extrusion machines correctly again CURA-1931 and CURA-1038 --- cura/PrintInformation.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 6ba1274a49..4dedf9db16 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -89,8 +89,12 @@ class PrintInformation(QObject): for index, amount in enumerate(material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. - extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0] - density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) + if extruder_stacks: # Multi extrusion machine + extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0] + density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) + else: # Machine with no extruder stacks + density = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("properties", {}).get("density", 0) + self._material_weights.append(float(amount) * float(density)) self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) self.materialLengthsChanged.emit() From 48d39ce3876937b414f76d6bcee70d06bf86565a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 18 Jul 2016 11:46:12 +0200 Subject: [PATCH 51/80] material_guid is now also a setting in fdmprinter CURA-1836 --- plugins/CuraEngineBackend/StartSliceJob.py | 15 ++++++++------- resources/definitions/fdmprinter.def.json | 8 ++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 5b715230e2..a726e239e0 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -174,18 +174,19 @@ class StartSliceJob(Job): def _buildExtruderMessage(self, stack): message = self._slice_message.addRepeatedMessage("extruders") message.id = int(stack.getMetaDataEntry("position")) + + material_instance_container = stack.findContainer({"type": "material"}) + for key in stack.getAllKeys(): setting = message.getMessage("settings").addRepeatedMessage("settings") setting.name = key - setting.value = str(stack.getProperty(key, "value")).encode("utf-8") + if key == "material_guid" and material_instance_container: + # Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it. + setting.value = str(material_instance_container.getMetaDataEntry("GUID", "")).encode("utf-8") + else: + setting.value = str(stack.getProperty(key, "value")).encode("utf-8") Job.yieldThread() - # ALso send the material GUID as a setting. - material_instance_container = stack.findContainer({"type": "material"}) - if material_instance_container: - setting = message.getMessage("settings").addRepeatedMessage("settings") - setting.name = "material_GUID" - setting.value = str(material_instance_container.getMetaDataEntry("GUID", "")).encode("utf-8") ## Sends all global settings to the engine. # # The settings are taken from the global stack. This does not include any diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8833c175f3..c54b8e85f4 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -57,6 +57,14 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "material_guid": + { + "label": "Material GUID", + "description": "GUID of the material. This is set automatically. ", + "default_value": "", + "type": "str", + "enabled": false + }, "material_bed_temp_wait": { "label": "Wait for bed heatup", From 3e908824b9f2de309605cea892c9942a0a7f8c4a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 18 Jul 2016 15:16:20 +0200 Subject: [PATCH 52/80] Added workaround for singleton not getting shortcuts CURA-1603 --- resources/qml/Cura.qml | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index f70dffa3cc..38019de8e2 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -506,6 +506,64 @@ UM.MainWindow onTriggered: preferences.getCurrentItem().showProfileNameDialog() } + // Workaround for shortcuts not working for singletons. + // The main window eats all the events, so we need to pass them manually. + Action + { + shortcut: StandardKey.Undo + onTriggered: Cura.Actions.undo.trigger() + } + Action + { + shortcut: StandardKey.Redo + onTriggered: Cura.Actions.redo.trigger() + } + Action + { + shortcut: StandardKey.Quit + onTriggered: Cura.Actions.quit.trigger() + } + Action + { + shortcut: StandardKey.Help + onTriggered: Cura.Actions.help.trigger() + } + Action + { + shortcut: StandardKey.Delete + onTriggered: Cura.Actions.delete.trigger() + } + Action + { + shortcut: "Ctrl+G" + onTriggered: Cura.Actions.groupObjects.trigger() + } + Action + { + shortcut: "Ctrl+Shift+G" + onTriggered: Cura.Actions.unGroupObjects.trigger() + } + Action + { + shortcut: "Ctrl+Alt+G" + onTriggered: Cura.Actions.mergeObjects.trigger() + } + Action + { + shortcut: "Ctrl+D" + onTriggered: Cura.Actions.deleteAll.trigger() + } + Action + { + shortcut: StandardKey.Open + onTriggered: Cura.Actions.open.trigger() + } + Action + { + shortcut: StandardKey.WhatsThis + onTriggered: Cura.Actions.showEngineLog.trigger() + } + Menu { id: objectContextMenu; From 3e4ff9241ed4444f41e402a983c7f690ad89ca84 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 18 Jul 2016 15:38:57 +0200 Subject: [PATCH 53/80] Moved the BlurSettings signal to cura main window This reduces the number of focus changes from O(N) to O(1) by the blur event --- resources/qml/Cura.qml | 11 +++++++++++ resources/qml/Settings/SettingItem.qml | 9 --------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 38019de8e2..604f8e0b92 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -506,6 +506,17 @@ UM.MainWindow onTriggered: preferences.getCurrentItem().showProfileNameDialog() } + // BlurSettings is a way to force the focus away from any of the setting items. + // We need to do this in order to keep the bindings intact. + Connections + { + target: Cura.MachineManager + onBlurSettings: + { + contentItem.focus = true + } + } + // Workaround for shortcuts not working for singletons. // The main window eats all the events, so we need to pass them manually. Action diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 69272764c9..a7bdabb3c5 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -248,14 +248,5 @@ Item { } } - Connections - { - target: Cura.MachineManager - onBlurSettings: - { - revertButton.focus = true - } - } - UM.I18nCatalog { id: catalog; name: "cura" } } From b3837fbafd5c404fe0219efcdc2dbf007a547eb9 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 18 Jul 2016 16:02:24 +0200 Subject: [PATCH 54/80] Raft thickness lowers the build volume. CURA-1707 Now adding more visuals for better UX. --- cura/BuildVolume.py | 34 +++++++++++++++++-- cura/CuraApplication.py | 7 ++-- cura/PlatformPhysics.py | 6 ++-- .../ProcessSlicedLayersJob.py | 5 ++- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index b438365f78..2024ae5adc 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the AGPLv3 or higher. from UM.i18n import i18nCatalog +from UM.Scene.Platform import Platform from UM.Scene.SceneNode import SceneNode from UM.Application import Application from UM.Resources import Resources @@ -41,6 +42,9 @@ class BuildVolume(SceneNode): self.setCalculateBoundingBox(False) self._volume_aabb = None + self.raft_thickness = 0.0 + self._platform = Platform(self) + self._active_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() @@ -172,6 +176,21 @@ class BuildVolume(SceneNode): " \"Print Sequence\" setting to prevent the gantry from colliding" " with printed objects."), lifetime=10).show() + def _updateRaftThickness(self): + old_raft_thickness = self.raft_thickness + adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value") + self.raft_thickness = 0.0 + if adhesion_type == "raft": + self.raft_thickness = ( + self._active_container_stack.getProperty("raft_base_thickness", "value") + + self._active_container_stack.getProperty("raft_interface_thickness", "value") + + self._active_container_stack.getProperty("raft_surface_layers", "value") * + self._active_container_stack.getProperty("raft_surface_thickness", "value") + + self._active_container_stack.getProperty("raft_airgap", "value")) + # Rounding errors do not matter, we check if raft_thickness has changed at all + if old_raft_thickness != self.raft_thickness: + self.setPosition(Vector(0, -self.raft_thickness, 0), SceneNode.TransformSpace.World) + def _onGlobalContainerStackChanged(self): if self._active_container_stack: self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged) @@ -190,6 +209,7 @@ class BuildVolume(SceneNode): self._depth = self._active_container_stack.getProperty("machine_depth", "value") self._updateDisallowedAreas() + self._updateRaftThickness() self.rebuild() @@ -197,15 +217,24 @@ class BuildVolume(SceneNode): if property_name != "value": return + rebuild_me = False if setting_key == "print_sequence": if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time": self._height = self._active_container_stack.getProperty("gantry_height", "value") self._buildVolumeMessage() else: self._height = self._active_container_stack.getProperty("machine_height", "value") - self.rebuild() + rebuild_me = True + if setting_key in self._skirt_settings: self._updateDisallowedAreas() + rebuild_me = True + + if setting_key in self._raft_settings: + self._updateRaftThickness() + rebuild_me = True + + if rebuild_me: self.rebuild() def _updateDisallowedAreas(self): @@ -269,7 +298,7 @@ class BuildVolume(SceneNode): self._disallowed_areas = areas - ## Convenience function to calculate the size of the bed adhesion. + ## Convenience function to calculate the size of the bed adhesion in directions x, y. def _getSkirtSize(self, container_stack): skirt_size = 0.0 @@ -295,3 +324,4 @@ class BuildVolume(SceneNode): return max(min(value, max_value), min_value) _skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"] + _raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"] diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 08d46af4df..1164c57008 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -4,7 +4,6 @@ from UM.Qt.QtApplication import QtApplication from UM.Scene.SceneNode import SceneNode from UM.Scene.Camera import Camera -from UM.Scene.Platform import Platform as Scene_Platform from UM.Math.Vector import Vector from UM.Math.Quaternion import Quaternion from UM.Math.AxisAlignedBox import AxisAlignedBox @@ -144,7 +143,6 @@ class CuraApplication(QtApplication): ]) self._physics = None self._volume = None - self._platform = None self._output_devices = {} self._print_information = None self._previous_active_tool = None @@ -377,8 +375,8 @@ class CuraApplication(QtApplication): Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() - self._platform = Scene_Platform(root) + # The platform is a child of BuildVolume self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) @@ -857,3 +855,6 @@ class CuraApplication(QtApplication): @pyqtSlot("QSize") def setMinimumWindowSize(self, size): self.getMainWindow().setMinimumSize(size) + + def getBuildVolume(self): + return self._volume \ No newline at end of file diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 0c9c933899..191f7b0e27 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -40,6 +40,7 @@ class PlatformPhysics: return root = self._controller.getScene().getRoot() + for node in BreadthFirstIterator(root): if node is root or type(node) is not SceneNode or node.getBoundingBox() is None: continue @@ -58,10 +59,7 @@ class PlatformPhysics: move_vector = Vector() if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0 - if bbox.bottom > 0: - move_vector = move_vector.set(y=-bbox.bottom + z_offset) - elif bbox.bottom < z_offset: - move_vector = move_vector.set(y=(-bbox.bottom) - z_offset) + move_vector = move_vector.set(y=-bbox.bottom + z_offset) # If there is no convex hull for the node, start calculating it and continue. if not node.getDecorator(ConvexHullDecorator): diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index d23f71e874..ab504f276d 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -128,7 +128,10 @@ class ProcessSlicedLayersJob(Job): new_node.addDecorator(decorator) new_node.setMeshData(mesh) - new_node.setParent(self._scene.getRoot()) # Note: After this we can no longer abort! + # Set build volume as parent, the build volume can move as a result of raft settings. + # It makes sense to set the build volume as parent: the print is actually printed on it. + new_node_parent = Application.getInstance().getBuildVolume() + new_node.setParent(new_node_parent) # Note: After this we can no longer abort! settings = Application.getInstance().getGlobalContainerStack() if not settings.getProperty("machine_center_is_zero", "value"): From 31901606b892a4a5235eaabd1b44f9137f304ea1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 18 Jul 2016 16:01:18 +0200 Subject: [PATCH 55/80] Properly translate default profiles Otherwise the machine instance doesn't get loaded. Contributes to issue CURA-844. --- .../VersionUpgrade21to22/VersionUpgrade21to22.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py index a45a4a6e79..2493e23405 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py @@ -18,7 +18,11 @@ _printer_translations = { _profile_translations = { "PLA": "generic_pla", "ABS": "generic_abs", - "CPE": "generic_cpe" + "CPE": "generic_cpe", + "Low Quality": "low", + "Normal Quality": "normal", + "High Quality": "high", + "Ulti Quality": "high" #This one doesn't have an equivalent. Map it to high. } ## How to translate setting names from the old version to the new. From 0e6a46c9ebedfc8655d34b16b52e4afef983e797 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 18 Jul 2016 16:50:39 +0200 Subject: [PATCH 56/80] Use a simpler fix for dealing with QML Action's shortcuts not working It is a bit more magical (hence the added documentation) but it makes things a lot more transparent. This prevents a lot of future issues. Contributes to CURA-1603 --- resources/qml/Cura.qml | 70 ++++++++---------------------------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 604f8e0b92..8404db01fa 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -22,6 +22,18 @@ UM.MainWindow Component.onCompleted: { Printer.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size")) + + // Workaround silly issues with QML Action's shortcut property. + // + // Currently, there is no way to define shortcuts as "Application Shortcut". + // This means that all Actions are "Window Shortcuts". The code for this + // implements a rather naive check that just checks if any of the action's parents + // are a window. Since the "Actions" object is a singleton it has no parent by + // default. If we set its parent to something contained in this window, the + // shortcut will activate properly because one of its parents is a window. + // + // This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property. + Cura.Actions.parent = backgroundItem } Item @@ -517,64 +529,6 @@ UM.MainWindow } } - // Workaround for shortcuts not working for singletons. - // The main window eats all the events, so we need to pass them manually. - Action - { - shortcut: StandardKey.Undo - onTriggered: Cura.Actions.undo.trigger() - } - Action - { - shortcut: StandardKey.Redo - onTriggered: Cura.Actions.redo.trigger() - } - Action - { - shortcut: StandardKey.Quit - onTriggered: Cura.Actions.quit.trigger() - } - Action - { - shortcut: StandardKey.Help - onTriggered: Cura.Actions.help.trigger() - } - Action - { - shortcut: StandardKey.Delete - onTriggered: Cura.Actions.delete.trigger() - } - Action - { - shortcut: "Ctrl+G" - onTriggered: Cura.Actions.groupObjects.trigger() - } - Action - { - shortcut: "Ctrl+Shift+G" - onTriggered: Cura.Actions.unGroupObjects.trigger() - } - Action - { - shortcut: "Ctrl+Alt+G" - onTriggered: Cura.Actions.mergeObjects.trigger() - } - Action - { - shortcut: "Ctrl+D" - onTriggered: Cura.Actions.deleteAll.trigger() - } - Action - { - shortcut: StandardKey.Open - onTriggered: Cura.Actions.open.trigger() - } - Action - { - shortcut: StandardKey.WhatsThis - onTriggered: Cura.Actions.showEngineLog.trigger() - } - Menu { id: objectContextMenu; From 62496753627591a4a135b6beabaf87c632a85ace Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 18 Jul 2016 17:18:25 +0200 Subject: [PATCH 57/80] Removed stray debug prints CURA-1669 --- cura/Settings/MachineManager.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 4b3141f900..2b2135e4a3 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -788,13 +788,10 @@ class MachineManager(QObject): return self._empty_quality_container def _onMachineNameChanged(self): - print("machine name changed") self.globalContainerChanged.emit() def _onMaterialNameChanged(self): - print("material name changed") self.activeMaterialChanged.emit() def _onQualityNameChanged(self): - print("quality name changed") self.activeQualityChanged.emit() From dec94443db2e51065bca64ca5a5bd993bd5776f4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 18 Jul 2016 19:39:47 +0200 Subject: [PATCH 58/80] Initialise extruder quality profile to a profile that is appropriate for this machine/variant/material Fixes CURA-1926 --- cura/Settings/ExtruderManager.py | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 079b01598e..c736d89990 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -187,18 +187,27 @@ class ExtruderManager(QObject): # Find a quality to use for this extruder. quality = container_registry.getEmptyInstanceContainer() - # First add any quality. Later, overwrite with preference if the preference is valid. - qualities = container_registry.findInstanceContainers(type = "quality") - if len(qualities) >= 1: - quality = qualities[0] - preferred_quality_id = machine_definition.getMetaDataEntry("preferred_quality") - if preferred_quality_id: - preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id, type = "quality") - if len(preferred_quality) >= 1: - quality = preferred_quality[0] - else: - UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality_id, machine_id) - # And leave it at the default quality. + search_criteria = { "type": "quality" } + if machine_definition.getMetaDataEntry("has_machine_quality"): + search_criteria["definition"] = machine_definition.id + if machine_definition.getMetaDataEntry("has_materials") and material: + search_criteria["material"] = material.id + else: + search_criteria["definition"] = "fdmprinter" + + preferred_quality = machine_definition.getMetaDataEntry("preferred_quality") + if preferred_quality: + search_criteria["id"] = preferred_quality + + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) + if not containers and preferred_quality: + UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality, machine_id) + search_criteria.pop("id", None) + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) + if containers: + quality = containers[0] + + container_stack.addContainer(containers[0]) container_stack.addContainer(quality) user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id) From 4b7066e55bd222ae8c1cf3a7880bce276e9ab200 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 19 Jul 2016 08:29:47 +0200 Subject: [PATCH 59/80] Fix adding quality profile to stack twice CURA-1926 --- cura/Settings/ExtruderManager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index c736d89990..744a6811c5 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -207,7 +207,6 @@ class ExtruderManager(QObject): if containers: quality = containers[0] - container_stack.addContainer(containers[0]) container_stack.addContainer(quality) user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id) From fd96e471179e5932a52211dc13cdf8445d3739cc Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 19 Jul 2016 09:25:36 +0200 Subject: [PATCH 60/80] Removed fixed height for checkup buttons again. Turned out that this was already fixed, so a fixed height isn't needed. CURA-422 --- plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml index 34544dca75..14ed1e2c51 100644 --- a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml +++ b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml @@ -196,7 +196,6 @@ Cura.MachineAction visible: checkupMachineAction.usbConnected Button { - height: 20 text: checkupMachineAction.heatupHotendStarted ? catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") onClicked: { @@ -259,7 +258,6 @@ Cura.MachineAction Button { text: checkupMachineAction.heatupBedStarted ?catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") - height: 20 onClicked: { if (checkupMachineAction.heatupBedStarted) From 3bcd96533fcf5a70761512dc2833629d15597066 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 19 Jul 2016 10:25:03 +0200 Subject: [PATCH 61/80] Finished making visible raft plane. CURA-1707 --- cura/BuildVolume.py | 64 ++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 2024ae5adc..e85a852441 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -20,6 +20,25 @@ catalog = i18nCatalog("cura") import numpy +def approximatedCircleVertices(r): + """ + Return vertices from an approximated circle. + :param r: radius + :return: numpy 2-array with the vertices + """ + + return numpy.array([ + [-r, 0], + [-r * 0.707, r * 0.707], + [0, r], + [r * 0.707, r * 0.707], + [r, 0], + [r * 0.707, -r * 0.707], + [0, -r], + [-r * 0.707, -r * 0.707] + ], numpy.float32) + + ## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas. class BuildVolume(SceneNode): VolumeOutlineColor = Color(12, 169, 227, 255) @@ -42,7 +61,9 @@ class BuildVolume(SceneNode): self.setCalculateBoundingBox(False) self._volume_aabb = None - self.raft_thickness = 0.0 + self._raft_thickness = 0.0 + self._adhesion_type = None + self._raft_mesh = None self._platform = Platform(self) self._active_container_stack = None @@ -76,6 +97,9 @@ class BuildVolume(SceneNode): renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True) if self._disallowed_area_mesh: renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9) + if self._raft_mesh and self._adhesion_type == "raft": + renderer.queueNode(self, mesh=self._raft_mesh, transparent=True, backface_cull=True, sort=-9) + return True ## Recalculates the build volume & disallowed areas. @@ -92,6 +116,7 @@ class BuildVolume(SceneNode): mb = MeshBuilder() + # Outline 'cube' of the build volume mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) @@ -116,11 +141,23 @@ class BuildVolume(SceneNode): Vector(max_w, min_h - 0.2, max_d), Vector(min_w, min_h - 0.2, max_d) ) + for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() + # Build raft mesh: a plane on the height of the raft. + mb = MeshBuilder() + mb.addQuad( + Vector(min_w, self._raft_thickness, min_d), + Vector(max_w, self._raft_thickness, min_d), + Vector(max_w, self._raft_thickness, max_d), + Vector(min_w, self._raft_thickness, max_d), + color=Color(128, 128, 128, 64) + ) + self._raft_mesh = mb.build() + disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: @@ -177,19 +214,19 @@ class BuildVolume(SceneNode): " with printed objects."), lifetime=10).show() def _updateRaftThickness(self): - old_raft_thickness = self.raft_thickness - adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value") - self.raft_thickness = 0.0 - if adhesion_type == "raft": - self.raft_thickness = ( + old_raft_thickness = self._raft_thickness + self._adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value") + self._raft_thickness = 0.0 + if self._adhesion_type == "raft": + self._raft_thickness = ( self._active_container_stack.getProperty("raft_base_thickness", "value") + self._active_container_stack.getProperty("raft_interface_thickness", "value") + self._active_container_stack.getProperty("raft_surface_layers", "value") * self._active_container_stack.getProperty("raft_surface_thickness", "value") + self._active_container_stack.getProperty("raft_airgap", "value")) # Rounding errors do not matter, we check if raft_thickness has changed at all - if old_raft_thickness != self.raft_thickness: - self.setPosition(Vector(0, -self.raft_thickness, 0), SceneNode.TransformSpace.World) + if old_raft_thickness != self._raft_thickness: + self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World) def _onGlobalContainerStackChanged(self): if self._active_container_stack: @@ -250,16 +287,7 @@ class BuildVolume(SceneNode): # Extend every area already in the disallowed_areas with the skirt size. for area in disallowed_areas: poly = Polygon(numpy.array(area, numpy.float32)) - poly = poly.getMinkowskiHull(Polygon(numpy.array([ - [-skirt_size, 0], - [-skirt_size * 0.707, skirt_size * 0.707], - [0, skirt_size], - [skirt_size * 0.707, skirt_size * 0.707], - [skirt_size, 0], - [skirt_size * 0.707, -skirt_size * 0.707], - [0, -skirt_size], - [-skirt_size * 0.707, -skirt_size * 0.707] - ], numpy.float32))) + poly = poly.getMinkowskiHull(Polygon(approximatedCircleVertices(skirt_size))) areas.append(poly) From a9aa46e32bf1c121be471609e0fd8271d522f5e6 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 19 Jul 2016 11:04:29 +0200 Subject: [PATCH 62/80] Fixed prime location due to definition -> stack change. --- cura/BuildVolume.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 38922ab4a5..1709a67dd5 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -19,6 +19,7 @@ from UM.View.GL.OpenGL import OpenGL catalog = i18nCatalog("cura") import numpy +import copy # Setting for clearance around the prime @@ -283,17 +284,16 @@ class BuildVolume(SceneNode): if not self._active_container_stack: return - disallowed_areas = self._active_container_stack.getProperty("machine_disallowed_areas", "value") + disallowed_areas = copy.deepcopy( + self._active_container_stack.getProperty("machine_disallowed_areas", "value")) areas = [] # Add extruder prime locations as disallowed areas. # Probably needs some rework after coordinate system change. - machine_definition = self._active_container_stack.getBottom() - current_machine_id = machine_definition.getId() extruder_manager = ExtruderManager.getInstance() - extruders = extruder_manager.getMachineExtruders(current_machine_id) - machine_width = machine_definition.getProperty("machine_width", "value") - machine_depth = machine_definition.getProperty("machine_depth", "value") + extruders = extruder_manager.getMachineExtruders(self._active_container_stack.getId()) + machine_width = self._active_container_stack.getProperty("machine_width", "value") + machine_depth = self._active_container_stack.getProperty("machine_depth", "value") for single_extruder in extruders: extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value") extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value") From 44de859916c5a7214133e766e637d00b63bdf706 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 19 Jul 2016 13:16:15 +0200 Subject: [PATCH 63/80] JSON fix: made gradual infill step max depend on infill line distance (CURA-836) --- 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 839811fe73..d4933be5bb 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1000,7 +1000,7 @@ "type": "int", "minimum_value": "0", "maximum_value_warning": "4", - "maximum_value": "17", + "maximum_value": "20 - math.log(infill_line_distance) / math.log(2)", "settable_per_mesh": true }, "gradual_infill_step_height": From 7731f9406c1807f9e63f6dab154a09910739525e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 19 Jul 2016 15:59:44 +0200 Subject: [PATCH 64/80] Dialog_profile/material/load_path is now saved and used. CURA-1900 --- cura/CuraApplication.py | 22 +++++++++++++++++---- resources/qml/Cura.qml | 3 ++- resources/qml/Preferences/MaterialsPage.qml | 6 ++++-- resources/qml/Preferences/ProfilesPage.qml | 6 ++++-- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1164c57008..29c1f086b4 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -194,6 +194,14 @@ class CuraApplication(QtApplication): Preferences.getInstance().addPreference("view/center_on_select", True) Preferences.getInstance().addPreference("mesh/scale_to_fit", True) Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) + + for key in [ + "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin + "dialog_profile_path", + "dialog_material_path"]: + + Preferences.getInstance().addPreference("local_file/%s" % key, "~/") + Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode") Preferences.getInstance().setDefault("general/visible_settings", """ @@ -332,10 +340,16 @@ class CuraApplication(QtApplication): f.write(data) - @pyqtSlot(result = QUrl) - def getDefaultPath(self): - return QUrl.fromLocalFile(os.path.expanduser("~/")) - + @pyqtSlot(str, result = QUrl) + def getDefaultPath(self, key): + #return QUrl.fromLocalFile(os.path.expanduser("~/")) + default_path = Preferences.getInstance().getValue("local_file/%s" % key) + return QUrl.fromLocalFile(default_path) + + @pyqtSlot(str, str) + def setDefaultPath(self, key, default_path): + Preferences.getInstance().setValue("local_file/%s" % key, default_path) + ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 8404db01fa..c449b4c83e 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -638,7 +638,7 @@ UM.MainWindow //TODO: Support multiple file selection, workaround bug in KDE file dialog //selectMultiple: true nameFilters: UM.MeshFileHandler.supportedReadFileTypes; - folder: Printer.getDefaultPath() + folder: CuraApplication.getDefaultPath("dialog_load_path") onAccepted: { //Because several implementations of the file dialog only update the folder @@ -646,6 +646,7 @@ UM.MainWindow var f = folder; folder = f; + CuraApplication.setDefaultPath("dialog_load_path", folder); UM.MeshFileHandler.readLocalFile(fileUrl) var meshName = backgroundItem.getMeshName(fileUrl.toString()) backgroundItem.hasMesh(decodeURIComponent(meshName)) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 18059545e2..aaaa4f5e9d 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -200,7 +200,7 @@ UM.ManagementPage title: catalog.i18nc("@title:window", "Import Material"); selectExisting: true; nameFilters: Cura.ContainerManager.getContainerNameFilters("material") - folder: CuraApplication.getDefaultPath() + folder: CuraApplication.getDefaultPath("dialog_material_path") onAccepted: { var result = Cura.ContainerManager.importContainer(fileUrl) @@ -221,6 +221,7 @@ UM.ManagementPage messageDialog.icon = StandardIcon.Critical } messageDialog.open() + CuraApplication.setDefaultPath("dialog_material_path", folder) } } @@ -230,7 +231,7 @@ UM.ManagementPage title: catalog.i18nc("@title:window", "Export Material"); selectExisting: false; nameFilters: Cura.ContainerManager.getContainerNameFilters("material") - folder: CuraApplication.getDefaultPath() + folder: CuraApplication.getDefaultPath("dialog_material_path") onAccepted: { if(base.currentItem.metadata.base_file) @@ -255,6 +256,7 @@ UM.ManagementPage messageDialog.text = catalog.i18nc("@info:status", "Successfully exported material to %1").arg(fileUrl) messageDialog.open() } + CuraApplication.setDefaultPath("dialog_material_path", folder) } } diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 5a56ac8dc3..119a16facc 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -291,7 +291,7 @@ UM.ManagementPage title: catalog.i18nc("@title:window", "Import Profile"); selectExisting: true; nameFilters: base.model.getFileNameFilters("profile_reader") - folder: base.model.getDefaultPath() + folder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { var result = base.model.importProfile(fileUrl) @@ -309,6 +309,7 @@ UM.ManagementPage messageDialog.icon = StandardIcon.Critical } messageDialog.open() + CuraApplication.setDefaultPath("dialog_profile_path", folder) } } @@ -318,7 +319,7 @@ UM.ManagementPage title: catalog.i18nc("@title:window", "Export Profile"); selectExisting: false; nameFilters: base.model.getFileNameFilters("profile_writer") - folder: base.model.getDefaultPath() + folder: CuraApplication.getDefaultPath("dialog_profile_path") onAccepted: { var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter) @@ -329,6 +330,7 @@ UM.ManagementPage messageDialog.open() } // else pop-up Message thing from python code + CuraApplication.setDefaultPath("dialog_profile_path", folder) } } } From da047c6f908ed92f7e1476894bff2f4f14bbf4ed Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 19 Jul 2016 16:56:26 +0200 Subject: [PATCH 65/80] Added benchmark time logs --- plugins/CuraEngineBackend/CuraEngineBackend.py | 7 ++++++- plugins/CuraEngineBackend/ProcessSlicedLayersJob.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index d2f34da9a3..eca6d1fdba 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -22,6 +22,7 @@ from . import StartSliceJob import os import sys +from time import time from PyQt5.QtCore import QTimer @@ -99,6 +100,8 @@ class CuraEngineBackend(Backend): Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted) Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped) + self._slice_start_time = None + ## Called when closing the application. # # This function should terminate the engine process. @@ -127,6 +130,7 @@ class CuraEngineBackend(Backend): ## Perform a slice of the scene. def slice(self): + self._slice_start_time = time() if not self._enabled or not self._global_container_stack: #We shouldn't be slicing. # try again in a short time self._change_timer.start() @@ -214,6 +218,7 @@ class CuraEngineBackend(Backend): # Preparation completed, send it to the backend. self._socket.sendMessage(job.getSliceMessage()) + Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time ) ## Listener for when the scene has changed. # @@ -277,7 +282,7 @@ class CuraEngineBackend(Backend): self.processingProgress.emit(1.0) self._slicing = False - + Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()): self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data) self._process_layers_job.start() diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index d23f71e874..599ed52fc1 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -9,6 +9,7 @@ from UM.Mesh.MeshData import MeshData from UM.Message import Message from UM.i18n import i18nCatalog +from UM.Logger import Logger from UM.Math.Vector import Vector @@ -16,7 +17,7 @@ from cura import LayerDataBuilder from cura import LayerDataDecorator import numpy - +from time import time catalog = i18nCatalog("cura") @@ -38,6 +39,7 @@ class ProcessSlicedLayersJob(Job): self._abort_requested = True def run(self): + start_time = time() if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1) self._progress.show() @@ -147,6 +149,8 @@ class ProcessSlicedLayersJob(Job): # Clear the unparsed layers. This saves us a bunch of memory if the Job does not get destroyed. self._layers = None + Logger.log("d", "Processing layers took %s seconds", time() - start_time) + def _onActiveViewChanged(self): if self.isRunning(): if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": From 6e7c1759d34c18ddb20d2ecd8459b3326d89fb39 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 19 Jul 2016 17:04:42 +0200 Subject: [PATCH 66/80] Remove commented out code CURA-1900 --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 29c1f086b4..32a7391159 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -342,7 +342,6 @@ class CuraApplication(QtApplication): @pyqtSlot(str, result = QUrl) def getDefaultPath(self, key): - #return QUrl.fromLocalFile(os.path.expanduser("~/")) default_path = Preferences.getInstance().getValue("local_file/%s" % key) return QUrl.fromLocalFile(default_path) From 19c60ee5844bcf8e120f82432f89d2625773ed0c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 09:34:03 +0200 Subject: [PATCH 67/80] Group delet checking is more explicit CURA-1891 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 29c1f086b4..689ef2c783 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -583,7 +583,7 @@ class CuraApplication(QtApplication): op.push() if group_node: - if len(group_node.getChildren()) == 1: + if len(group_node.getChildren()) == 1 and group_node.callDecoration("isGroup"): group_node.getChildren()[0].setParent(group_node.getParent()) op = RemoveSceneNodeOperation(group_node) op.push() From aed033674f54e555d992848eb2205664dbf06745 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 09:39:19 +0200 Subject: [PATCH 68/80] Changed some warnings into errors CURA-1706 --- resources/definitions/fdmextruder.def.json | 4 ++-- resources/definitions/fdmprinter.def.json | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 7ce44b77b0..bde24ee684 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -153,7 +153,7 @@ "unit": "mm", "default_value": 0, "minimum_value_warning": "0", - "maximum_value_warning": "machine_height", + "maximum_value": "machine_height", "settable_per_mesh": false, "settable_per_extruder": true } @@ -175,7 +175,7 @@ "unit": "mm", "default_value": 0, "minimum_value_warning": "machine_nozzle_offset_x", - "maximum_value_warning": "machine_width", + "maximum_value": "machine_width", "settable_per_mesh": false, "settable_per_extruder": true, "enabled": false diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d4933be5bb..8f435c1e5c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -342,7 +342,7 @@ "unit": "mm", "default_value": 0, "minimum_value_warning": "0", - "maximum_value_warning": "machine_height", + "maximum_value": "machine_height", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -706,7 +706,7 @@ "default_value": 0.8, "minimum_value": "0", "minimum_value_warning": "0.6", - "maximum_value_warning": "machine_height", + "maximum_value": "machine_height", "type": "float", "settable_per_mesh": true, "children": @@ -718,7 +718,7 @@ "unit": "mm", "default_value": 0.8, "minimum_value": "0", - "maximum_value_warning": "machine_height", + "maximum_value": "machine_height", "type": "float", "value": "top_bottom_thickness", "settable_per_mesh": true, @@ -746,7 +746,7 @@ "minimum_value": "0", "type": "float", "value": "top_bottom_thickness", - "maximum_value_warning": "machine_height", + "maximum_value": "machine_height", "settable_per_mesh": true, "children": { From bb4d4e78077c4ff07251e5e6203d1585e107e0b0 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 11:01:38 +0200 Subject: [PATCH 69/80] Moved viewmode in order so the tooltip is displayed over per-object settings panel CURA-1651 --- resources/qml/Cura.qml | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index c449b4c83e..d0870991d2 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -321,23 +321,7 @@ UM.MainWindow sourceSize.height: height; } - Button - { - id: viewModeButton - anchors - { - top: toolbar.bottom; - topMargin: UM.Theme.getSize("window_margin").height; - left: parent.left; - } - text: catalog.i18nc("@action:button","View Mode"); - iconSource: UM.Theme.getIcon("viewmode"); - - style: UM.Theme.styles.tool_button; - tooltip: ''; - menu: ViewMenu { } - } Toolbar { @@ -367,6 +351,24 @@ UM.MainWindow width: UM.Theme.getSize("sidebar").width; } + Button + { + id: viewModeButton + + anchors + { + top: toolbar.bottom; + topMargin: UM.Theme.getSize("window_margin").height; + left: parent.left; + } + text: catalog.i18nc("@action:button","View Mode"); + iconSource: UM.Theme.getIcon("viewmode"); + + style: UM.Theme.styles.tool_button; + tooltip: ''; + menu: ViewMenu { } + } + Rectangle { id: viewportOverlay From b69388525f2f6efc8670873c1536463ba642b872 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 11:06:26 +0200 Subject: [PATCH 70/80] Fixed uncaught exception on first run --- cura/PlatformPhysics.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 191f7b0e27..23de74b80e 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -48,7 +48,13 @@ class PlatformPhysics: bbox = node.getBoundingBox() # Ignore intersections with the bottom - build_volume_bounding_box = self._build_volume.getBoundingBox().set(bottom=-9001) + build_volume_bounding_box = self._build_volume.getBoundingBox() + if build_volume_bounding_box: + build_volume_bounding_box.set(bottom=-9001) + else: + # No bounding box. This is triggered when running Cura from command line with a model for the first time + # In that situation there is a model, but no machine (and therefore no build volume. + return node._outside_buildarea = False # Mark the node as outside the build volume if the bounding box test fails. From 79f640e344967714839c30c4c028d764f360a34c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 20 Jul 2016 11:12:44 +0200 Subject: [PATCH 71/80] Fixed simple sidebar infill label font. CURA-1824 --- resources/qml/SidebarSimple.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index a393500fb7..04b93e7d2a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -125,6 +125,7 @@ Item } Label{ id: infillLabel + font: UM.Theme.getFont("default") anchors.top: infillIconLining.bottom anchors.horizontalCenter: infillIconLining.horizontalCenter color: infillListView.activeIndex == index ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_border") From 923e4de4ed95236a09e41e9b3effd024861fd37e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 11:13:24 +0200 Subject: [PATCH 72/80] Stack changes now also ensure that validation state change signal is emitted CURA-1890 --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 2b2135e4a3..0c435ba2b9 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -233,7 +233,7 @@ class MachineManager(QObject): self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack) - + self.globalValidationChanged.emit() material = self._global_container_stack.findContainer({"type": "material"}) material.nameChanged.connect(self._onMaterialNameChanged) From 612bb39680bf763931236e09c0d352a2003812c1 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 20 Jul 2016 11:36:32 +0200 Subject: [PATCH 73/80] Compensated build volume bbox and scale_to_max_bounds with raft_thickness. Rework of CURA-1707 --- cura/BuildVolume.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 1709a67dd5..e5bd037f1b 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -191,7 +191,9 @@ class BuildVolume(SceneNode): else: self._disallowed_area_mesh = None - self._volume_aabb = AxisAlignedBox(minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h, max_d)) + self._volume_aabb = AxisAlignedBox( + minimum = Vector(min_w, min_h - 1.0, min_d), + maximum = Vector(max_w, max_h - self._raft_thickness, max_d)) skirt_size = 0.0 @@ -204,7 +206,7 @@ class BuildVolume(SceneNode): # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum = Vector(min_w + skirt_size + 1, min_h, min_d + disallowed_area_size - skirt_size + 1), - maximum = Vector(max_w - skirt_size - 1, max_h, max_d - disallowed_area_size + skirt_size - 1) + maximum = Vector(max_w - skirt_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + skirt_size - 1) ) Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds From 6ec69d523b2bea433f5fc94d7a21669bc9744d25 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 13:05:45 +0200 Subject: [PATCH 74/80] Fixed reloading meshes for 3mf CURA-1622 --- cura/CuraApplication.py | 6 +++++- plugins/3MFReader/ThreeMFReader.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4715ff6009..361facc30c 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -851,7 +851,11 @@ class CuraApplication(QtApplication): def _reloadMeshFinished(self, job): # TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh! - job._node.setMeshData(job.getResult().getMeshData()) + mesh_data = job.getResult().getMeshData() + if mesh_data: + job._node.setMeshData(job.getResult().getMeshData()) + else: + Logger.log("w", "Could not find a mesh in reloaded node.") def _openFile(self, file): job = ReadMeshJob(os.path.abspath(file)) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 2a51e442da..57d76b2783 100644 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -111,6 +111,8 @@ class ThreeMFReader(MeshReader): if len(objects) > 1: group_decorator = GroupDecorator() result.addDecorator(group_decorator) + elif len(objects) == 1: + result = result.getChildren()[0] # Only one object found, return that. except Exception as e: Logger.log("e", "exception occured in 3mf reader: %s", e) From cbbf62106d90ac154384f62d3eb45797cf93c9d3 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 20 Jul 2016 13:25:05 +0200 Subject: [PATCH 75/80] Fix moving objects through bottom. --- cura/PlatformPhysics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 23de74b80e..d2a848dd72 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -50,7 +50,8 @@ class PlatformPhysics: # Ignore intersections with the bottom build_volume_bounding_box = self._build_volume.getBoundingBox() if build_volume_bounding_box: - build_volume_bounding_box.set(bottom=-9001) + # It's over 9000! + build_volume_bounding_box = build_volume_bounding_box.set(bottom=-9001) else: # No bounding box. This is triggered when running Cura from command line with a model for the first time # In that situation there is a model, but no machine (and therefore no build volume. From 77c5d25e70f42c403d6b271d61f34c172d290e35 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 14:11:16 +0200 Subject: [PATCH 76/80] Cutoff point for convex hull is now a bit below 0 to prevent rounding issues. CURA-1608 --- cura/ConvexHullDecorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index f8d1a1e12e..3ccb9481f9 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -157,7 +157,7 @@ class ConvexHullDecorator(SceneNodeDecorator): vertex_data = mesh.getConvexHullTransformedVertices(world_transform) # Don't use data below 0. # TODO; We need a better check for this as this gives poor results for meshes with long edges. - vertex_data = vertex_data[vertex_data[:,1] >= 0] + vertex_data = vertex_data[vertex_data[:,1] >= -0.01] if len(vertex_data) >= 4: # Round the vertex data to 1/10th of a mm, then remove all duplicate vertices From f8a9fa1a660279e7c35fcaea158771830345074a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 14:44:44 +0200 Subject: [PATCH 77/80] Deleting objects from groups no longer cause position changes CURA-1891 --- cura/CuraApplication.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 361facc30c..79bb21cd15 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -583,6 +583,7 @@ class CuraApplication(QtApplication): op.push() if group_node: if len(group_node.getChildren()) == 1 and group_node.callDecoration("isGroup"): + group_node.getChildren()[0].translate(group_node.getPosition()) group_node.getChildren()[0].setParent(group_node.getParent()) op = RemoveSceneNodeOperation(group_node) op.push() From 33313ddb707b6f83a0e14c3589c1c84ecd6d5308 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 20 Jul 2016 15:15:16 +0200 Subject: [PATCH 78/80] Fixed some imports for USB printing --- plugins/USBPrinting/USBPrinterOutputDevice.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index da3dfa2bde..6b5fe22fcf 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -8,14 +8,12 @@ import time import queue import re import functools -import os.path from UM.Application import Application from UM.Logger import Logger -from UM.PluginRegistry import PluginRegistry from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState +from UM.Message import Message -from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal from UM.i18n import i18nCatalog @@ -137,7 +135,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): # \param gcode_list List with gcode (strings). def printGCode(self, gcode_list): if self._progress or self._connection_state != ConnectionState.connected: - self._error_message = Message(i18n_catalog.i18nc("@info:status", "Printer is busy or not connected. Unable to start a new job.")) + self._error_message = Message(catalog.i18nc("@info:status", "Printer is busy or not connected. Unable to start a new job.")) self._error_message.show() Logger.log("d", "Printer is busy or not connected, aborting print") self.writeError.emit(self) From 8eef34ac4587630cfecbe6efee5f5f8123150c86 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 21 Jul 2016 10:30:22 +0200 Subject: [PATCH 79/80] USB printer connection is now reset when print is completed CURA-1822 --- plugins/USBPrinting/USBPrinterOutputDevice.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 6b5fe22fcf..7bd5b66cc2 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -502,6 +502,13 @@ class USBPrinterOutputDevice(PrinterOutputDevice): # It will be normalized (based on max_progress) to range 0 - 100 def setProgress(self, progress, max_progress = 100): self._progress = (progress / max_progress) * 100 # Convert to scale of 0-100 + if self._progress == 100: + # Printing is done, reset progress + self._gcode_position = 0 + self.setProgress(0) + self._is_printing = False + self._is_paused = False + self._updateJobState("ready") self.progressChanged.emit() ## Cancel the current print. Printer connection wil continue to listen. From 6602177102ab3a0b10c3155b4f584b767dded342 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 21 Jul 2016 13:20:37 +0200 Subject: [PATCH 80/80] Removed unneeded getMeshData call CURA-1622 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 79bb21cd15..82cc769172 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -854,7 +854,7 @@ class CuraApplication(QtApplication): # TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh! mesh_data = job.getResult().getMeshData() if mesh_data: - job._node.setMeshData(job.getResult().getMeshData()) + job._node.setMeshData(mesh_data) else: Logger.log("w", "Could not find a mesh in reloaded node.")