From 67636d6f3c8d0f6f10d986b0591d9ed71a3d53bd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 12:01:05 +0200 Subject: [PATCH 01/23] _updateMaterial container now correctly returns generic material CURA-2236 --- cura/Settings/MachineManager.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index ccd14fcb1d..a2f4e4abdc 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -547,6 +547,7 @@ class MachineManager(QObject): preferred_material = None if old_material: preferred_material_name = old_material.getName() + self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0], preferred_material_name).id) else: Logger.log("w", "While trying to set the active variant, no variant was found to replace.") @@ -806,11 +807,11 @@ class MachineManager(QObject): if containers: return containers[0] - if "name" in search_criteria or "id" in search_criteria: + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) + if "variant" in search_criteria or "id" in search_criteria: # If a material by this name can not be found, try a wider set of search criteria - search_criteria.pop("name", None) + search_criteria.pop("variant", None) search_criteria.pop("id", None) - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) if containers: return containers[0] @@ -858,7 +859,7 @@ class MachineManager(QObject): # We still weren't able to find a quality for this specific material. # Try to find qualities for a generic version of the material. - material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic" } + material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"} if definition.getMetaDataEntry("has_machine_quality"): if material_container: material_search_criteria["definition"] = material_container.getDefinition().id From 51d653beba4e9876922d5f608c58b606aacf6842 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 12:40:38 +0200 Subject: [PATCH 02/23] Added logging if material container was not found CURA-2236 --- 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 a2f4e4abdc..f957df2c9b 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -815,7 +815,7 @@ class MachineManager(QObject): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) if containers: return containers[0] - + Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.") return self._empty_material_container def _updateQualityContainer(self, definition, variant_container, material_container = None, preferred_quality_name = None): From 3227507297fec4e782efb69436d7d325edd1a917 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 13:31:36 +0200 Subject: [PATCH 03/23] An empty quality container will now give a "not supported" warning CURA-2236 --- cura/CuraApplication.py | 1 + cura/Settings/MachineManager.py | 7 ++++--- resources/qml/SidebarHeader.qml | 2 +- resources/themes/cura/styles.qml | 17 ++++++++++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index aa843bccdb..e6dda417ff 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -180,6 +180,7 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().addContainer(empty_material_container) empty_quality_container = copy.deepcopy(empty_container) empty_quality_container._id = "empty_quality" + empty_quality_container.setName("Not supported") empty_quality_container.addMetaDataEntry("type", "quality") ContainerRegistry.getInstance().addContainer(empty_quality_container) empty_quality_changes_container = copy.deepcopy(empty_container) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f957df2c9b..bf82a95f1a 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -7,7 +7,7 @@ from PyQt5.QtWidgets import QMessageBox from UM.Application import Application from UM.Preferences import Preferences from UM.Logger import Logger - +from UM.Message import Message from UM.Settings.SettingRelation import RelationType import UM.Settings @@ -856,7 +856,6 @@ class MachineManager(QObject): containers = container_registry.findInstanceContainers(**search_criteria) if containers: return containers[0] - # We still weren't able to find a quality for this specific material. # Try to find qualities for a generic version of the material. material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"} @@ -873,7 +872,6 @@ class MachineManager(QObject): material_search_criteria["variant"] = variant_container.id else: material_search_criteria["definition"] = "fdmprinter" - material_containers = container_registry.findInstanceContainers(**material_search_criteria) if material_containers: search_criteria["material"] = material_containers[0].getId() @@ -891,6 +889,9 @@ class MachineManager(QObject): if containers: return containers[0] + # Notify user that we were unable to find a matching quality + message = Message(catalog.i18nc("@info:status", "Unable to find a quality profile for this combination, using an empty one instead.")) + message.show() return self._empty_quality_container ## Finds a quality-changes container to use if any other container diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 3350ebeb7b..c9c0e722eb 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -277,7 +277,7 @@ Column height: UM.Theme.getSize("setting_control").height tooltip: Cura.MachineManager.activeQualityName style: UM.Theme.styles.sidebar_header_button - + property var valueWarning: Cura.MachineManager.activeQualityId == "empty_quality" menu: ProfileMenu { } UM.SimpleButton diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml index 8d813bc2b5..3cfb4514ee 100644 --- a/resources/themes/cura/styles.qml +++ b/resources/themes/cura/styles.qml @@ -11,7 +11,22 @@ QtObject { property Component sidebar_header_button: Component { ButtonStyle { background: Rectangle { - color: control.enabled ? Theme.getColor("setting_control") : Theme.getColor("setting_control_disabled") + color: + { + if(control.enabled) + { + if(control.valueWarning) + { + return Theme.getColor("setting_validation_warning"); + } else + { + return Theme.getColor("setting_control"); + } + } else { + return Theme.getColor("setting_control_disabled"); + } + } + border.width: Theme.getSize("default_lining").width border.color: !control.enabled ? Theme.getColor("setting_control_disabled_border") : control.hovered ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border") From 1b1be138188e3ffe886eedbcca15c72c304420f1 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 13:47:19 +0200 Subject: [PATCH 04/23] Added normal quality_type to empty container so switching quality_changes works again CURA-2236 --- cura/CuraApplication.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e6dda417ff..2091eff5ed 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -181,6 +181,7 @@ class CuraApplication(QtApplication): empty_quality_container = copy.deepcopy(empty_container) empty_quality_container._id = "empty_quality" empty_quality_container.setName("Not supported") + empty_quality_container.addMetaDataEntry("quality_type", "normal") empty_quality_container.addMetaDataEntry("type", "quality") ContainerRegistry.getInstance().addContainer(empty_quality_container) empty_quality_changes_container = copy.deepcopy(empty_container) From c268fcd8c6f510c72b5292692c7db70642601061 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Mon, 5 Sep 2016 14:38:24 +0200 Subject: [PATCH 05/23] fix: wire printing height depends on nozzle head dist (CURA-1555) --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ce406dc923..8b2805b3aa 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3759,6 +3759,7 @@ "type": "float", "unit": "mm", "default_value": 3, + "value": "machine_nozzle_head_distance", "minimum_value": "0.0001", "maximum_value_warning": "20", "enabled": "wireframe_enabled", From df519ed00a838e89ca22be4e0adc22d866d17f8e Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sat, 3 Sep 2016 13:16:15 +0200 Subject: [PATCH 06/23] CURA-2157: Adding an confirmation dialog Tested while starting two prints and aborting them. The buttons for "Yes" and "No" are translated by Qt5. --- resources/qml/MonitorButton.qml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/resources/qml/MonitorButton.qml b/resources/qml/MonitorButton.qml index 79168ed6df..2a8e2f4097 100644 --- a/resources/qml/MonitorButton.qml +++ b/resources/qml/MonitorButton.qml @@ -4,6 +4,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 import UM 1.1 as UM @@ -160,7 +161,7 @@ Rectangle anchors.rightMargin: UM.Theme.getSize("default_margin").width text: catalog.i18nc("@label:", "Abort Print") - onClicked: Cura.MachineManager.printerOutputDevices[0].setJobState("abort") + onClicked: confirmationDialog.visible = true style: ButtonStyle { @@ -216,6 +217,18 @@ Rectangle } } + MessageDialog + { + id: confirmationDialog + + title: catalog.i18nc("@text:MessageDialog", "Abort print") + icon: StandardIcon.Warning + text: catalog.i18nc("@text:MessageDialog", "Do you really want to abort the print?") + standardButtons: StandardButton.Yes | StandardButton.No + Component.onCompleted: visible = false + onYes: Cura.MachineManager.printerOutputDevices[0].setJobState("abort") + } + Button { id: pauseResumeButton From 938a2fc691f80f2684df0f81eadd49ab6f88e008 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 15:38:56 +0200 Subject: [PATCH 07/23] Update wording CURA-2157 --- resources/qml/MonitorButton.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/MonitorButton.qml b/resources/qml/MonitorButton.qml index 2a8e2f4097..b1dc76872d 100644 --- a/resources/qml/MonitorButton.qml +++ b/resources/qml/MonitorButton.qml @@ -221,9 +221,9 @@ Rectangle { id: confirmationDialog - title: catalog.i18nc("@text:MessageDialog", "Abort print") + title: catalog.i18nc("@window:title", "Abort print") icon: StandardIcon.Warning - text: catalog.i18nc("@text:MessageDialog", "Do you really want to abort the print?") + text: catalog.i18nc("@label", "Are you sure you want to abort the print?") standardButtons: StandardButton.Yes | StandardButton.No Component.onCompleted: visible = false onYes: Cura.MachineManager.printerOutputDevices[0].setJobState("abort") From 66f773434fb18ed74281602cab2a9ecc4378f283 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 15:42:09 +0200 Subject: [PATCH 08/23] UpgradeFirmwareAction now supports custom firmware uploading CURA-955 --- .../USBPrinterOutputDeviceManager.py | 30 +++++++------- .../UpgradeFirmwareMachineAction.qml | 40 ++++++++++++------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index 801ce4743f..7d1b3fea3b 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -103,10 +103,11 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): self._firmware_view.show() - @pyqtSlot() - def updateAllFirmware(self): + @pyqtSlot(str) + def updateAllFirmware(self, file_name): + file_name = file_name.replace("file://", "") # File dialogs prepend the path with file://, which we don't need / want if not self._usb_output_devices: - Message(i18n_catalog.i18nc("@info","Cannot update firmware, there were no connected printers found.")).show() + Message(i18n_catalog.i18nc("@info", "Cannot update firmware, there were no connected printers found.")).show() return for printer_connection in self._usb_output_devices: @@ -114,26 +115,26 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): self.spawnFirmwareInterface("") for printer_connection in self._usb_output_devices: try: - self._usb_output_devices[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName())) + self._usb_output_devices[printer_connection].updateFirmware(file_name) except FileNotFoundError: # Should only happen in dev environments where the resources/firmware folder is absent. self._usb_output_devices[printer_connection].setProgress(100, 100) - Logger.log("w", "No firmware found for printer %s called '%s'" %(printer_connection, self._getDefaultFirmwareName())) + Logger.log("w", "No firmware found for printer %s called '%s'" % (printer_connection, self.getDefaultFirmwareName())) Message(i18n_catalog.i18nc("@info", "Could not find firmware required for the printer at %s.") % printer_connection).show() self._firmware_view.close() continue - @pyqtSlot(str, result = bool) - def updateFirmwareBySerial(self, serial_port): + @pyqtSlot(str, str, result = bool) + def updateFirmwareBySerial(self, serial_port, file_name): if serial_port in self._usb_output_devices: self.spawnFirmwareInterface(self._usb_output_devices[serial_port].getSerialPort()) try: - self._usb_output_devices[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName())) + self._usb_output_devices[serial_port].updateFirmware(file_name) except FileNotFoundError: self._firmware_view.close() - Logger.log("e", "Could not find firmware required for this machine called '%s'" %(self._getDefaultFirmwareName())) + Logger.log("e", "Could not find firmware required for this machine called '%s'" % (self.getDefaultFirmwareName())) return False return True return False @@ -147,7 +148,8 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): return USBPrinterOutputDeviceManager._instance - def _getDefaultFirmwareName(self): + @pyqtSlot(result = str) + def getDefaultFirmwareName(self): # Check if there is a valid global container stack global_container_stack = Application.getInstance().getGlobalContainerStack() if not global_container_stack: @@ -193,13 +195,13 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): Logger.log("d", "Choosing basic firmware for machine %s.", machine_id) hex_file = machine_without_extras[machine_id] # Return "basic" firmware else: - Logger.log("e", "There is no firmware for machine %s.", machine_id) + Logger.log("w", "There is no firmware for machine %s.", machine_id) if hex_file: - return hex_file.format(baudrate=baudrate) + return Resources.getPath(CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) else: - Logger.log("e", "Could not find any firmware for machine %s.", machine_id) - raise FileNotFoundError() + Logger.log("w", "Could not find any firmware for machine %s.", machine_id) + return "" ## Helper to identify serial ports (and scan for them) def _addRemovePorts(self, serial_ports): diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 0c9b80c010..ce2e2a39cb 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -5,6 +5,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.2 // For filedialog import UM 1.2 as UM import Cura 1.0 as Cura @@ -44,34 +45,45 @@ Cura.MachineAction anchors.topMargin: UM.Theme.getSize("default_margin").height width: parent.width wrapMode: Text.WordWrap - text: catalog.i18nc("@label", "The firmware shipping with new Ultimakers works, but upgrades have been made to make better prints, and make calibration easier."); + text: catalog.i18nc("@label", "The firmware shipping with new Printers works, but new versions tend to have more features and improvements."); } - Label - { - id: upgradeText2 - anchors.top: upgradeText1.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - width: parent.width - wrapMode: Text.WordWrap - text: catalog.i18nc("@label", "Cura requires these new features and thus your firmware will most likely need to be upgraded. You can do so now."); - } Row { - anchors.top: upgradeText2.bottom + anchors.top: upgradeText1.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width spacing: UM.Theme.getSize("default_margin").width + property var firmwareName: Cura.USBPrinterManager.getDefaultFirmwareName() Button { - id: upgradeButton - text: catalog.i18nc("@action:button","Upgrade to Marlin Firmware"); + id: autoUpgradeButton + text: catalog.i18nc("@action:button", "Automatically upgrade Firmware"); + enabled: parent.firmwareName != "" onClicked: { - Cura.USBPrinterManager.updateAllFirmware() + Cura.USBPrinterManager.updateAllFirmware(parent.firmwareName) + } + } + Button + { + id: manualUpgradeButton + text: catalog.i18nc("@action:button", "Upload custom Firmware"); + onClicked: + { + customFirmwareDialog.open() } } } + + FileDialog + { + id: customFirmwareDialog + title: catalog.i18nc("@title:window", "Select custom firmware") + nameFilters: "Firmware image files (*.hex)" + selectExisting: true + onAccepted: Cura.USBPrinterManager.updateAllFirmware(fileUrl) + } } } \ No newline at end of file From de8785da3741023d934a818a99637c1f07c6742a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 15:48:31 +0200 Subject: [PATCH 09/23] All machines that suport USB connection now get the upgrade firmware action for free! CURA-955 --- .../UpgradeFirmwareMachineAction.py | 10 +++++++++- resources/definitions/fdmprinter.def.json | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py index 53476207fd..71d3f0b55b 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py @@ -1,9 +1,17 @@ from cura.MachineAction import MachineAction from UM.i18n import i18nCatalog +import cura.Settings.CuraContainerRegistry +import UM.Settings.DefinitionContainer catalog = i18nCatalog("cura") class UpgradeFirmwareMachineAction(MachineAction): def __init__(self): super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware")) - self._qml_url = "UpgradeFirmwareMachineAction.qml" \ No newline at end of file + self._qml_url = "UpgradeFirmwareMachineAction.qml" + cura.Settings.CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) + + def _onContainerAdded(self, container): + # Add this action as a supported action to all machine definitions + if isinstance(container, UM.Settings.DefinitionContainer) and container.getMetaDataEntry("type") == "machine" and container.getMetaDataEntry("supports_usb_connection"): + UM.Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index a219347f10..58bb170c21 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -15,7 +15,8 @@ "machine_extruder_trains": { "0": "fdmextruder" - } + }, + "supports_usb_connection": true }, "settings": { From 9a28b0d4339b58f36f746a8323944f566d0d28e6 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 16:20:12 +0200 Subject: [PATCH 10/23] Previously active tool is now set correctly once something is selected again CURA-1481 --- cura/CuraApplication.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 2091eff5ed..892440cba0 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -511,8 +511,6 @@ class CuraApplication(QtApplication): if self.getController().getActiveTool(): self._previous_active_tool = self.getController().getActiveTool().getPluginId() self.getController().setActiveTool(None) - else: - self._previous_active_tool = None def _onToolOperationStopped(self, event): if self._center_after_select: From bd8db49a952558fe895d25f52c5914545716b82a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 16:29:15 +0200 Subject: [PATCH 11/23] Add layer data type and color for Support Interface CURA-2049 --- cura/LayerPolygon.py | 9 ++++++--- plugins/CuraEngineBackend/Cura.proto | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index c62113916d..67b665eb4c 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -14,6 +14,7 @@ class LayerPolygon: SupportInfillType = 7 MoveCombingType = 8 MoveRetractionType = 9 + SupportInterfaceType = 10 __jump_map = numpy.logical_or( numpy.arange(10) == NoneType, numpy.arange(10) >= MoveCombingType ) @@ -178,10 +179,11 @@ class LayerPolygon: SkinType: Color(1.0, 1.0, 0.0, 1.0), SupportType: Color(0.0, 1.0, 1.0, 1.0), SkirtType: Color(0.0, 1.0, 1.0, 1.0), - InfillType: Color(1.0, 0.74, 0.0, 1.0), + InfillType: Color(1.0, 0.75, 0.0, 1.0), SupportInfillType: Color(0.0, 1.0, 1.0, 1.0), MoveCombingType: Color(0.0, 0.0, 1.0, 1.0), MoveRetractionType: Color(0.5, 0.5, 1.0, 1.0), + SupportInterfaceType: Color(0.25, 0.75, 1.0, 1.0), } # Should be generated in better way, not hardcoded. @@ -192,8 +194,9 @@ class LayerPolygon: [1.0, 1.0, 0.0, 1.0], [0.0, 1.0, 1.0, 1.0], [0.0, 1.0, 1.0, 1.0], - [1.0, 0.74, 0.0, 1.0], + [1.0, 0.75, 0.0, 1.0], [0.0, 1.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0], - [0.5, 0.5, 1.0, 1.0] + [0.5, 0.5, 1.0, 1.0], + [0.25, 0.75, 1.0, 1.0] ]) \ No newline at end of file diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 289c0a98a0..e26b3040f0 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -56,6 +56,7 @@ message Polygon { SupportInfillType = 7; MoveCombingType = 8; MoveRetractionType = 9; + SupportInterfaceType = 10; } Type type = 1; // Type of move bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used) From b7605aecc2372ab712c538d5c97774258105f7cb Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 16:51:13 +0200 Subject: [PATCH 12/23] Update wording The options listed under "Experimental" aren't all modes. --- 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 4d99a4eb56..dc5a07ac46 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3519,7 +3519,7 @@ }, "experimental": { - "label": "Experimental Modes", + "label": "Experimental", "type": "category", "icon": "category_experimental", "description": "experimental!", From 4817dbe62ffef1b4ee9cc3e950e63be04e27be94 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 17:00:37 +0200 Subject: [PATCH 13/23] Platform physics now checks if the found result actually is a solution If not, it keeps checking a bit more to see if it can find another solution CURA-2156 --- cura/PlatformPhysics.py | 55 ++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index c9afb4ccbd..e25541e91c 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -29,6 +29,8 @@ class PlatformPhysics: self._change_timer.setInterval(100) self._change_timer.setSingleShot(True) self._change_timer.timeout.connect(self._onChangeTimerFinished) + self._move_factor = 1.1 # By how much should we multiply overlap to calculate a new spot? + self._max_overlap_checks = 10 # How many times should we try to find a new spot per tick? Preferences.getInstance().addPreference("physics/automatic_push_free", True) Preferences.getInstance().addPreference("physics/automatic_drop_down", True) @@ -97,29 +99,42 @@ class PlatformPhysics: continue if other_node in transformed_nodes: - continue # Other node is already moving, wait for next pass. + continue # Other node is already moving, wait for next pass. - # Get the overlap distance for both convex hulls. If this returns None, there is no intersection. - head_hull = node.callDecoration("getConvexHullHead") - if head_hull: - overlap = head_hull.intersectsPolygon(other_node.callDecoration("getConvexHull")) - if not overlap: - other_head_hull = other_node.callDecoration("getConvexHullHead") - if other_head_hull: - overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_head_hull) - else: - own_convex_hull = node.callDecoration("getConvexHull") - other_convex_hull = other_node.callDecoration("getConvexHull") - if own_convex_hull and other_convex_hull: - overlap = own_convex_hull.intersectsPolygon(other_convex_hull) + overlap = (0, 0) # Start loop with no overlap + move_vector = move_vector.set(x=overlap[0] * self._move_factor, z=overlap[1] * self._move_factor) + current_overlap_checks = 0 + # Continue to check the overlap until we no longer find one. + while overlap and current_overlap_checks <= self._max_overlap_checks: + current_overlap_checks += 1 + head_hull = node.callDecoration("getConvexHullHead") + if head_hull: # One at a time intersection. + overlap = head_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_node.callDecoration("getConvexHull")) + if not overlap: + other_head_hull = other_node.callDecoration("getConvexHullHead") + if other_head_hull: + overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull) + if overlap: + # Moving ensured that overlap was still there. Try anew! + move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, + z=move_vector.z + overlap[1] * self._move_factor) + else: + # Moving ensured that overlap was still there. Try anew! + move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, + z=move_vector.z + overlap[1] * self._move_factor) else: - # This can happen in some cases if the object is not yet done with being loaded. - # Simply waiting for the next tick seems to resolve this correctly. - overlap = None + own_convex_hull = node.callDecoration("getConvexHull") + other_convex_hull = other_node.callDecoration("getConvexHull") + if own_convex_hull and other_convex_hull: + overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull) + if overlap: # Moving ensured that overlap was still there. Try anew! + move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, + z=move_vector.z + overlap[1] * self._move_factor) + else: + # This can happen in some cases if the object is not yet done with being loaded. + # Simply waiting for the next tick seems to resolve this correctly. + overlap = None - if overlap is None: - continue - move_vector = move_vector.set(x=overlap[0] * 1.1, z=overlap[1] * 1.1) convex_hull = node.callDecoration("getConvexHull") if convex_hull: if not convex_hull.isValid(): From bb7f6f87c7f02a02d3093fe0b30dd1d982b62737 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 5 Sep 2016 17:41:52 +0200 Subject: [PATCH 14/23] Platfom physics now actually checks max_overlap_checks instead of max_overlap_checks +1 CURA-2156 --- cura/PlatformPhysics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index e25541e91c..d718f25b87 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -105,7 +105,7 @@ class PlatformPhysics: move_vector = move_vector.set(x=overlap[0] * self._move_factor, z=overlap[1] * self._move_factor) current_overlap_checks = 0 # Continue to check the overlap until we no longer find one. - while overlap and current_overlap_checks <= self._max_overlap_checks: + while overlap and current_overlap_checks < self._max_overlap_checks: current_overlap_checks += 1 head_hull = node.callDecoration("getConvexHullHead") if head_hull: # One at a time intersection. From 60568a30706ece60b945aa9635dafd5d191424af Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 18:10:35 +0200 Subject: [PATCH 15/23] Fix size of LayerPolygon.__jump_map CURA-2049 --- cura/LayerPolygon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 67b665eb4c..db9582c960 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -16,7 +16,7 @@ class LayerPolygon: MoveRetractionType = 9 SupportInterfaceType = 10 - __jump_map = numpy.logical_or( numpy.arange(10) == NoneType, numpy.arange(10) >= MoveCombingType ) + __jump_map = numpy.logical_or( numpy.arange(11) == NoneType, numpy.arange(11) >= MoveCombingType ) def __init__(self, mesh, extruder, line_types, data, line_widths): self._mesh = mesh From 287cbcbb161c388f75155345fc86d460ea41dcca Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 18:15:02 +0200 Subject: [PATCH 16/23] Properly fix LayerPolygon.__jump_map CURA-2049 --- cura/LayerPolygon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index db9582c960..c5eb4b699e 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -16,7 +16,7 @@ class LayerPolygon: MoveRetractionType = 9 SupportInterfaceType = 10 - __jump_map = numpy.logical_or( numpy.arange(11) == NoneType, numpy.arange(11) >= MoveCombingType ) + __jump_map = numpy.logical_or( numpy.arange(11) == NoneType, numpy.arange(11) >= MoveRetractionType ) def __init__(self, mesh, extruder, line_types, data, line_widths): self._mesh = mesh From b735d46e9016581ff3452321805d9ca4f81e01a8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Sep 2016 20:35:20 +0200 Subject: [PATCH 17/23] Show sidebar tooltips above messagestack --- resources/qml/Cura.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 34dbcf1b67..42c2ad9cf4 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -346,6 +346,7 @@ UM.MainWindow bottom: parent.bottom; right: parent.right; } + z: 1 onMonitoringPrintChanged: base.monitoringPrint = monitoringPrint width: UM.Theme.getSize("sidebar").width; } From 46acc4d351fb2ed25d60b51149fa2460ae587006 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 6 Sep 2016 08:32:51 +0200 Subject: [PATCH 18/23] Update wording CURA-2236 --- 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 bf82a95f1a..3e6b55ec7e 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -890,7 +890,7 @@ class MachineManager(QObject): return containers[0] # Notify user that we were unable to find a matching quality - message = Message(catalog.i18nc("@info:status", "Unable to find a quality profile for this combination, using an empty one instead.")) + message = Message(catalog.i18nc("@info:status", "Unable to find a quality profile for this combination. Default settings will be used instead.")) message.show() return self._empty_quality_container From 2380614bd87f043d69bea7162baacbd103c846ea Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 6 Sep 2016 08:43:00 +0200 Subject: [PATCH 19/23] Update wording of error messages Clearly list problem first, followed by possible resolvement. --- plugins/CuraEngineBackend/CuraEngineBackend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 9e6bec45e4..72884ce5a5 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -229,7 +229,7 @@ class CuraEngineBackend(Backend): if job.getResult() == StartSliceJob.StartJobResult.SettingError: if Application.getInstance().getPlatformActivity: - self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors.")) + self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. Please check your settings for errors.")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: @@ -238,7 +238,7 @@ class CuraEngineBackend(Backend): if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice: if Application.getInstance().getPlatformActivity: - self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable models found.")) + self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit.")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: From 71e6733c8e36670ededc3fc887b761056f322559 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 6 Sep 2016 09:08:46 +0200 Subject: [PATCH 20/23] Firmware update logging now uses correct path CURA-955 --- plugins/USBPrinting/USBPrinterOutputDeviceManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index 7d1b3fea3b..b2cab36fa3 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -119,7 +119,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): except FileNotFoundError: # Should only happen in dev environments where the resources/firmware folder is absent. self._usb_output_devices[printer_connection].setProgress(100, 100) - Logger.log("w", "No firmware found for printer %s called '%s'" % (printer_connection, self.getDefaultFirmwareName())) + Logger.log("w", "No firmware found for printer %s called '%s'" % (printer_connection, file_name) Message(i18n_catalog.i18nc("@info", "Could not find firmware required for the printer at %s.") % printer_connection).show() self._firmware_view.close() @@ -134,7 +134,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): self._usb_output_devices[serial_port].updateFirmware(file_name) except FileNotFoundError: self._firmware_view.close() - Logger.log("e", "Could not find firmware required for this machine called '%s'" % (self.getDefaultFirmwareName())) + Logger.log("e", "Could not find firmware required for this machine called '%s'", file_name) return False return True return False From 6db03538a17de768165397f39646fe6afbc8a1c8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 6 Sep 2016 09:23:20 +0200 Subject: [PATCH 21/23] Removed capital letter CURA-955 --- plugins/USBPrinting/USBPrinterOutputDeviceManager.py | 2 +- .../UltimakerMachineActions/UpgradeFirmwareMachineAction.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index b2cab36fa3..248649f431 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -119,7 +119,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension): except FileNotFoundError: # Should only happen in dev environments where the resources/firmware folder is absent. self._usb_output_devices[printer_connection].setProgress(100, 100) - Logger.log("w", "No firmware found for printer %s called '%s'" % (printer_connection, file_name) + Logger.log("w", "No firmware found for printer %s called '%s'", printer_connection, file_name) Message(i18n_catalog.i18nc("@info", "Could not find firmware required for the printer at %s.") % printer_connection).show() self._firmware_view.close() diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index ce2e2a39cb..153d8254ef 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -45,7 +45,7 @@ Cura.MachineAction anchors.topMargin: UM.Theme.getSize("default_margin").height width: parent.width wrapMode: Text.WordWrap - text: catalog.i18nc("@label", "The firmware shipping with new Printers works, but new versions tend to have more features and improvements."); + text: catalog.i18nc("@label", "The firmware shipping with new printers works, but new versions tend to have more features and improvements."); } Row From 6909f88ce6d3ea335fc2bd2f159fe64c2105aa21 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 6 Sep 2016 10:28:19 +0200 Subject: [PATCH 22/23] Increase default limit on feed rate There is no real limit by default now. Only light speed (and the limit on the input element's length). The feed rate limit should be set by a machine definition. If there is no limit set, let there be no limit to what the user can input. Contributes to issue CURA-2284. --- resources/definitions/fdmprinter.def.json | 2 +- resources/definitions/ultimaker.def.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index dc5a07ac46..bdcc864d82 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -403,7 +403,7 @@ "description": "The maximum speed of the filament.", "unit": "mm/s", "type": "float", - "default_value": 25, + "default_value": 299792458000, "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false diff --git a/resources/definitions/ultimaker.def.json b/resources/definitions/ultimaker.def.json index dc52b00dcc..0a3729c766 100644 --- a/resources/definitions/ultimaker.def.json +++ b/resources/definitions/ultimaker.def.json @@ -9,6 +9,9 @@ "visible": false }, "overrides": { + "machine_max_feedrate_e": { + "default_value": 45 + }, "material_print_temperature": { "minimum_value": "0" }, From 635f26da8e053014356118f40d6fcab68d40683a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 6 Sep 2016 10:30:09 +0200 Subject: [PATCH 23/23] Lower warning values for retraction speeds As discussed with David, the warning should really be quite a bit lower. No printers actually reach 100. Contributes to issue CURA-2284. --- resources/definitions/fdmprinter.def.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index bdcc864d82..e76d277b0c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1161,7 +1161,7 @@ "default_value": 25, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", - "maximum_value_warning": "100", + "maximum_value_warning": "25", "enabled": "retraction_enable", "settable_per_mesh": false, "settable_per_extruder": true, @@ -1174,7 +1174,7 @@ "default_value": 25, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", - "maximum_value_warning": "100", + "maximum_value_warning": "25", "enabled": "retraction_enable", "value": "retraction_speed", "settable_per_mesh": false, @@ -1188,7 +1188,7 @@ "default_value": 25, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", - "maximum_value_warning": "100", + "maximum_value_warning": "25", "enabled": "retraction_enable", "value": "retraction_speed", "settable_per_mesh": false,