diff --git a/cura/Arrange.py b/cura/Arrange.py index e0bd94b742..e69c5efef4 100755 --- a/cura/Arrange.py +++ b/cura/Arrange.py @@ -2,10 +2,15 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Logger import Logger from cura.ShapeArray import ShapeArray +from collections import namedtuple + import numpy import copy +## Return object for bestSpot +LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points", "priority"]) + ## The Arrange classed is used together with ShapeArray. The class tries to find # good locations for objects that you try to put on a build place. # Different priority schemes can be defined so it alters the behavior while using @@ -54,7 +59,7 @@ class Arrange: for i in range(count): new_node = copy.deepcopy(node) - x, y, penalty_points, start_prio = self.bestSpot( + x, y = self.bestSpot( offset_shape_arr, start_prio = start_prio, step = step) transformation = new_node._transformation if x is not None: # We could find a place @@ -80,6 +85,7 @@ class Arrange: self._priority_unique_values = numpy.unique(self._priority) self._priority_unique_values.sort() + ## def backFirst(self): self._priority = numpy.fromfunction( lambda i, j: 10 * j + abs(self._offset_x - i), self.shape, dtype=numpy.int32) @@ -107,6 +113,7 @@ class Arrange: return numpy.sum(prio_slice[numpy.where(shape_arr.arr == 1)]) ## Find "best" spot for ShapeArray + # Return namedtuple with properties x, y, penalty_points, priority def bestSpot(self, shape_arr, start_prio = 0, step = 1): start_idx_list = numpy.where(self._priority_unique_values == start_prio) if start_idx_list: @@ -124,8 +131,8 @@ class Arrange: # array to "world" coordinates penalty_points = self.checkShape(projected_x, projected_y, shape_arr) if penalty_points != 999999: - return projected_x, projected_y, penalty_points, prio - return None, None, None, prio # No suitable location found :-( + return LocationSuggestion(x = projected_x, y = projected_y, penalty_points = penalty_points, priority = prio) + return LocationSuggestion(x = None, y = None, penalty_points = None, priority = prio) # No suitable location found :-( ## Place the object def place(self, x, y, shape_arr): diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7c10a58f8e..e788b175e4 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1043,8 +1043,10 @@ class CuraApplication(QtApplication): for size, node, offset_shape_arr, hull_shape_arr in nodes_arr: # we assume that when a location does not fit, it will also not fit for the next # object (while what can be untrue). That saves a lot of time. - x, y, penalty_points, start_prio = arranger.bestSpot( + best_spot = arranger.bestSpot( offset_shape_arr, start_prio = start_prio) + x, y = best_spot.x, best_spot.y + start_prio = best_spot.priority if x is not None: # We could find a place arranger.place(x, y, hull_shape_arr) # take place before the next one diff --git a/tests/TestArrange.py b/tests/TestArrange.py new file mode 100755 index 0000000000..84e9ed446f --- /dev/null +++ b/tests/TestArrange.py @@ -0,0 +1,75 @@ +import pytest +import numpy +import time + +from cura.Arrange import Arrange +from cura.ShapeArray import ShapeArray + + +def gimmeShapeArray(): + vertices = numpy.array([[-3, 1], [3, 1], [0, -3]]) + shape_arr = ShapeArray.fromPolygon(vertices) + return shape_arr + + +def test_smoke_arrange(): + ar = Arrange.create(fixed_nodes = []) + + +def test_centerFirst(): + ar = Arrange(300, 300, 150, 150) + ar.centerFirst() + assert ar._priority[150][150] < ar._priority[170][150] + assert ar._priority[150][150] < ar._priority[150][170] + assert ar._priority[150][150] < ar._priority[170][170] + assert ar._priority[150][150] < ar._priority[130][150] + assert ar._priority[150][150] < ar._priority[150][130] + assert ar._priority[150][150] < ar._priority[130][130] + + +def test_backFirst(): + ar = Arrange(300, 300, 150, 150) + ar.backFirst() + assert ar._priority[150][150] < ar._priority[150][170] + assert ar._priority[150][150] < ar._priority[170][170] + assert ar._priority[150][150] > ar._priority[150][130] + assert ar._priority[150][150] > ar._priority[130][130] + + +def test_smoke_bestSpot(): + ar = Arrange(30, 30, 15, 15) + ar.centerFirst() + + shape_arr = gimmeShapeArray() + best_spot = ar.bestSpot(shape_arr) + assert hasattr(best_spot, "x") + assert hasattr(best_spot, "y") + assert hasattr(best_spot, "penalty_points") + assert hasattr(best_spot, "priority") + + +def test_smoke_place(): + ar = Arrange(30, 30, 15, 15) + ar.centerFirst() + + shape_arr = gimmeShapeArray() + + assert not numpy.any(ar._occupied) + ar.place(0, 0, shape_arr) + assert numpy.any(ar._occupied) + + +def test_place_objects(): + ar = Arrange(20, 20, 10, 10) + ar.centerFirst() + shape_arr = gimmeShapeArray() + print(shape_arr) + + now = time.time() + for i in range(5): + best_spot_x, best_spot_y, score, prio = ar.bestSpot(shape_arr) + print(best_spot_x, best_spot_y, score) + ar.place(best_spot_x, best_spot_y, shape_arr) + print(ar._occupied) + + print(time.time() - now)