mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-13 18:55:59 +08:00
Merge pull request #20352 from Ultimaker/CURA-12169_fix-autoarrange-for-disallowed-areas
CURA-12169 fix autoarrange for disallowed areas
This commit is contained in:
commit
650e7994cc
@ -40,7 +40,7 @@ class ArrangeObjectsJob(Job):
|
|||||||
|
|
||||||
found_solution_for_all = False
|
found_solution_for_all = False
|
||||||
try:
|
try:
|
||||||
found_solution_for_all = arranger.arrange()
|
found_solution_for_all = arranger.arrange(only_if_full_success = True)
|
||||||
except: # If the thread crashes, the message should still close
|
except: # If the thread crashes, the message should still close
|
||||||
Logger.logException("e",
|
Logger.logException("e",
|
||||||
"Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.")
|
"Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.")
|
||||||
|
@ -16,12 +16,16 @@ class Arranger:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def arrange(self, add_new_nodes_in_scene: bool = False) -> bool:
|
def arrange(self, add_new_nodes_in_scene: bool = False, only_if_full_success: bool = False) -> bool:
|
||||||
"""
|
"""
|
||||||
Find placement for a set of scene nodes, and move them by using a single grouped operation.
|
Find placement for a set of scene nodes, and move them by using a single grouped operation.
|
||||||
:param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations
|
: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
|
:return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
|
||||||
"""
|
"""
|
||||||
grouped_operation, not_fit_count = self.createGroupOperationForArrange(add_new_nodes_in_scene)
|
grouped_operation, not_fit_count = self.createGroupOperationForArrange(add_new_nodes_in_scene)
|
||||||
grouped_operation.push()
|
full_success = not_fit_count == 0
|
||||||
return not_fit_count == 0
|
|
||||||
|
if full_success or not only_if_full_success:
|
||||||
|
grouped_operation.push()
|
||||||
|
|
||||||
|
return full_success
|
||||||
|
@ -54,22 +54,6 @@ class Nest2DArrange(Arranger):
|
|||||||
machine_depth = self._build_volume.getDepth() - (edge_disallowed_size * 2)
|
machine_depth = self._build_volume.getDepth() - (edge_disallowed_size * 2)
|
||||||
build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor))
|
build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor))
|
||||||
|
|
||||||
if self._fixed_nodes is None:
|
|
||||||
self._fixed_nodes = []
|
|
||||||
|
|
||||||
# Add all the items we want to arrange
|
|
||||||
node_items = []
|
|
||||||
for node in self._nodes_to_arrange:
|
|
||||||
hull_polygon = node.callDecoration("getConvexHull")
|
|
||||||
if not hull_polygon or hull_polygon.getPoints is None:
|
|
||||||
Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName()))
|
|
||||||
continue
|
|
||||||
converted_points = []
|
|
||||||
for point in hull_polygon.getPoints():
|
|
||||||
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
|
||||||
item = Item(converted_points)
|
|
||||||
node_items.append(item)
|
|
||||||
|
|
||||||
# Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas)
|
# Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas)
|
||||||
half_machine_width = 0.5 * machine_width - 1
|
half_machine_width = 0.5 * machine_width - 1
|
||||||
half_machine_depth = 0.5 * machine_depth - 1
|
half_machine_depth = 0.5 * machine_depth - 1
|
||||||
@ -80,37 +64,64 @@ class Nest2DArrange(Arranger):
|
|||||||
[half_machine_width, half_machine_depth]
|
[half_machine_width, half_machine_depth]
|
||||||
], numpy.float32))
|
], numpy.float32))
|
||||||
|
|
||||||
disallowed_areas = self._build_volume.getDisallowedAreas()
|
def _convert_points(points):
|
||||||
for area in disallowed_areas:
|
if points is not None and len(points) > 2: # numpy array has to be explicitly checked against None
|
||||||
converted_points = []
|
converted_points = []
|
||||||
|
for point in points:
|
||||||
|
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
||||||
|
return [converted_points]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
polygons_nodes_to_arrange = []
|
||||||
|
for node in self._nodes_to_arrange:
|
||||||
|
hull_polygon = node.callDecoration("getConvexHull")
|
||||||
|
if not hull_polygon or hull_polygon.getPoints is None:
|
||||||
|
Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName()))
|
||||||
|
continue
|
||||||
|
|
||||||
|
polygons_nodes_to_arrange += _convert_points(hull_polygon.getPoints())
|
||||||
|
|
||||||
|
polygons_disallowed_areas = []
|
||||||
|
for area in self._build_volume.getDisallowedAreas():
|
||||||
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
# Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise)
|
||||||
clipped_area = area.intersectionConvexHulls(build_plate_polygon)
|
clipped_area = area.intersectionConvexHulls(build_plate_polygon)
|
||||||
|
|
||||||
if clipped_area.getPoints() is not None and len(
|
polygons_disallowed_areas += _convert_points(clipped_area.getPoints())
|
||||||
clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
|
||||||
for point in clipped_area.getPoints():
|
|
||||||
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
|
||||||
|
|
||||||
disallowed_area = Item(converted_points)
|
polygons_fixed_nodes = []
|
||||||
|
if self._fixed_nodes is None:
|
||||||
|
self._fixed_nodes = []
|
||||||
|
for node in self._fixed_nodes:
|
||||||
|
hull_polygon = node.callDecoration("getConvexHull")
|
||||||
|
|
||||||
|
if hull_polygon is not None:
|
||||||
|
polygons_fixed_nodes += _convert_points(hull_polygon.getPoints())
|
||||||
|
|
||||||
|
strategies = [NfpConfig.Alignment.CENTER,
|
||||||
|
NfpConfig.Alignment.BOTTOM_LEFT,
|
||||||
|
NfpConfig.Alignment.BOTTOM_RIGHT,
|
||||||
|
NfpConfig.Alignment.TOP_LEFT,
|
||||||
|
NfpConfig.Alignment.TOP_RIGHT,
|
||||||
|
NfpConfig.Alignment.DONT_ALIGN]
|
||||||
|
found_solution_for_all = False
|
||||||
|
while not found_solution_for_all and len(strategies) > 0:
|
||||||
|
|
||||||
|
# Add all the items we want to arrange
|
||||||
|
node_items = []
|
||||||
|
for polygon in polygons_nodes_to_arrange:
|
||||||
|
node_items.append(Item(polygon))
|
||||||
|
|
||||||
|
for polygon in polygons_disallowed_areas:
|
||||||
|
disallowed_area = Item(polygon)
|
||||||
disallowed_area.markAsDisallowedAreaInBin(0)
|
disallowed_area.markAsDisallowedAreaInBin(0)
|
||||||
node_items.append(disallowed_area)
|
node_items.append(disallowed_area)
|
||||||
|
|
||||||
for node in self._fixed_nodes:
|
for polygon in polygons_fixed_nodes:
|
||||||
converted_points = []
|
item = Item(polygon)
|
||||||
hull_polygon = node.callDecoration("getConvexHull")
|
|
||||||
|
|
||||||
if hull_polygon is not None and hull_polygon.getPoints() is not None and len(
|
|
||||||
hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None
|
|
||||||
for point in hull_polygon.getPoints():
|
|
||||||
converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor)))
|
|
||||||
item = Item(converted_points)
|
|
||||||
item.markAsFixedInBin(0)
|
item.markAsFixedInBin(0)
|
||||||
node_items.append(item)
|
node_items.append(item)
|
||||||
|
|
||||||
strategies = [NfpConfig.Alignment.CENTER] * 3 + [NfpConfig.Alignment.BOTTOM_LEFT] * 3
|
|
||||||
found_solution_for_all = False
|
|
||||||
while not found_solution_for_all and len(strategies) > 0:
|
|
||||||
config = NfpConfig()
|
config = NfpConfig()
|
||||||
config.accuracy = 1.0
|
config.accuracy = 1.0
|
||||||
config.alignment = NfpConfig.Alignment.CENTER
|
config.alignment = NfpConfig.Alignment.CENTER
|
||||||
|
@ -84,6 +84,7 @@ class MultiplyObjectsJob(Job):
|
|||||||
arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000)
|
arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000)
|
||||||
|
|
||||||
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True)
|
group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True)
|
||||||
|
found_solution_for_all = not_fit_count == 0
|
||||||
|
|
||||||
if nodes_to_add_without_arrange:
|
if nodes_to_add_without_arrange:
|
||||||
for nested_node in nodes_to_add_without_arrange:
|
for nested_node in nodes_to_add_without_arrange:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user