mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-16 18:59:39 +08:00
Switch out the arranger algorithm for arrange all
CURA-7440
This commit is contained in:
parent
d16ab4fdd6
commit
b0a8a5ccab
@ -4,6 +4,9 @@ from PyQt5.QtCore import QCoreApplication
|
|||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
|
from UM.Math.Matrix import Matrix
|
||||||
|
from UM.Math.Quaternion import Quaternion
|
||||||
|
from UM.Operations.RotateOperation import RotateOperation
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Operations.TranslateOperation import TranslateOperation
|
from UM.Operations.TranslateOperation import TranslateOperation
|
||||||
@ -18,6 +21,7 @@ from cura.Arranging.Arrange import Arrange
|
|||||||
from cura.Arranging.ShapeArray import ShapeArray
|
from cura.Arranging.ShapeArray import ShapeArray
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from pynest2d import *
|
||||||
|
|
||||||
|
|
||||||
class ArrangeObjectsJob(Job):
|
class ArrangeObjectsJob(Job):
|
||||||
@ -38,64 +42,31 @@ class ArrangeObjectsJob(Job):
|
|||||||
machine_width = global_container_stack.getProperty("machine_width", "value")
|
machine_width = global_container_stack.getProperty("machine_width", "value")
|
||||||
machine_depth = global_container_stack.getProperty("machine_depth", "value")
|
machine_depth = global_container_stack.getProperty("machine_depth", "value")
|
||||||
|
|
||||||
arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = self._fixed_nodes, min_offset = self._min_offset)
|
factor = 10000
|
||||||
|
|
||||||
# Build set to exclude children (those get arranged together with the parents).
|
build_plate_bounding_box = Box(machine_width * factor, machine_depth * factor )
|
||||||
included_as_child = set()
|
|
||||||
|
node_items = []
|
||||||
for node in self._nodes:
|
for node in self._nodes:
|
||||||
included_as_child.update(node.getAllChildren())
|
hull_polygon = node.callDecoration("getConvexHull")
|
||||||
|
converted_points = []
|
||||||
|
for point in hull_polygon.getPoints():
|
||||||
|
converted_points.append(Point(point[0] * factor, point[1] * factor))
|
||||||
|
item = Item(converted_points)
|
||||||
|
node_items.append(item)
|
||||||
|
|
||||||
# Collect nodes to be placed
|
config = NfpConfig()
|
||||||
nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr)
|
config.accuracy = 1.0
|
||||||
for node in self._nodes:
|
num_bins = nest(node_items, build_plate_bounding_box, 1, config)
|
||||||
if node in included_as_child:
|
found_solution_for_all = num_bins == 1
|
||||||
continue
|
|
||||||
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = self._min_offset, include_children = True)
|
|
||||||
if offset_shape_arr is None:
|
|
||||||
Logger.log("w", "Node [%s] could not be converted to an array for arranging...", str(node))
|
|
||||||
continue
|
|
||||||
nodes_arr.append((offset_shape_arr.arr.shape[0] * offset_shape_arr.arr.shape[1], node, offset_shape_arr, hull_shape_arr))
|
|
||||||
|
|
||||||
# Sort the nodes with the biggest area first.
|
|
||||||
nodes_arr.sort(key=lambda item: item[0])
|
|
||||||
nodes_arr.reverse()
|
|
||||||
|
|
||||||
# Place nodes one at a time
|
|
||||||
start_priority = 0
|
|
||||||
last_priority = start_priority
|
|
||||||
last_size = None
|
|
||||||
grouped_operation = GroupedOperation()
|
grouped_operation = GroupedOperation()
|
||||||
found_solution_for_all = True
|
for node, node_item in zip(self._nodes, node_items):
|
||||||
not_fit_count = 0
|
rotation_matrix = Matrix()
|
||||||
for idx, (size, node, offset_shape_arr, hull_shape_arr) in enumerate(nodes_arr):
|
rotation_matrix.setByRotationAxis(node_item.rotation(),Vector(0, -1, 0))
|
||||||
# For performance reasons, we assume that when a location does not fit,
|
|
||||||
# it will also not fit for the next object (while what can be untrue).
|
|
||||||
if last_size == size: # This optimization works if many of the objects have the same size
|
|
||||||
start_priority = last_priority
|
|
||||||
else:
|
|
||||||
start_priority = 0
|
|
||||||
best_spot = arranger.bestSpot(hull_shape_arr, start_prio = start_priority)
|
|
||||||
x, y = best_spot.x, best_spot.y
|
|
||||||
node.removeDecorator(ZOffsetDecorator)
|
|
||||||
if node.getBoundingBox():
|
|
||||||
center_y = node.getWorldPosition().y - node.getBoundingBox().bottom
|
|
||||||
else:
|
|
||||||
center_y = 0
|
|
||||||
if x is not None: # We could find a place
|
|
||||||
last_size = size
|
|
||||||
last_priority = best_spot.priority
|
|
||||||
|
|
||||||
arranger.place(x, y, offset_shape_arr) # take place before the next one
|
grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
|
||||||
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0, node_item.translation().y() / factor)))
|
||||||
else:
|
|
||||||
Logger.log("d", "Arrange all: could not find spot!")
|
|
||||||
found_solution_for_all = False
|
|
||||||
grouped_operation.addOperation(TranslateOperation(node, Vector(200, center_y, -not_fit_count * 20), set_position = True))
|
|
||||||
not_fit_count += 1
|
|
||||||
|
|
||||||
status_message.setProgress((idx + 1) / len(nodes_arr) * 100)
|
|
||||||
Job.yieldThread()
|
|
||||||
QCoreApplication.processEvents()
|
|
||||||
|
|
||||||
grouped_operation.push()
|
grouped_operation.push()
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import os
|
|||||||
# tries to create PyQt objects on a non-main thread.
|
# tries to create PyQt objects on a non-main thread.
|
||||||
import Arcus # @UnusedImport
|
import Arcus # @UnusedImport
|
||||||
import Savitar # @UnusedImport
|
import Savitar # @UnusedImport
|
||||||
|
import pynest2d # @UnusedImport
|
||||||
|
|
||||||
from PyQt5.QtNetwork import QSslConfiguration, QSslSocket
|
from PyQt5.QtNetwork import QSslConfiguration, QSslSocket
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user