Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/cura
diff options
context:
space:
mode:
authorGhostkeeper <rubend@tutanota.com>2021-10-18 14:23:29 +0300
committerGhostkeeper <rubend@tutanota.com>2021-10-18 14:23:29 +0300
commit0d350b5f96e614b1c2652ebe52941ef390a20ebf (patch)
treec25caf9ffdb3d761d9e907be38d6eb8a559a6951 /cura
parent5ed57e403c082d5d78c0f311c489b98368d974f6 (diff)
parent89c5a38afa10a2ebc8415f3d1a5c6daad5d1d8e8 (diff)
Merge branch '4.12' into CURA-8609_sync_materials_to_printer
Diffstat (limited to 'cura')
-rw-r--r--cura/Arranging/Nest2DArrange.py42
-rwxr-xr-xcura/BuildVolume.py5
-rwxr-xr-xcura/CuraApplication.py4
-rw-r--r--cura/Machines/Models/QualityProfilesDropDownMenuModel.py4
-rw-r--r--cura/MultiplyObjectsJob.py39
5 files changed, 65 insertions, 29 deletions
diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py
index fdac63cd9d..ebe96202f2 100644
--- a/cura/Arranging/Nest2DArrange.py
+++ b/cura/Arranging/Nest2DArrange.py
@@ -110,18 +110,11 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV
return found_solution_for_all, node_items
-def arrange(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, factor = 10000, add_new_nodes_in_scene: bool = False) -> bool:
- """
- Find placement for a set of scene nodes, and move them by using a single grouped operation.
- :param nodes_to_arrange: The list of nodes that need to be moved.
- :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
- :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
- are placed.
- :param factor: The library that we use is int based. This factor defines how accuracte we want it to be.
- :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
-
- :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
- """
+def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"],
+ build_volume: "BuildVolume",
+ fixed_nodes: Optional[List["SceneNode"]] = None,
+ factor = 10000,
+ add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]:
scene_root = Application.getInstance().getController().getScene().getRoot()
found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor)
@@ -143,6 +136,27 @@ def arrange(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fi
grouped_operation.addOperation(
TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True))
not_fit_count += 1
- grouped_operation.push()
- return found_solution_for_all
+ return grouped_operation, not_fit_count
+
+
+def arrange(nodes_to_arrange: List["SceneNode"],
+ build_volume: "BuildVolume",
+ fixed_nodes: Optional[List["SceneNode"]] = None,
+ factor = 10000,
+ add_new_nodes_in_scene: bool = False) -> bool:
+ """
+ Find placement for a set of scene nodes, and move them by using a single grouped operation.
+ :param nodes_to_arrange: The list of nodes that need to be moved.
+ :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
+ :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
+ are placed.
+ :param factor: The library that we use is int based. This factor defines how accuracte we want it to be.
+ :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
+
+ :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
+ """
+
+ grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, factor, add_new_nodes_in_scene)
+ grouped_operation.push()
+ return not_fit_count != 0
diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py
index cf397e395e..e0c43c4876 100755
--- a/cura/BuildVolume.py
+++ b/cura/BuildVolume.py
@@ -1078,9 +1078,10 @@ class BuildVolume(SceneNode):
# setting does *not* have a limit_to_extruder setting (which means that we can't ask the global extruder what
# the value is.
adhesion_extruder = self._global_container_stack.getProperty("adhesion_extruder_nr", "value")
- skirt_brim_line_width = self._global_container_stack.extruderList[int(adhesion_extruder)].getProperty("skirt_brim_line_width", "value")
+ adhesion_stack = self._global_container_stack.extruderList[int(adhesion_extruder)]
+ skirt_brim_line_width = adhesion_stack.getProperty("skirt_brim_line_width", "value")
- initial_layer_line_width_factor = self._global_container_stack.getProperty("initial_layer_line_width_factor", "value")
+ initial_layer_line_width_factor = adhesion_stack.getProperty("initial_layer_line_width_factor", "value")
# Use brim width if brim is enabled OR the prime tower has a brim.
if adhesion_type == "brim":
brim_line_count = self._global_container_stack.getProperty("brim_line_count", "value")
diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py
index 01ded93124..3d4ec1209f 100755
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -750,7 +750,9 @@ class CuraApplication(QtApplication):
@pyqtSlot(str, result = QUrl)
def getDefaultPath(self, key):
default_path = self.getPreferences().getValue("local_file/%s" % key)
- return QUrl.fromLocalFile(default_path)
+ if os.path.exists(default_path):
+ return QUrl.fromLocalFile(default_path)
+ return QUrl()
@pyqtSlot(str, str)
def setDefaultPath(self, key, default_path):
diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
index 7aa30c6f82..f7316e9c09 100644
--- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
+++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
@@ -41,10 +41,6 @@ class QualityProfilesDropDownMenuModel(ListModel):
machine_manager.activeQualityGroupChanged.connect(self._onChange)
machine_manager.activeMaterialChanged.connect(self._onChange)
machine_manager.activeVariantChanged.connect(self._onChange)
- machine_manager.extruderChanged.connect(self._onChange)
-
- extruder_manager = application.getExtruderManager()
- extruder_manager.extrudersChanged.connect(self._onChange)
self._layer_height_unit = "" # This is cached
diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py
index 4c1caf137c..1446ae687e 100644
--- a/cura/MultiplyObjectsJob.py
+++ b/cura/MultiplyObjectsJob.py
@@ -6,11 +6,15 @@ from typing import List
from UM.Application import Application
from UM.Job import Job
+from UM.Math.Vector import Vector
from UM.Message import Message
+from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
+from UM.Operations.GroupedOperation import GroupedOperation
+from UM.Operations.TranslateOperation import TranslateOperation
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.i18n import i18nCatalog
-from cura.Arranging.Nest2DArrange import arrange
+from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange
i18n_catalog = i18nCatalog("cura")
@@ -43,11 +47,11 @@ class MultiplyObjectsJob(Job):
# Only count sliceable objects
if node_.callDecoration("isSliceable"):
fixed_nodes.append(node_)
-
+ nodes_to_add_without_arrange = []
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") or current_node.getParent().callDecoration("isSliceable")):
+ while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
current_node = current_node.getParent()
if current_node in processed_nodes:
@@ -56,19 +60,38 @@ class MultiplyObjectsJob(Job):
for _ in range(self._count):
new_node = copy.deepcopy(node)
-
# Same build plate
build_plate_number = current_node.callDecoration("getBuildPlateNumber")
new_node.callDecoration("setBuildPlateNumber", build_plate_number)
for child in new_node.getChildren():
child.callDecoration("setBuildPlateNumber", build_plate_number)
-
- nodes.append(new_node)
+ if not current_node.getParent().callDecoration("isSliceable"):
+ nodes.append(new_node)
+ else:
+ # The node we're trying to place has another node that is sliceable as a parent.
+ # As such, we shouldn't arrange it (but it should be added to the scene!)
+ nodes_to_add_without_arrange.append(new_node)
+ new_node.setParent(current_node.getParent())
found_solution_for_all = True
+ group_operation = GroupedOperation()
if nodes:
- found_solution_for_all = arrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes,
- factor = 10000, add_new_nodes_in_scene = True)
+ group_operation, not_fit_count = createGroupOperationForArrange(nodes,
+ Application.getInstance().getBuildVolume(),
+ fixed_nodes,
+ factor = 10000,
+ add_new_nodes_in_scene = True)
+ found_solution_for_all = not_fit_count == 0
+
+ if nodes_to_add_without_arrange:
+ for nested_node in nodes_to_add_without_arrange:
+ group_operation.addOperation(AddSceneNodeOperation(nested_node, nested_node.getParent()))
+ # Move the node a tiny bit so it doesn't overlap with the existing one.
+ # This doesn't fix it if someone creates more than one duplicate, but it at least shows that something
+ # happened (and after moving it, it's clear that there are more underneath)
+ group_operation.addOperation(TranslateOperation(nested_node, Vector(2.5, 2.5, 2.5)))
+
+ group_operation.push()
status_message.hide()
if not found_solution_for_all: