From 54d53756de262d8a654e8a23cf29e24252240e5e Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Mon, 18 Dec 2017 12:48:35 +0100 Subject: [PATCH 01/14] Ignore new plugin --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8d9ba4b2d2..88c4d5b6eb 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ plugins/CuraVariSlicePlugin plugins/CuraLiveScriptingPlugin plugins/CuraPrintProfileCreator plugins/OctoPrintPlugin +plugins/CuraCloudPlugin #Build stuff CMakeCache.txt From 0e1cd9957877180006c86557ed3f9979b18372f4 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 21 Dec 2017 17:08:44 +0100 Subject: [PATCH 02/14] Add flag to ignore discard or keep dialog when changing print setup --- cura/Settings/MachineManager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 05aed1f5e2..b3a2e6612b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -739,7 +739,7 @@ class MachineManager(QObject): ## Set the active material by switching out a container # Depending on from/to material+current variant, a quality profile is chosen and set. @pyqtSlot(str) - def setActiveMaterial(self, material_id: str): + def setActiveMaterial(self, material_id: str, always_discard_changes = False): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): containers = ContainerRegistry.getInstance().findInstanceContainers(id = material_id) if not containers or not self._active_container_stack: @@ -821,10 +821,10 @@ class MachineManager(QObject): if not old_quality_changes: new_quality_id = candidate_quality.getId() - self.setActiveQuality(new_quality_id) + self.setActiveQuality(new_quality_id, always_discard_changes = always_discard_changes) @pyqtSlot(str) - def setActiveVariant(self, variant_id: str): + def setActiveVariant(self, variant_id: str, always_discard_changes = False): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_id) if not containers or not self._active_container_stack: @@ -840,14 +840,14 @@ class MachineManager(QObject): if old_material: preferred_material_name = old_material.getName() preferred_material_id = self._updateMaterialContainer(self._global_container_stack.definition, self._global_container_stack, containers[0], preferred_material_name).id - self.setActiveMaterial(preferred_material_id) + self.setActiveMaterial(preferred_material_id, always_discard_changes = always_discard_changes) else: Logger.log("w", "While trying to set the active variant, no variant was found to replace.") ## set the active quality # \param quality_id The quality_id of either a quality or a quality_changes @pyqtSlot(str) - def setActiveQuality(self, quality_id: str): + def setActiveQuality(self, quality_id: str, always_discard_changes = False): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.blurSettings.emit() @@ -909,7 +909,7 @@ class MachineManager(QObject): # the dialog will be the those before the switching. self._executeDelayedActiveContainerStackChanges() - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1 and not always_discard_changes: Application.getInstance().discardOrKeepProfileChanges() ## Used to update material and variant in the active container stack with a delay. From 56435f12c0f1410e2447fbca1c3ced6c3642da37 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 21 Dec 2017 17:12:39 +0100 Subject: [PATCH 03/14] Add additional debug logging in machine manager for changing stack setup --- cura/Settings/MachineManager.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b3a2e6612b..dbff11279f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -851,6 +851,8 @@ class MachineManager(QObject): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.blurSettings.emit() + Logger.log("d", "Attempting to change the active quality to %s", quality_id) + containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = quality_id) if not containers or not self._global_container_stack: return @@ -905,6 +907,8 @@ class MachineManager(QObject): "quality_changes": stack_quality_changes }) + Logger.log("d", "Active quality changed") + # show the keep/discard dialog after the containers have been switched. Otherwise, the default values on # the dialog will be the those before the switching. self._executeDelayedActiveContainerStackChanges() @@ -917,6 +921,9 @@ class MachineManager(QObject): # before the user decided to keep or discard any of their changes using the dialog. # The Application.onDiscardOrKeepProfileChangesClosed signal triggers this method. def _executeDelayedActiveContainerStackChanges(self): + + Logger.log("d", "Applying configuration changes...") + if self._new_variant_container is not None: self._active_container_stack.variant = self._new_variant_container self._new_variant_container = None @@ -937,6 +944,8 @@ class MachineManager(QObject): self._new_quality_containers.clear() + Logger.log("d", "New configuration applied") + ## Cancel set changes for material and variant in the active container stack. # Used for ignoring any changes when switching between printers (setActiveMachine) def _cancelDelayedActiveContainerStackChanges(self): From 5b43a32986ba176c703479ed01e2de5985cfb3a7 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 11:56:47 +0100 Subject: [PATCH 04/14] Extract UI boot from non-UI boot --- cura/CuraApplication.py | 48 ++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e90dfd70d3..66adcebb29 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -636,13 +636,35 @@ class CuraApplication(QtApplication): def run(self): self.preRun() - - self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) + # Check if we should run as single instance or not self._setUpSingleInstanceServer() + # Detect in which mode to run and execute that mode + if self.getCommandLineOption("headless", False): + self.runWithoutGUI() + else: + self.runWithGUI() + + ## Run Cura without GUI elements and interaction (server mode). + def runWithoutGUI(self): + self.closeSplash() + + for file_name in self.getCommandLineOption("file", []): + self._openFile(file_name) + for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. + self._openFile(file_name) + + self._started = True + self.exec_() + + ## Run Cura with GUI (desktop mode). + def runWithGUI(self): + self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) + controller = self.getController() + # Initialize UI state controller.setActiveStage("PrepareStage") controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") @@ -662,8 +684,10 @@ class CuraApplication(QtApplication): # Set the build volume of the arranger to the used build volume Arrange.build_volume = self._volume + # Set default background color for scene self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) + # Initialize platform physics self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) @@ -691,22 +715,16 @@ class CuraApplication(QtApplication): self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) - run_without_gui = self.getCommandLineOption("headless", False) - if not run_without_gui: - self.initializeEngine() - controller.setActiveStage("PrepareStage") + self.initializeEngine() - if run_without_gui or self._engine.rootObjects: - self.closeSplash() + # Make sure the correct stage is activated + controller.setActiveStage("PrepareStage") - for file_name in self.getCommandLineOption("file", []): - self._openFile(file_name) - for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. - self._openFile(file_name) + # Hide the splash screen + self.closeSplash() - self._started = True - - self.exec_() + self._started = True + self.exec_() def getMachineManager(self, *args) -> MachineManager: if self._machine_manager is None: From 1bfe296be711f5f05c32e4a1fb4a9cfaed26952f Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 11:59:38 +0100 Subject: [PATCH 05/14] Move all QML registrations together --- cura/CuraApplication.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 66adcebb29..c6ae0392a1 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -705,13 +705,6 @@ class CuraApplication(QtApplication): self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) - qmlRegisterSingletonType(ExtruderManager, "Cura", 1, 0, "ExtruderManager", self.getExtruderManager) - qmlRegisterSingletonType(MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager) - qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager) - qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager", self.getSettingInheritanceManager) - qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager) - qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) - self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) @@ -785,6 +778,13 @@ class CuraApplication(QtApplication): qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") + qmlRegisterSingletonType(ExtruderManager, "Cura", 1, 0, "ExtruderManager", self.getExtruderManager) + qmlRegisterSingletonType(MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager) + qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager) + qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager", self.getSettingInheritanceManager) + qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager) + qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) + qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") qmlRegisterType(ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") qmlRegisterSingletonType(ProfilesModel, "Cura", 1, 0, "ProfilesModel", ProfilesModel.createProfilesModel) From 4bc47585e63e3becbbb8442ffdf1da2695a9dd7c Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 12:27:45 +0100 Subject: [PATCH 06/14] Improvement in booting order --- cura/CuraApplication.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c6ae0392a1..305c69f833 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -646,10 +646,6 @@ class CuraApplication(QtApplication): else: self.runWithGUI() - ## Run Cura without GUI elements and interaction (server mode). - def runWithoutGUI(self): - self.closeSplash() - for file_name in self.getCommandLineOption("file", []): self._openFile(file_name) for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. @@ -658,6 +654,10 @@ class CuraApplication(QtApplication): self._started = True self.exec_() + ## Run Cura without GUI elements and interaction (server mode). + def runWithoutGUI(self): + self.closeSplash() + ## Run Cura with GUI (desktop mode). def runWithGUI(self): self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) @@ -716,9 +716,6 @@ class CuraApplication(QtApplication): # Hide the splash screen self.closeSplash() - self._started = True - self.exec_() - def getMachineManager(self, *args) -> MachineManager: if self._machine_manager is None: self._machine_manager = MachineManager.createMachineManager() From 07ad74d7f92acf61394abb900bf75fe0d87b9c80 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 22 Dec 2017 14:20:54 +0100 Subject: [PATCH 07/14] =?UTF-8?q?Always=20construct=20scene=20and=20build?= =?UTF-8?q?=20plat=C3=AB=20node=20tree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cura/CuraApplication.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 305c69f833..9fd5b3913f 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -640,12 +640,18 @@ class CuraApplication(QtApplication): # Check if we should run as single instance or not self._setUpSingleInstanceServer() + # Setup scene and build volume + root = self.getController().getScene().getRoot() + self._volume = BuildVolume.BuildVolume(self.getController().getScene().getRoot()) + Arrange.build_volume = self._volume + # Detect in which mode to run and execute that mode if self.getCommandLineOption("headless", False): self.runWithoutGUI() else: self.runWithGUI() + # Pre-load files if requested for file_name in self.getCommandLineOption("file", []): self._openFile(file_name) for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. @@ -676,41 +682,37 @@ class CuraApplication(QtApplication): Selection.selectionChanged.connect(self.onSelectionChanged) - root = controller.getScene().getRoot() - - # The platform is a child of BuildVolume - self._volume = BuildVolume.BuildVolume(root) - - # Set the build volume of the arranger to the used build volume - Arrange.build_volume = self._volume - # Set default background color for scene self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) # Initialize platform physics self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) + # Initialize camera + root = controller.getScene().getRoot() camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") - camera_tool = self.getController().getTool("CameraTool") + # Initialize camera tool + camera_tool = controller.getTool("CameraTool") camera_tool.setOrigin(Vector(0, 100, 0)) camera_tool.setZoomRange(0.1, 200000) + # Initialize camera animations self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) + # Initialize QML engine self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) - self.initializeEngine() - # Make sure the correct stage is activated + # Make sure the correct stage is activated after QML is loaded controller.setActiveStage("PrepareStage") # Hide the splash screen From bd1bf2caafcdd9dac33bf059423a08155ccda129 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 12 Jan 2018 17:38:47 +0100 Subject: [PATCH 08/14] Add use_gui flag in application, don't use theme functions when not using gui --- cura/CuraApplication.py | 16 +++++++++++++++- cura/Scene/ConvexHullNode.py | 5 ++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e9484d5b3a..3adb8681cc 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -142,6 +142,7 @@ class CuraApplication(QtApplication): if not hasattr(sys, "frozen"): Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")) + self._use_gui = True self._open_file_queue = [] # Files to open when plug-ins are loaded. # Need to do this before ContainerRegistry tries to load the machines @@ -451,7 +452,7 @@ class CuraApplication(QtApplication): elif choice == "always_keep": # don't show dialog and KEEP the profile self.discardOrKeepProfileChangesClosed("keep") - else: + elif self._use_gui: # ALWAYS ask whether to keep or discard the profile self.showDiscardOrKeepProfileChanges.emit() has_user_interaction = True @@ -676,10 +677,13 @@ class CuraApplication(QtApplication): ## Run Cura without GUI elements and interaction (server mode). def runWithoutGUI(self): + self._use_gui = False self.closeSplash() ## Run Cura with GUI (desktop mode). def runWithGUI(self): + self._use_gui = True + self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() @@ -732,6 +736,9 @@ class CuraApplication(QtApplication): # Hide the splash screen self.closeSplash() + def hasGui(self): + return self._use_gui + def getMachineManager(self, *args) -> MachineManager: if self._machine_manager is None: self._machine_manager = MachineManager.createMachineManager() @@ -1344,6 +1351,7 @@ class CuraApplication(QtApplication): pass fileLoaded = pyqtSignal(str) + fileCompleted = pyqtSignal(str) def _reloadMeshFinished(self, job): # TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh! @@ -1353,6 +1361,10 @@ class CuraApplication(QtApplication): else: Logger.log("w", "Could not find a mesh in reloaded node.") + ## Import a file from disk + def openFile(self, filename): + self._openFile(filename) + def _openFile(self, filename): self.readLocalFile(QUrl.fromLocalFile(filename)) @@ -1514,6 +1526,8 @@ class CuraApplication(QtApplication): op.push() scene.sceneChanged.emit(node) + self.fileCompleted.emit(filename) + def addNonSliceableExtension(self, extension): self._non_sliceable_extensions.append(extension) diff --git a/cura/Scene/ConvexHullNode.py b/cura/Scene/ConvexHullNode.py index 02d8ed833c..4db31cf0ac 100644 --- a/cura/Scene/ConvexHullNode.py +++ b/cura/Scene/ConvexHullNode.py @@ -24,7 +24,10 @@ class ConvexHullNode(SceneNode): self._original_parent = parent # Color of the drawn convex hull - self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb()) + if Application.getInstance().hasGui(): + self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb()) + else: + self._color = Color(0, 0, 0) # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting. self._mesh_height = 0.1 From 41dec889ac09fb469e3f5c77468b3db7bc3a7b9b Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Mon, 15 Jan 2018 11:52:15 +0100 Subject: [PATCH 09/14] Also emit a back-end slicing error when the job result is an actual error --- plugins/CuraEngineBackend/CuraEngineBackend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 3272fb019d..f64dd08f3e 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -290,6 +290,7 @@ class CuraEngineBackend(QObject, Backend): self._start_slice_job = None if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error: + self.backendStateChange.emit(BackendState.Error) return if job.getResult() == StartSliceJob.StartJobResult.MaterialIncompatible: From 02b681a8f27f8fc2d1ab5109f80ceaffe132b45f Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 16 Jan 2018 15:10:16 +0100 Subject: [PATCH 10/14] Fixes for slicing --- cura/Arranging/ArrangeObjectsJob.py | 2 ++ cura/CuraApplication.py | 12 ++++++------ cura/Scene/CuraSceneNode.py | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index f529543779..765c3333cb 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -88,3 +88,5 @@ class ArrangeObjectsJob(Job): no_full_solution_message = Message(i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"), title = i18n_catalog.i18nc("@info:title", "Can't Find Location")) no_full_solution_message.show() + + self.finished.emit(self) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ff38a24cc6..99fc13265a 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -23,6 +23,7 @@ from UM.Settings.ContainerStack import ContainerStack from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Validator import Validator from UM.Message import Message +from UM.Signal import Signal from UM.i18n import i18nCatalog from UM.Workspace.WorkspaceReader import WorkspaceReader from UM.Decorators import deprecated @@ -805,10 +806,13 @@ class CuraApplication(QtApplication): # \param engine The QML engine. def registerObjects(self, engine): super().registerObjects(engine) + engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("CuraApplication", self) + self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) + self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) @@ -1369,10 +1373,6 @@ class CuraApplication(QtApplication): else: Logger.log("w", "Could not find a mesh in reloaded node.") - ## Import a file from disk - def openFile(self, filename): - self._openFile(filename) - def _openFile(self, filename): self.readLocalFile(QUrl.fromLocalFile(filename)) @@ -1521,8 +1521,8 @@ class CuraApplication(QtApplication): # Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher node, _ = arranger.findNodePlacement(node, offset_shape_arr, hull_shape_arr, step = 10) - # This node is deepcopied from some other node which already has a BuildPlateDecorator, but the deepcopy - # of BuildPlateDecorator produces one that's assoicated with build plate -1. So, here we need to check if + # This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy + # of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if # the BuildPlateDecorator exists or not and always set the correct build plate number. build_plate_decorator = node.getDecorator(BuildPlateDecorator) if build_plate_decorator is None: diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 9df2931f0b..1bffe4392b 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -9,7 +9,7 @@ from copy import deepcopy class CuraSceneNode(SceneNode): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._outside_buildarea = True + self._outside_buildarea = False def setOutsideBuildArea(self, new_value): self._outside_buildarea = new_value From cbd6a996fad8ff6e0526d95cae62db50dc02b61f Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 16 Jan 2018 15:10:46 +0100 Subject: [PATCH 11/14] Remove unused Signal import --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 99fc13265a..b21a5bcf26 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -23,7 +23,6 @@ from UM.Settings.ContainerStack import ContainerStack from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Validator import Validator from UM.Message import Message -from UM.Signal import Signal from UM.i18n import i18nCatalog from UM.Workspace.WorkspaceReader import WorkspaceReader from UM.Decorators import deprecated From 8a53549bce61ec6df04297574ee21a09c3983d6d Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 17 Jan 2018 17:01:03 +0100 Subject: [PATCH 12/14] CURA-4033 split update bounds for a single node in buildvolume and also call it from readMeshFinished --- cura/BuildVolume.py | 68 +++++++++++++++++++++++-------------- cura/CuraApplication.py | 1 + cura/Scene/CuraSceneNode.py | 1 + 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 2567641cc9..7a495b2064 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -1,6 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Settings.ExtruderManager import ExtruderManager from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog @@ -25,7 +26,7 @@ catalog = i18nCatalog("cura") import numpy import math -from typing import List +from typing import List, Optional # Setting for clearance around the prime PRIME_CLEARANCE = 6.5 @@ -194,8 +195,7 @@ class BuildVolume(SceneNode): return True - ## For every sliceable node, update node._outside_buildarea - # + ## For every sliceable node, update outsideBuildArea def updateNodeBoundaryCheck(self): root = Application.getInstance().getController().getScene().getRoot() nodes = list(BreadthFirstIterator(root)) @@ -212,35 +212,51 @@ class BuildVolume(SceneNode): for node in nodes: # Need to check group nodes later - if node.callDecoration("isGroup"): - group_nodes.append(node) # Keep list of affected group_nodes - - if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - node._outside_buildarea = False - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: - node._outside_buildarea = True - continue - - convex_hull = node.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node._outside_buildarea = True - continue + self.checkBoundsAndUpdate(node, bounds = build_volume_bounding_box) # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: for child_node in group_node.getAllChildren(): child_node._outside_buildarea = group_node._outside_buildarea + ## Update the outsideBuildArea of a single node, given bounds or current build volume + def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None): + if not isinstance(node, CuraSceneNode): + return + + if bounds is None: + build_volume_bounding_box = self.getBoundingBox() + if build_volume_bounding_box: + # 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. + return + else: + build_volume_bounding_box = bounds + + if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): + bbox = node.getBoundingBox() + + # Mark the node as outside the build volume if the bounding box test fails. + if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + node.setOutsideBuildArea(True) + return + + convex_hull = self.callDecoration("getConvexHull") + if convex_hull: + if not convex_hull.isValid(): + return + # Check for collisions between disallowed areas and the object + for area in self.getDisallowedAreas(): + overlap = convex_hull.intersectsPolygon(area) + if overlap is None: + continue + node.setOutsideBuildArea(True) + return + node.setOutsideBuildArea(False) + ## Recalculates the build volume & disallowed areas. def rebuild(self): if not self._width or not self._height or not self._depth: diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ff38a24cc6..0b10ce8735 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1481,6 +1481,7 @@ class CuraApplication(QtApplication): node.setSelectable(True) node.setName(os.path.basename(filename)) + self.getBuildVolume().checkBoundsAndUpdate(node) extension = os.path.splitext(filename)[1] if extension.lower() in self._non_sliceable_extensions: diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 9df2931f0b..c5dcffd2c2 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -1,5 +1,6 @@ from UM.Application import Application from UM.Logger import Logger +from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Scene.SceneNode import SceneNode from copy import deepcopy From 5e99fd6c1e2022989cf38d421789c06aeea66f72 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 18 Jan 2018 09:05:40 +0100 Subject: [PATCH 13/14] Fixes for print information when running in headless mode --- cura/CuraApplication.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 603ffb8bd4..bfaeb26d8d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -673,6 +673,10 @@ class CuraApplication(QtApplication): for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) + # initialize info objects + self._print_information = PrintInformation.PrintInformation() + self._cura_actions = CuraActions.CuraActions(self) + self._started = True self.exec_() @@ -807,13 +811,10 @@ class CuraApplication(QtApplication): def registerObjects(self, engine): super().registerObjects(engine) + # global contexts engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("CuraApplication", self) - - self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) - - self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") From 68347afc480b39b44efb56adc065e0f8da78ee20 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 18 Jan 2018 14:40:15 +0100 Subject: [PATCH 14/14] CURA-4033 fix init order of print information --- cura/CuraApplication.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index bfaeb26d8d..b825e456c2 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -661,6 +661,10 @@ class CuraApplication(QtApplication): self._volume = BuildVolume.BuildVolume(self.getController().getScene().getRoot()) Arrange.build_volume = self._volume + # initialize info objects + self._print_information = PrintInformation.PrintInformation() + self._cura_actions = CuraActions.CuraActions(self) + # Detect in which mode to run and execute that mode if self.getCommandLineOption("headless", False): self.runWithoutGUI() @@ -673,10 +677,6 @@ class CuraApplication(QtApplication): for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) - # initialize info objects - self._print_information = PrintInformation.PrintInformation() - self._cura_actions = CuraActions.CuraActions(self) - self._started = True self.exec_()