def test_backFirst(): ar = Arrange(300, 300, 150, 150, scale=1) ar.backFirst() assert ar._priority[150][150] < ar._priority[170][150] 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[130][130]
def test_centerFirst_rectangular(): ar = Arrange(400, 300, 200, 150, scale=1) ar.centerFirst() assert ar._priority[150][200] < ar._priority[150][220] assert ar._priority[150][200] < ar._priority[170][200] assert ar._priority[150][200] < ar._priority[170][220] assert ar._priority[150][200] < ar._priority[180][150] assert ar._priority[150][200] < ar._priority[130][200] assert ar._priority[150][200] < ar._priority[130][180]
def test_centerFirst(): ar = Arrange(300, 300, 150, 150, scale=1) 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_ShapeArray_scaling(): scale = 2 ar = Arrange(16, 16, 8, 8, scale=scale) ar.centerFirst() shape_arr = gimmeShapeArray(scale) print(shape_arr.arr) count = len(numpy.where(shape_arr.arr == 1)[0]) print(count) assert count >= 40 # should approach 2*2*12 = 48
def test_smoke_bestSpot(): ar = Arrange(30, 30, 15, 15, scale=1) 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_ShapeArray_scaling2(): scale = 0.5 ar = Arrange(16, 16, 8, 8, scale=scale) ar.centerFirst() shape_arr = gimmeShapeArray(scale) print(shape_arr.arr) count = len(numpy.where(shape_arr.arr == 1)[0]) print(count) assert count >= 1 # should approach 3, but it can be inaccurate due to pixel rounding
def test_bestSpot(): ar = Arrange(16, 16, 8, 8, scale=1) ar.centerFirst() shape_arr = gimmeShapeArray() best_spot = ar.bestSpot(shape_arr) assert best_spot.x == 0 assert best_spot.y == 0 ar.place(best_spot.x, best_spot.y, shape_arr) # Place object a second time best_spot = ar.bestSpot(shape_arr) assert best_spot.x is not None # we found a location assert best_spot.x != 0 or best_spot.y != 0 # it can't be on the same location ar.place(best_spot.x, best_spot.y, shape_arr) print(ar._occupied) # For debugging
def test_checkShape_place(): ar = Arrange(30, 30, 15, 15) ar.centerFirst() shape_arr = gimmeShapeArray() points = ar.checkShape(3, 6, shape_arr) ar.place(3, 6, shape_arr) points2 = ar.checkShape(3, 6, shape_arr) assert points2 is None
def test_smoke_place_objects(): ar = Arrange(20, 20, 10, 10, scale=1) ar.centerFirst() shape_arr = gimmeShapeArray() for i in range(5): best_spot_x, best_spot_y, score, prio = ar.bestSpot(shape_arr) ar.place(best_spot_x, best_spot_y, shape_arr)
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_checkShape(): ar = Arrange(30, 30, 15, 15) ar.centerFirst() shape_arr = gimmeShapeArray() points = ar.checkShape(0, 0, shape_arr) points2 = ar.checkShape(5, 0, shape_arr) points3 = ar.checkShape(0, 5, shape_arr) assert points2 > points assert points3 > points
def test_checkShape_rectangular(): ar = Arrange(20, 30, 10, 15) ar.centerFirst() print(ar._priority) shape_arr = gimmeShapeArray() points = ar.checkShape(0, 0, shape_arr) points2 = ar.checkShape(5, 0, shape_arr) points3 = ar.checkShape(0, 5, shape_arr) assert points2 > points assert points3 > points
def test_centerFirst_rectangular2(): ar = Arrange(10, 20, 5, 10, scale=1) ar.centerFirst() print(ar._priority) assert ar._priority[10][5] < ar._priority[10][7]
def test_bestSpot_rectangular_build_plate(): ar = Arrange(16, 40, 8, 20, scale=1) ar.centerFirst() shape_arr = gimmeShapeArray() best_spot = ar.bestSpot(shape_arr) ar.place(best_spot.x, best_spot.y, shape_arr) assert best_spot.x == 0 assert best_spot.y == 0 # Place object a second time best_spot2 = ar.bestSpot(shape_arr) assert best_spot2.x is not None # we found a location assert best_spot2.x != 0 or best_spot2.y != 0 # it can't be on the same location ar.place(best_spot2.x, best_spot2.y, shape_arr) # Place object a 3rd time best_spot3 = ar.bestSpot(shape_arr) assert best_spot3.x is not None # we found a location assert best_spot3.x != best_spot.x or best_spot3.y != best_spot.y # it can't be on the same location assert best_spot3.x != best_spot2.x or best_spot3.y != best_spot2.y # it can't be on the same location ar.place(best_spot3.x, best_spot3.y, shape_arr) best_spot_x = ar.bestSpot(shape_arr) ar.place(best_spot_x.x, best_spot_x.y, shape_arr) best_spot_x = ar.bestSpot(shape_arr) ar.place(best_spot_x.x, best_spot_x.y, shape_arr) best_spot_x = ar.bestSpot(shape_arr) ar.place(best_spot_x.x, best_spot_x.y, shape_arr) print(ar._occupied) # For debugging
def test_smoke_arrange(): ar = Arrange.create(fixed_nodes=[])
def test_compare_occupied_and_priority_tables(): ar = Arrange(10, 15, 5, 7) ar.centerFirst() assert ar._priority.shape == ar._occupied.shape
def test_bestSpot_scale_rectangular(): scale = 0.5 ar = Arrange(16, 40, 8, 20, scale=scale) ar.centerFirst() shape_arr = gimmeShapeArray(scale) shape_arr_square = gimmeShapeArraySquare(scale) best_spot = ar.bestSpot(shape_arr_square) assert best_spot.x == 0 assert best_spot.y == 0 ar.place(best_spot.x, best_spot.y, shape_arr_square) print(ar._occupied) # Place object a second time best_spot = ar.bestSpot(shape_arr) assert best_spot.x is not None # we found a location assert best_spot.x != 0 or best_spot.y != 0 # it can't be on the same location ar.place(best_spot.x, best_spot.y, shape_arr) best_spot = ar.bestSpot(shape_arr_square) ar.place(best_spot.x, best_spot.y, shape_arr_square) print(ar._occupied) # For debugging
def add(self): new_arrange = Arrange.create(x = self._x, y = self._y, fixed_nodes = self._fixed_nodes) self._arrange.append(new_arrange) self._count += 1 self._update_first_empty()
def run(self): status_message = Message( i18n_catalog.i18nc("@info:status", "Finding new location for objects"), lifetime=0, dismissable=False, progress=0, title=i18n_catalog.i18nc("@info:title", "Finding Location")) status_message.show() global_container_stack = Application.getInstance( ).getGlobalContainerStack() machine_width = global_container_stack.getProperty( "machine_width", "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) # Collect nodes to be placed nodes_arr = [ ] # fill with (size, node, offset_shape_arr, hull_shape_arr) for node in self._nodes: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode( node, min_offset=self._min_offset) 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() found_solution_for_all = True not_fit_count = 0 for idx, (size, node, offset_shape_arr, hull_shape_arr) in enumerate(nodes_arr): # 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( TranslateOperation(node, Vector(x, center_y, y), set_position=True)) 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() grouped_operation.push() status_message.hide() if not found_solution_for_all: no_full_solution_message = Message(i18n_catalog.i18nc( "@info:status", "Unable to find a location within the build volume for all objects" ), title=i18n_catalog.i18nc( "@info:title", "Can't Find Location")) no_full_solution_message.show() self.finished.emit(self)
def run(self): status_message = Message( i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0, dismissable=False, progress=0, title=i18n_catalog.i18nc("@info:title", "Placing Object")) status_message.show() scene = Application.getInstance().getController().getScene() total_progress = len(self._objects) * self._count current_progress = 0 global_container_stack = Application.getInstance( ).getGlobalContainerStack() machine_width = global_container_stack.getProperty( "machine_width", "value") machine_depth = global_container_stack.getProperty( "machine_depth", "value") root = scene.getRoot() scale = 0.5 arranger = Arrange.create(x=machine_width, y=machine_depth, scene_root=root, scale=scale, min_offset=self._min_offset) processed_nodes = [] nodes = [] not_fit_count = 0 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")): 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 < machine_width or node.getBoundingBox( ).depth < machine_depth: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode( current_node, min_offset=self._min_offset, scale=scale) else: node_too_big = True found_solution_for_all = True arranger.resetLastPriority() for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. new_node = copy.deepcopy(node) solution_found = False if not node_too_big: solution_found = arranger.findNodePlacement( new_node, offset_shape_arr, hull_shape_arr) if node_too_big or not solution_found: found_solution_for_all = False new_location = new_node.getPosition() new_location = new_location.set(z=-not_fit_count * 20) new_node.setPosition(new_location) not_fit_count += 1 # 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) current_progress += 1 status_message.setProgress( (current_progress / total_progress) * 100) Job.yieldThread() Job.yieldThread() if nodes: op = GroupedOperation() for new_node in nodes: op.addOperation( AddSceneNodeOperation(new_node, current_node.getParent())) op.push() status_message.hide() if not found_solution_for_all: no_full_solution_message = Message(i18n_catalog.i18nc( "@info:status", "Unable to find a location within the build volume for all objects" ), title=i18n_catalog.i18nc( "@info:title", "Placing Object")) no_full_solution_message.show()