From 3078ac2d2d2b46b4e8c5a2b5e70a938439e00b20 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 23 Mar 2018 09:46:05 +0100 Subject: [PATCH 1/6] Prevent scaling support eraser with scaled parent --- plugins/SupportEraser/SupportEraser.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 7884ca30c7..4804caebba 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -19,8 +19,10 @@ from cura.Scene.CuraSceneNode import CuraSceneNode from cura.PickingPass import PickingPass +from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation +from cura.Operations.SetParentOperation import SetParentOperation from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator @@ -117,7 +119,10 @@ class SupportEraser(Tool): new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) - op = AddSceneNodeOperation(node, parent) + op = GroupedOperation() + # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent + op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) + op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) From 977eb8c94d3364b98b27582700942884bfce8b3a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 23 Mar 2018 16:10:02 +0100 Subject: [PATCH 2/6] Fix duplicating SettingOverrideDecorator settings A deepcopy of a SettingOverrideDecorator also creates a deepcopy of a SettingContainer. This SettingContainer has the same id as the original, which makes CuraContainerStack.replaceContainer reject the new SettingContainer. --- cura/Settings/CuraContainerStack.py | 4 ++-- cura/Settings/SettingOverrideDecorator.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index ca4f866598..14d100f757 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -228,7 +228,7 @@ class CuraContainerStack(ContainerStack): # # \throws Exception.InvalidContainerError Raised when trying to replace a container with a container that has an incorrect type. @override(ContainerStack) - def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False) -> None: + def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False, force_replace: bool = False) -> None: expected_type = _ContainerIndexes.IndexTypeMap[index] if expected_type == "definition": if not isinstance(container, DefinitionContainer): @@ -237,7 +237,7 @@ class CuraContainerStack(ContainerStack): raise Exceptions.InvalidContainerError("Cannot replace container at index {index} with a container that is not of {type} type, but {actual_type} type.".format(index = index, type = expected_type, actual_type = container.getMetaDataEntry("type"))) current_container = self._containers[index] - if current_container.getId() == container.getId(): + if current_container.getId() == container.getId() and not force_replace: return super().replaceContainer(index, container, postpone_emit) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index e853a3a979..ee5fd42462 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -56,7 +56,8 @@ class SettingOverrideDecorator(SceneNodeDecorator): instance_container = copy.deepcopy(self._stack.getContainer(0), memo) ## Set the copied instance as the first (and only) instance container of the stack. - deep_copy._stack.replaceContainer(0, instance_container) + # Force replacing the container even though the id of the created deepcopy is the same + deep_copy._stack.replaceContainer(0, instance_container, force_replace = True) # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) From 78b49e8400b62472c322e2b755482372fdf57588 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 23 Mar 2018 16:35:36 +0100 Subject: [PATCH 3/6] When multiplying a parented node, multiply the parent instead (like groups) --- cura/MultiplyObjectsJob.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index b9f37ec6f8..3444da249f 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -32,14 +32,19 @@ class MultiplyObjectsJob(Job): root = scene.getRoot() arranger = Arrange.create(scene_root=root) + processed_nodes = [] nodes = [] for node in self._objects: # If object is part of a group, multiply group current_node = node - while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): + while current_node.getParent() and (current_node.getParent().callDecoration("isGroup") or current_node.getParent().callDecoration("isSliceable")): current_node = current_node.getParent() + if current_node in processed_nodes: + continue + processed_nodes.append(current_node) + node_too_big = False if node.getBoundingBox().width < 300 or node.getBoundingBox().depth < 300: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) From caf700750cdae6f8716e38675f336951a4c32bd0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 27 Mar 2018 08:32:13 +0200 Subject: [PATCH 4/6] Revert "Fix duplicating SettingOverrideDecorator settings" This reverts commit 977eb8c94d3364b98b27582700942884bfce8b3a. This has been fixed in a different way in c7a3d33411a51f4fe284bfc45f0bba178636cc27 --- cura/Settings/CuraContainerStack.py | 4 ++-- cura/Settings/SettingOverrideDecorator.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 14d100f757..ca4f866598 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -228,7 +228,7 @@ class CuraContainerStack(ContainerStack): # # \throws Exception.InvalidContainerError Raised when trying to replace a container with a container that has an incorrect type. @override(ContainerStack) - def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False, force_replace: bool = False) -> None: + def replaceContainer(self, index: int, container: ContainerInterface, postpone_emit: bool = False) -> None: expected_type = _ContainerIndexes.IndexTypeMap[index] if expected_type == "definition": if not isinstance(container, DefinitionContainer): @@ -237,7 +237,7 @@ class CuraContainerStack(ContainerStack): raise Exceptions.InvalidContainerError("Cannot replace container at index {index} with a container that is not of {type} type, but {actual_type} type.".format(index = index, type = expected_type, actual_type = container.getMetaDataEntry("type"))) current_container = self._containers[index] - if current_container.getId() == container.getId() and not force_replace: + if current_container.getId() == container.getId(): return super().replaceContainer(index, container, postpone_emit) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index ee5fd42462..e853a3a979 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -56,8 +56,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): instance_container = copy.deepcopy(self._stack.getContainer(0), memo) ## Set the copied instance as the first (and only) instance container of the stack. - # Force replacing the container even though the id of the created deepcopy is the same - deep_copy._stack.replaceContainer(0, instance_container, force_replace = True) + deep_copy._stack.replaceContainer(0, instance_container) # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) From 523e6a59e35b65c028b2e47fe96b201e4bffa076 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 9 Apr 2018 11:29:49 +0200 Subject: [PATCH 5/6] Exclude non-printing-meshes from bounding box of parents Non-printing-meshes inside a group should not affect push apart or drop to build plate --- cura/Scene/CuraSceneNode.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 48d271a2f2..428a59f554 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -103,6 +103,25 @@ class CuraSceneNode(SceneNode): return True return False + ## Override of SceneNode._calculateAABB to exclude non-printing-meshes from bounding box + def _calculateAABB(self): + aabb = None + if self._mesh_data: + aabb = self._mesh_data.getExtents(self.getWorldTransformation()) + else: # If there is no mesh_data, use a boundingbox that encompasses the local (0,0,0) + position = self.getWorldPosition() + aabb = AxisAlignedBox(minimum = position, maximum = position) + + for child in self._children: + if child.callDecoration("isNonPrintingMesh"): + # Non-printing-meshes inside a group should not affect push apart or drop to build plate + continue + if aabb is None: + aabb = child.getBoundingBox() + else: + aabb = aabb + child.getBoundingBox() + self._aabb = aabb + ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): copy = CuraSceneNode(no_setting_override = True) # Setting override will be added later From d9034a6c85f649d475ed9795f0e028d1ba033f05 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 15 Apr 2018 12:08:49 +0200 Subject: [PATCH 6/6] Only respond to left mouse button --- plugins/SupportEraser/SupportEraser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 4804caebba..06d9fc3707 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -58,7 +58,7 @@ class SupportEraser(Tool): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier - if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): + if event.type == Event.MousePressEvent and MouseEvent.LeftButton in event.buttons and self._controller.getToolsEnabled(): if ctrl_is_active: self._controller.setActiveTool("TranslateTool") return