From e3dd7a449d396cadd97835cb531fe74dc0264b13 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 16:09:59 +0100 Subject: [PATCH 1/2] CURA-5090 speedups by using qtimers on updating mostly visual elements --- cura/BuildVolume.py | 2 +- cura/CuraApplication.py | 15 +++++++++++--- cura/Machines/Models/MultiBuildPlateModel.py | 12 +++++++++-- cura/ObjectsModel.py | 17 ++++++++++++++-- cura/Scene/ConvexHullDecorator.py | 21 +++++++++++++++++++- plugins/SimulationView/SimulationView.py | 7 ++++--- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 0b81a5183f..d93ce1107d 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -136,6 +136,7 @@ class BuildVolume(SceneNode): if active_extruder_changed is not None: node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild) node.decoratorsChanged.disconnect(self._updateNodeListeners) + self._updateDisallowedAreasAndRebuild() # make sure we didn't miss anything before we updated the node listeners self._scene_objects = new_scene_objects self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered. @@ -150,7 +151,6 @@ class BuildVolume(SceneNode): active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal") if active_extruder_changed is not None: active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild) - self._updateDisallowedAreasAndRebuild() def setWidth(self, width): if width is not None: diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 84ec787cd7..99cc30a12b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -4,7 +4,7 @@ #Type hinting. from typing import Dict -from PyQt5.QtCore import QObject +from PyQt5.QtCore import QObject, QTimer from PyQt5.QtNetwork import QLocalServer from PyQt5.QtNetwork import QLocalSocket @@ -283,10 +283,15 @@ class CuraApplication(QtApplication): self._preferred_mimetype = "" self._i18n_catalog = i18nCatalog("cura") - self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) + self._update_platform_activity_timer = QTimer() + self._update_platform_activity_timer.setInterval(500) + self._update_platform_activity_timer.setSingleShot(True) + self._update_platform_activity_timer.timeout.connect(self.updatePlatformActivity) + + self.getController().getScene().sceneChanged.connect(self.updatePlatformActivityDelayed) self.getController().toolOperationStopped.connect(self._onToolOperationStopped) self.getController().contextMenuRequested.connect(self._onContextMenuRequested) - self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivity) + self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivityDelayed) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") @@ -1061,6 +1066,10 @@ class CuraApplication(QtApplication): def getSceneBoundingBoxString(self): return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()} + def updatePlatformActivityDelayed(self, node = None): + if node is not None and node.getMeshData() is not None: + self._update_platform_activity_timer.start() + ## Update scene bounding box for current build plate def updatePlatformActivity(self, node = None): count = 0 diff --git a/cura/Machines/Models/MultiBuildPlateModel.py b/cura/Machines/Models/MultiBuildPlateModel.py index f0f4997014..958e93837a 100644 --- a/cura/Machines/Models/MultiBuildPlateModel.py +++ b/cura/Machines/Models/MultiBuildPlateModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty +from PyQt5.QtCore import QTimer, pyqtSignal, pyqtProperty from UM.Application import Application from UM.Scene.Selection import Selection @@ -21,8 +21,13 @@ class MultiBuildPlateModel(ListModel): def __init__(self, parent = None): super().__init__(parent) + self._update_timer = QTimer() + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._updateSelectedObjectBuildPlateNumbers) + self._application = Application.getInstance() - self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbers) + self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbersDelayed) Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers) self._max_build_plate = 1 # default @@ -45,6 +50,9 @@ class MultiBuildPlateModel(ListModel): def activeBuildPlate(self): return self._active_build_plate + def _updateSelectedObjectBuildPlateNumbersDelayed(self, *args): + self._update_timer.start() + def _updateSelectedObjectBuildPlateNumbers(self, *args): result = set() for node in Selection.getAllSelectedObjects(): diff --git a/cura/ObjectsModel.py b/cura/ObjectsModel.py index f02e8b4db5..cfe4320e28 100644 --- a/cura/ObjectsModel.py +++ b/cura/ObjectsModel.py @@ -1,3 +1,8 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import QTimer + from UM.Application import Application from UM.Qt.ListModel import ListModel from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -14,8 +19,13 @@ class ObjectsModel(ListModel): def __init__(self): super().__init__() - Application.getInstance().getController().getScene().sceneChanged.connect(self._update) - Preferences.getInstance().preferenceChanged.connect(self._update) + Application.getInstance().getController().getScene().sceneChanged.connect(self._updateDelayed) + Preferences.getInstance().preferenceChanged.connect(self._updateDelayed) + + self._update_timer = QTimer() + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) self._build_plate_number = -1 @@ -23,6 +33,9 @@ class ObjectsModel(ListModel): self._build_plate_number = nr self._update() + def _updateDelayed(self, *args): + self._update_timer.start() + def _update(self, *args): nodes = [] filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate") diff --git a/cura/Scene/ConvexHullDecorator.py b/cura/Scene/ConvexHullDecorator.py index 3a563c2764..66bc8a7fc3 100644 --- a/cura/Scene/ConvexHullDecorator.py +++ b/cura/Scene/ConvexHullDecorator.py @@ -1,6 +1,8 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from PyQt5.QtCore import QTimer + from UM.Application import Application from UM.Math.Polygon import Polygon from UM.Scene.SceneNodeDecorator import SceneNodeDecorator @@ -22,6 +24,10 @@ class ConvexHullDecorator(SceneNodeDecorator): self._global_stack = None + # Make sure the timer is created on the main thread + self._recompute_convex_hull_timer = None + Application.getInstance().callLater(self.createRecomputeConvexHullTimer) + self._raft_thickness = 0.0 # For raft thickness, DRY self._build_volume = Application.getInstance().getBuildVolume() @@ -33,6 +39,12 @@ class ConvexHullDecorator(SceneNodeDecorator): self._onGlobalStackChanged() + def createRecomputeConvexHullTimer(self): + self._recompute_convex_hull_timer = QTimer() + self._recompute_convex_hull_timer.setInterval(200) + self._recompute_convex_hull_timer.setSingleShot(True) + self._recompute_convex_hull_timer.timeout.connect(self.recomputeConvexHull) + def setNode(self, node): previous_node = self._node # Disconnect from previous node signals @@ -99,6 +111,12 @@ class ConvexHullDecorator(SceneNodeDecorator): return self._compute2DConvexHull() return None + def recomputeConvexHullDelayed(self): + if self._recompute_convex_hull_timer is not None: + self._recompute_convex_hull_timer.start() + else: + self.recomputeConvexHull() + def recomputeConvexHull(self): controller = Application.getInstance().getController() root = controller.getScene().getRoot() @@ -279,7 +297,8 @@ class ConvexHullDecorator(SceneNodeDecorator): def _onChanged(self, *args): self._raft_thickness = self._build_volume.getRaftThickness() - self.recomputeConvexHull() + if not args or args[0] == self._node: + self.recomputeConvexHullDelayed() def _onGlobalStackChanged(self): if self._global_stack: diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 35ce9cc37a..5c3dca9fae 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -158,9 +158,10 @@ class SimulationView(View): return self._nozzle_node def _onSceneChanged(self, node): - self.setActivity(False) - self.calculateMaxLayers() - self.calculateMaxPathsOnLayer(self._current_layer_num) + if node.getMeshData() is not None: + self.setActivity(False) + self.calculateMaxLayers() + self.calculateMaxPathsOnLayer(self._current_layer_num) def isBusy(self): return self._busy From 6909c9263a050010f1f69a5b66930ad50641ce4c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 16:32:53 +0100 Subject: [PATCH 2/2] CURA-4400 fix setting extruder number on a group printed with mixed extruders --- cura/CuraActions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index f517ec4217..75338f17b6 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -109,10 +109,6 @@ class CuraActions(QObject): nodes_to_change = [] for node in Selection.getAllSelectedObjects(): - # Do not change any nodes that already have the right extruder set. - if node.callDecoration("getActiveExtruder") == extruder_id: - continue - # If the node is a group, apply the active extruder to all children of the group. if node.callDecoration("isGroup"): for grouped_node in BreadthFirstIterator(node): @@ -125,6 +121,10 @@ class CuraActions(QObject): nodes_to_change.append(grouped_node) continue + # Do not change any nodes that already have the right extruder set. + if node.callDecoration("getActiveExtruder") == extruder_id: + continue + nodes_to_change.append(node) if not nodes_to_change: