def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5): arranger = Arrange(220, 220, 110, 110, scale = scale) arranger.centerFirst() if fixed_nodes is None: fixed_nodes = [] for node_ in DepthFirstIterator(scene_root): # Only count sliceable objects if node_.callDecoration("isSliceable"): fixed_nodes.append(node_) # Place all objects fixed nodes for fixed_node in fixed_nodes: vertices = fixed_node.callDecoration("getConvexHull") if not vertices: continue points = copy.deepcopy(vertices._points) shape_arr = ShapeArray.fromPolygon(points, scale = scale) arranger.place(0, 0, shape_arr) # If a build volume was set, add the disallowed areas if Arrange.build_volume: disallowed_areas = Arrange.build_volume.getDisallowedAreas() for area in disallowed_areas: points = copy.deepcopy(area._points) shape_arr = ShapeArray.fromPolygon(points, scale = scale) arranger.place(0, 0, shape_arr) return arranger
def create(cls, scene_root=None, fixed_nodes=None, scale=0.5): arranger = Arrange(220, 220, 110, 110, scale=scale) arranger.centerFirst() if fixed_nodes is None: fixed_nodes = [] for node_ in DepthFirstIterator(scene_root): # Only count sliceable objects if node_.callDecoration("isSliceable"): fixed_nodes.append(node_) # Place all objects fixed nodes for fixed_node in fixed_nodes: vertices = fixed_node.callDecoration("getConvexHull") points = copy.deepcopy(vertices._points) shape_arr = ShapeArray.fromPolygon(points, scale=scale) arranger.place(0, 0, shape_arr) # If a build volume was set, add the disallowed areas if Arrange.build_volume: disallowed_areas = Arrange.build_volume.getDisallowedAreas() for area in disallowed_areas: points = copy.deepcopy(area._points) shape_arr = ShapeArray.fromPolygon(points, scale=scale) arranger.place(0, 0, shape_arr) return arranger
def run(self): status_message = Message(i18n_catalog.i18nc( "@info:status", "Multiplying and placing objects"), lifetime=0, dismissable=False, progress=0) status_message.show() scene = Application.getInstance().getController().getScene() node = scene.findObject(self._object_id) if not node and self._object_id != 0: # Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) # If object is part of a group, multiply group current_node = node while current_node.getParent() and current_node.getParent( ).callDecoration("isGroup"): current_node = current_node.getParent() root = scene.getRoot() arranger = Arrange.create(scene_root=root) node_too_big = False if node.getBoundingBox().width < 300 or node.getBoundingBox( ).depth < 300: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode( current_node, min_offset=self._min_offset) else: node_too_big = True nodes = [] found_solution_for_all = True for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. if not node_too_big: node, solution_found = arranger.findNodePlacement( current_node, offset_shape_arr, hull_shape_arr) if node_too_big or not solution_found: found_solution_for_all = False new_location = node.getPosition() new_location = new_location.set(z=100 - i * 20) node.setPosition(new_location) nodes.append(node) Job.yieldThread() status_message.setProgress((i + 1) / self._count * 100) 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" )) no_full_solution_message.show()
def test_check2(): base_array = numpy.zeros([5, 5], dtype=float) p1 = numpy.array([0, 3]) p2 = numpy.array([4, 3]) check_array = ShapeArray._check(p1, p2, base_array) assert numpy.any(check_array) assert not check_array[3][0] assert check_array[3][4]
def run(self): status_message = Message(i18n_catalog.i18nc("@info:status", "Finding new location for objects"), lifetime = 0, dismissable=False, progress = 0) status_message.show() arranger = Arrange.create(fixed_nodes = self._fixed_nodes) # 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) 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 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). # We also skip possibilities by slicing through the possibilities (step = 10) 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(offset_shape_arr, start_prio=start_priority, step=10) 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, hull_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, - idx * 20), set_position = True)) 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")) no_full_solution_message.show()
def run(self): status_message = Message(i18n_catalog.i18nc("@info:status", "Finding new location for objects"), lifetime = 0, dismissable=False, progress = 0) status_message.show() arranger = Arrange.create(fixed_nodes = self._fixed_nodes) # 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) 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 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). # We also skip possibilities by slicing through the possibilities (step = 10) 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(offset_shape_arr, start_prio=start_priority, step=1) 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, hull_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, - idx * 20), set_position = True)) 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")) no_full_solution_message.show()
def create(cls, scene_root=None, fixed_nodes=None, scale=1.0): global_stack = Application.getInstance().getGlobalContainerStack() machine_width = int(global_stack.getProperty("machine_width", "value")) machine_depth = int(global_stack.getProperty("machine_depth", "value")) arranger = Arrange(machine_depth, machine_width, int(machine_width / 2), int(machine_depth / 2), scale=scale) arranger.centerFirst() if fixed_nodes is None: fixed_nodes = [] for node_ in DepthFirstIterator(scene_root): # Only count sliceable objects if node_.callDecoration("isSliceable") and not isinstance( node_, DuplicatedNode): fixed_nodes.append(node_) # Place all objects fixed nodes for fixed_node in fixed_nodes: arrange_align = Preferences.getInstance().getValue( "mesh/arrange_align") if arrange_align: bb = fixed_node.getBoundingBox() points = numpy.array( [[bb.right, bb.back], [bb.left, bb.back], [bb.left, bb.front], [bb.right, bb.front]], dtype=numpy.float32) else: vertices = fixed_node.callDecoration("getConvexHull") points = copy.deepcopy(vertices._points) shape_arr = ShapeArray.fromPolygon(points, scale=scale) arranger.place(0, 0, shape_arr) # If a build volume was set, add the disallowed areas if Arrange.build_volume: disallowed_areas = Arrange.build_volume.getDisallowedAreas() for area in disallowed_areas: points = copy.deepcopy(area._points) shape_arr = ShapeArray.fromPolygon(points, scale=scale) arranger.place(0, 0, shape_arr) return arranger
def _onPrintModeChanged(self): if self._global_stack: self._restoreSettingsValue() print_mode = self._global_stack.getProperty("print_mode", "value") if print_mode != "regular": nodes = self._scene.getRoot().getChildren() max_offset = 0 machine_head_with_fans_polygon = self._global_stack.getProperty( "machine_head_with_fans_polygon", "value") machine_head_size = abs(machine_head_with_fans_polygon[0][0] - machine_head_with_fans_polygon[2][0]) margin = Application.getInstance().getBuildVolume().margin if print_mode == "mirror": margin += machine_head_size / 2 sliceable_nodes = [] for node in nodes: self._setActiveExtruder(node) if (node.callDecoration("isSliceable") or node.callDecoration("isGroup")) and not isinstance( node, DuplicatedNode): sliceable_nodes.append(node) offset_shape_arr, hull_shape_arr = ShapeArray.fromNode( node, 4) position = node.getPosition() max_offset = max( abs(offset_shape_arr.offset_x) + position.x + margin, max_offset) for node in sliceable_nodes: position = node.getPosition() offset = position.x - max_offset node.setPosition(Vector(offset, position.y, position.z)) if self._old_material == "": self._old_material = ExtruderManager.getInstance( ).getExtruderStack(1).material material = ExtruderManager.getInstance().getExtruderStack( 0).material ExtruderManager.getInstance().getExtruderStack( 1).setMaterial(material) variant = ExtruderManager.getInstance().getExtruderStack( 0).variant ExtruderManager.getInstance().getExtruderStack( 1).setVariant(variant) Preferences.getInstance().setValue( "cura/old_material", self._old_material.getId()) self.renderDuplicatedNodes() else: self.removeDuplicatedNodes() if self._old_material != "": ExtruderManager.getInstance().getExtruderStack( 1).setMaterial(self._old_material) self._old_material = "" Preferences.getInstance().setValue("cura/old_material", "")
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 root = scene.getRoot() arranger = Arrange.create(scene_root=root) nodes = [] 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"): current_node = current_node.getParent() node_too_big = False if node.getBoundingBox().width < 300 or node.getBoundingBox().depth < 300: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) else: node_too_big = True found_solution_for_all = True for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. if not node_too_big: node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) if node_too_big or not solution_found: found_solution_for_all = False new_location = node.getPosition() new_location = new_location.set(z = 100 - i * 20) node.setPosition(new_location) nodes.append(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()
def run(self): status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0, dismissable=False, progress=0) status_message.show() scene = Application.getInstance().getController().getScene() node = scene.findObject(self._object_id) if not node and self._object_id != 0: # Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) # If object is part of a group, multiply group current_node = node while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): current_node = current_node.getParent() root = scene.getRoot() arranger = Arrange.create(scene_root=root) offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset) nodes = [] found_solution_for_all = True for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) if not solution_found: found_solution_for_all = False new_location = node.getPosition() new_location = new_location.set(z = 100 - i * 20) node.setPosition(new_location) nodes.append(node) Job.yieldThread() status_message.setProgress((i + 1) / self._count * 100) 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")) no_full_solution_message.show()
def run(self): status_message = Message(i18n_catalog.i18nc( "@info:status", "Multiplying and placing objects"), lifetime=0, dismissable=False, progress=0) status_message.show() scene = Application.getInstance().getController().getScene() total_progress = len(self._objects) * self._count current_progress = 0 root = scene.getRoot() arranger = Arrange.create(scene_root=root) nodes = [] 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"): current_node = current_node.getParent() node_too_big = False if node.getBoundingBox().width < 300 or node.getBoundingBox( ).depth < 300: offset_shape_arr, hull_shape_arr = ShapeArray.fromNode( current_node, min_offset=self._min_offset) else: node_too_big = True found_solution_for_all = True for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. if not node_too_big: node, solution_found = arranger.findNodePlacement( current_node, offset_shape_arr, hull_shape_arr) if node_too_big or not solution_found: found_solution_for_all = False new_location = node.getPosition() new_location = new_location.set(z=100 - i * 20) node.setPosition(new_location) nodes.append(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: print_mode_enabled = Application.getInstance( ).getGlobalContainerStack().getProperty( "print_mode", "enabled") if print_mode_enabled: node_dup = DuplicatedNode(new_node) op.addOperation( AddNodesOperation(node_dup, current_node.getParent())) else: 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" )) no_full_solution_message.show()
def gimmeShapeArray(): vertices = numpy.array([[-3, 1], [3, 1], [0, -3]]) shape_arr = ShapeArray.fromPolygon(vertices) return shape_arr
def test_arrayFromPolygon2(): vertices = numpy.array([[-3, 1], [3, 1], [2, -3]]) array = ShapeArray.arrayFromPolygon([5, 5], vertices) assert numpy.any(array)