diff --git a/cura/Arrange.py b/cura/Arrange.py index 5cbd2b25ad..9ba1f67396 100755 --- a/cura/Arrange.py +++ b/cura/Arrange.py @@ -29,6 +29,7 @@ class Arrange: self._scale = scale # convert input coordinates to arrange coordinates self._offset_x = offset_x self._offset_y = offset_y + self._start_priority = 0 ## Helper to create an Arranger instance # @@ -71,14 +72,12 @@ class Arrange: # \param count Number of objects def findNodePlacements(self, node, offset_shape_arr, hull_shape_arr, count = 1, step = 1): nodes = [] - start_prio = 0 for i in range(count): new_node = copy.deepcopy(node) - best_spot = self.bestSpot( - offset_shape_arr, start_prio = start_prio, step = step) + offset_shape_arr, start_prio = self._start_priority, step = step) x, y = best_spot.x, best_spot.y - start_prio = best_spot.priority + self._start_priority = best_spot.priority # Ensure that the object is above the build platform new_node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator) if new_node.getBoundingBox(): diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 636753b632..9996935f80 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -39,6 +39,7 @@ from cura.SliceableObjectDecorator import SliceableObjectDecorator from cura.BlockSlicingDecorator import BlockSlicingDecorator from cura.ArrangeObjectsJob import ArrangeObjectsJob +from cura.MultiplyObjectsJob import MultiplyObjectsJob from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType from UM.Settings.ContainerRegistry import ContainerRegistry @@ -322,8 +323,6 @@ class CuraApplication(QtApplication): experimental """.replace("\n", ";").replace(" ", "")) - - self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) @@ -852,26 +851,9 @@ class CuraApplication(QtApplication): # \param min_offset minimum offset to other objects. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count, min_offset = 8): - node = self.getController().getScene().findObject(object_id) - - if not node and object_id != 0: # Workaround for tool handles overlapping the selected object - node = Selection.getSelectedObject(0) - - # If object is part of a group, multiply group - current_node = node - while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): - current_node = current_node.getParent() - - root = self.getController().getScene().getRoot() - arranger = Arrange.create(scene_root = root) - offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset = min_offset) - nodes = arranger.findNodePlacements(current_node, offset_shape_arr, hull_shape_arr, count = count) - - if nodes: - op = GroupedOperation() - for new_node in nodes: - op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent())) - op.push() + job = MultiplyObjectsJob(object_id, count, min_offset) + job.start() + return ## Center object on platform. @pyqtSlot("quint64") diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py new file mode 100644 index 0000000000..184dd8a07e --- /dev/null +++ b/cura/MultiplyObjectsJob.py @@ -0,0 +1,64 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from UM.Job import Job +from UM.Scene.SceneNode import SceneNode +from UM.Math.Vector import Vector +from UM.Operations.SetTransformOperation import SetTransformOperation +from UM.Operations.TranslateOperation import TranslateOperation +from UM.Operations.GroupedOperation import GroupedOperation +from UM.Logger import Logger +from UM.Message import Message +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("cura") + +from cura.ZOffsetDecorator import ZOffsetDecorator +from cura.Arrange import Arrange +from cura.ShapeArray import ShapeArray + +from typing import List + +from UM.Application import Application +from UM.Scene.Selection import Selection +from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation + + +class MultiplyObjectsJob(Job): + def __init__(self, object_id, count, min_offset = 8): + super().__init__() + self._object_id = object_id + self._count = count + self._min_offset = min_offset + + def run(self): + status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0, + dismissable=False, progress=0) + status_message.show() + scene = Application.getInstance().getController().getScene() + node = scene.findObject(self._object_id) + + if not node and self._object_id != 0: # Workaround for tool handles overlapping the selected object + node = Selection.getSelectedObject(0) + + # If object is part of a group, multiply group + current_node = node + while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): + current_node = current_node.getParent() + + root = scene.getRoot() + arranger = Arrange.create(scene_root=root) + offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) + nodes = [] + + for i in range(self._count): + # We do place the nodes one by one, as we want to yield in between. + nodes.extend(arranger.findNodePlacements(current_node, offset_shape_arr, hull_shape_arr, count = 1)) + Job.yieldThread() + status_message.setProgress((i + 1) / self._count * 100) + + if nodes: + op = GroupedOperation() + for new_node in nodes: + op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent())) + op.push() + status_message.hide() \ No newline at end of file