def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) Application.getInstance().getController().getScene().sceneChanged.emit(node)
def test_compute2DConvexHullMeshData(convex_hull_decorator): node = SceneNode() mb = MeshBuilder() mb.addCube(10,10,10) node.setMeshData(mb.build()) convex_hull_decorator._getSettingProperty = MagicMock(return_value = 0) with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(node) assert convex_hull_decorator._compute2DConvexHull() == Polygon([[5.0,-5.0], [-5.0,-5.0], [-5.0,5.0], [5.0,5.0]])
def test_getExtents(): # Create a cube mesh at position 0,0,0 builder = MeshBuilder() builder.addCube(20, 20, 20) mesh_data = builder.build() extents = mesh_data.getExtents() assert extents.width == 20 assert extents.height == 20 assert extents.depth == 20 assert extents.maximum == Vector(10, 10, 10) assert extents.minimum == Vector(-10, -10, -10)
def read(self, file_name): #Here you would typically open the file, read its contents, parse it, etc. #For this example we will just always create a cube and return that. builder = MeshBuilder() #To construct your own mesh, look at the methods provided by MeshBuilder. builder.addCube(10, 10, 10, Vector(0, 0, 0)) #Cube of 10 by 10 by 10. builder.calculateNormals() #Put the mesh inside a scene node. result_node = SceneNode() result_node.setMeshData(builder.build()) result_node.setName(file_name) #Typically the file name that the mesh originated from is a good name for the node. return result_node
def test_compute2DConvexHullMeshData(convex_hull_decorator): node = SceneNode() mb = MeshBuilder() mb.addCube(10, 10, 10) node.setMeshData(mb.build()) convex_hull_decorator._getSettingProperty = MagicMock(return_value=0) with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(node) assert convex_hull_decorator._compute2DConvexHull() == Polygon( [[5.0, -5.0], [-5.0, -5.0], [-5.0, 5.0], [5.0, 5.0]])
def test_getExtentsTransposed(): # Create a cube mesh at position 0,0,0 builder = MeshBuilder() builder.addCube(20, 20, 20) mesh_data = builder.build() transformation_matrix = Matrix() transformation_matrix.setByTranslation(Vector(10, 10, 10)) extents = mesh_data.getExtents(transformation_matrix) assert extents.width == 20 assert extents.height == 20 assert extents.depth == 20 assert extents.maximum == Vector(20, 20, 20) assert extents.minimum == Vector(0, 0, 0)
def test_compute2DConvexHullMeshDataGrouped(convex_hull_decorator): parent_node = SceneNode() parent_node.addDecorator(GroupDecorator()) node = SceneNode() parent_node.addChild(node) mb = MeshBuilder() mb.addCube(10, 10, 10) node.setMeshData(mb.build()) convex_hull_decorator._getSettingProperty = MagicMock(return_value=0) with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(parent_node) with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): copied_decorator = copy.deepcopy(convex_hull_decorator) copied_decorator._getSettingProperty = MagicMock(return_value=0) node.addDecorator(copied_decorator) assert convex_hull_decorator._compute2DConvexHull() == Polygon([[-5.0,5.0], [5.0,5.0], [5.0,-5.0], [-5.0,-5.0]])
def _createEraserMesh(self): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10, 10, 10) node.setMeshData(mesh.build()) # Place the cube in the platform. Do it manually so it works if the "automatic drop models" is OFF move_vector = Vector(0, 5, 0) node.setPosition(move_vector) active_build_plate = Application.getInstance().getMultiBuildPlateModel( ).activeBuildPlate node.addDecorator(SettingOverrideDecorator()) node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration( "getStack" ) #Don't try to get the active extruder since it may be None anyway. if not stack: node.addDecorator(SettingOverrideDecorator()) stack = node.callDecoration("getStack") settings = stack.getTop() if not (settings.getInstance("anti_overhang_mesh") and settings.getProperty("anti_overhang_mesh", "value")): definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) scene = self._controller.getScene() op = AddSceneNodeOperation(node, scene.getRoot()) op.push() Application.getInstance().getController().getScene().sceneChanged.emit( node)
def test_compute2DConvexHullMeshDataGrouped(convex_hull_decorator): parent_node = SceneNode() parent_node.addDecorator(GroupDecorator()) node = SceneNode() parent_node.addChild(node) mb = MeshBuilder() mb.addCube(10, 10, 10) node.setMeshData(mb.build()) convex_hull_decorator._getSettingProperty = MagicMock(return_value=0) with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(parent_node) with patch( "cura.Settings.ExtruderManager.ExtruderManager.getInstance"): copied_decorator = copy.deepcopy(convex_hull_decorator) copied_decorator._getSettingProperty = MagicMock(return_value=0) node.addDecorator(copied_decorator) assert convex_hull_decorator._compute2DConvexHull() == Polygon( [[-5.0, 5.0], [5.0, 5.0], [5.0, -5.0], [-5.0, -5.0]])
def _onGlobalContainerStackChanged(self): if self._global_container_stack: self.setMeshData(None) self._global_container_stack = Application.getInstance().getGlobalContainerStack() if self._global_container_stack: container = self._global_container_stack.findContainer({ "platform": "*" }) if container: mesh_file = container.getMetaDataEntry("platform") try: path = Resources.getPath(Resources.Meshes, mesh_file) except FileNotFoundError: Logger.log("w", "Unable to find the platform mesh %s", mesh_file) path = "" if self._load_platform_job: # This prevents a previous load job from triggering texture loads. self._load_platform_job.finished.disconnect(self._onPlatformLoaded) # Perform platform mesh loading in the background self._load_platform_job = _LoadPlatformJob(path) self._load_platform_job.finished.connect(self._onPlatformLoaded) self._load_platform_job.start() self._has_bed = True offset = container.getMetaDataEntry("platform_offset") if offset: if len(offset) == 3: self.setPosition(Vector(offset[0], offset[1], offset[2])) else: Logger.log("w", "Platform offset is invalid: %s", str(offset)) self.setPosition(Vector(0.0, 0.0, 0.0)) else: self.setPosition(Vector(0.0, 0.0, 0.0)) else: settings = Application.getInstance().getGlobalContainerStack() machine_width = settings.getProperty("machine_width", "value") machine_depth = settings.getProperty("machine_depth", "value") line_len = 25 line_wid = 1 handle_size = 3 mb = MeshBuilder() mb.addCube(line_wid, line_len, line_wid, Vector(-machine_width/2, line_len/2, machine_depth/2), ToolHandle.YAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(-machine_width/2, line_len, machine_depth/2), color=ToolHandle.YAxisSelectionColor) mb.addCube(line_len, line_wid, line_wid, Vector(line_len/2-machine_width/2, 0, machine_depth/2), ToolHandle.XAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(line_len-machine_width/2, 0, machine_depth/2), color=ToolHandle.XAxisSelectionColor, axis = Vector.Unit_Z, angle = 90) mb.addCube(line_wid, line_wid, line_len, Vector(-machine_width/2, 0, -line_len/2+machine_depth/2), ToolHandle.ZAxisSelectionColor) mb.addPyramid(handle_size, handle_size, handle_size, center=Vector(-machine_width/2, 0, -line_len+machine_depth/2), color=ToolHandle.ZAxisSelectionColor, axis = Vector.Unit_X, angle = 90) self.setMeshData(mb.build()) self.setPosition(Vector(0.0, 0.0, 0.0)) self._has_bed = False
def _getAxisMesh(self, node): mb = MeshBuilder() mb.addCube(width=self.axis_width, height=self.axis_height, depth=self.axis_width, color=self.YAxisColor, center=Vector(0, self.axis_height / 2, 0)) mb.addCube(width=self.axis_width, height=self.axis_width, depth=self.axis_height, color=self.ZAxisColor, center=Vector(0, 0, self.axis_height / 2)) mb.addCube(width=self.axis_height, height=self.axis_width, depth=self.axis_width, color=self.XAxisColor, center=Vector(self.axis_height / 2, 0, 0)) return mb.build().getTransformed(node.getWorldTransformation())
def buildMesh(self): mb = MeshBuilder() #SOLIDMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube( width = self._line_width, height = self._line_length, depth = self._line_width, center = Vector(0, self._handle_position/2, 0), color = self._y_axis_color ) if self.XAxis in self._enabled_axis: mb.addCube( width = self._line_length, height = self._line_width, depth = self._line_width, center = Vector(self._handle_position/2, 0, 0), color = self._x_axis_color ) if self.ZAxis in self._enabled_axis: mb.addCube( width = self._line_width, height = self._line_width, depth = self._line_length, center = Vector(0, 0, self._handle_position/2), color = self._z_axis_color ) #SOLIDMESH -> HANDLES if self.YAxis in self._enabled_axis: mb.addPyramid( width = self._handle_width, height = self._handle_height, depth = self._handle_width, center = Vector(0, self._handle_position, 0), color = self._y_axis_color ) if self.XAxis in self._enabled_axis: mb.addPyramid( width = self._handle_width, height = self._handle_height, depth = self._handle_width, center = Vector(self._handle_position, 0, 0), color = self._x_axis_color, axis = Vector.Unit_Z, angle = 90 ) if self.ZAxis in self._enabled_axis: mb.addPyramid( width = self._handle_width, height = self._handle_height, depth = self._handle_width, center = Vector(0, 0, self._handle_position), color = self._z_axis_color, axis = Vector.Unit_X, angle = -90 ) self.setSolidMesh(mb.build()) mb = MeshBuilder() #SELECTIONMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube( width = self._active_line_width, height = self._active_line_length, depth = self._active_line_width, center = Vector(0, self._active_handle_position/2, 0), color = self._y_axis_color ) if self.XAxis in self._enabled_axis: mb.addCube( width = self._active_line_length, height = self._active_line_width, depth = self._active_line_width, center = Vector(self._active_handle_position/2, 0, 0), color = self._x_axis_color ) if self.ZAxis in self._enabled_axis: mb.addCube( width = self._active_line_width, height = self._active_line_width, depth = self._active_line_length, center = Vector(0, 0, self._active_handle_position/2), color = self._z_axis_color ) #SELECTIONMESH -> HANDLES mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, 0), color = ToolHandle.AllAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, self._active_handle_position, 0), color = ToolHandle.YAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(self._active_handle_position, 0, 0), color = ToolHandle.XAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, self._active_handle_position), color = ToolHandle.ZAxisSelectionColor ) self.setSelectionMesh(mb.build())
def rebuild(self): if not self._width or not self._height or not self._depth: return min_w = -self._width / 2 max_w = self._width / 2 min_h = 0.0 max_h = self._height min_d = -self._depth / 2 max_d = self._depth / 2 mb = MeshBuilder() # Outline 'cube' of the build volume mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color=self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color=self.VolumeOutlineColor) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color=self.VolumeOutlineColor) self.setMeshData(mb.build()) mb = MeshBuilder() # Indication of the machine origin if self._global_container_stack.getProperty("machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb.addCube(width=self._origin_line_length, height=self._origin_line_width, depth=self._origin_line_width, center=origin + Vector(self._origin_line_length / 2, 0, 0), color=self.XAxisColor) mb.addCube(width=self._origin_line_width, height=self._origin_line_length, depth=self._origin_line_width, center=origin + Vector(0, self._origin_line_length / 2, 0), color=self.YAxisColor) mb.addCube(width=self._origin_line_width, height=self._origin_line_width, depth=self._origin_line_length, center=origin - Vector(0, 0, self._origin_line_length / 2), color=self.ZAxisColor) self._origin_mesh = mb.build() mb = MeshBuilder() mb.addQuad(Vector(min_w, min_h - 0.2, min_d), Vector(max_w, min_h - 0.2, min_d), Vector(max_w, min_h - 0.2, max_d), Vector(min_w, min_h - 0.2, max_d)) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: mb = MeshBuilder() color = Color(0.0, 0.0, 0.0, 0.15) for polygon in self._disallowed_areas: points = polygon.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min( points[:, 1] ) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs( numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._disallowed_area_mesh = mb.build() else: self._disallowed_area_mesh = None if self._error_areas: mb = MeshBuilder() for error_area in self._error_areas: color = Color(1.0, 0.0, 0.0, 0.5) points = error_area.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._error_mesh = mb.build() else: self._error_mesh = None self._volume_aabb = AxisAlignedBox( minimum=Vector(min_w, min_h - 1.0, min_d), maximum=Vector(max_w, max_h - self._raft_thickness, max_d)) bed_adhesion_size = self._getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum=Vector( min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum=Vector( max_w - bed_adhesion_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + bed_adhesion_size - 1)) Application.getInstance().getController().getScene( )._maximum_bounds = scale_to_max_bounds
def buildMesh(self): #SOLIDMESH -> LINES mb = MeshBuilder() mb.addCube(width=self._line_width, height=self._line_length, depth=self._line_width, center=Vector(0, self._handle_position / 2, 0), color=self._y_axis_color) mb.addCube(width=self._line_length, height=self._line_width, depth=self._line_width, center=Vector(self._handle_position / 2, 0, 0), color=self._x_axis_color) mb.addCube(width=self._line_width, height=self._line_width, depth=self._line_length, center=Vector(0, 0, self._handle_position / 2), color=self._z_axis_color) #SOLIDMESH -> HANDLES mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, 0, 0), color=self._all_axis_color) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, self._handle_position, 0), color=self._y_axis_color) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(self._handle_position, 0, 0), color=self._x_axis_color) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, 0, self._handle_position), color=self._z_axis_color) self.setSolidMesh(mb.build()) #SELECTIONMESH -> LINES mb = MeshBuilder() mb.addCube(width=self._active_line_width, height=self._active_line_length, depth=self._active_line_width, center=Vector(0, self._active_handle_position / 2, 0), color=ToolHandle.YAxisSelectionColor) mb.addCube(width=self._active_line_length, height=self._active_line_width, depth=self._active_line_width, center=Vector(self._active_handle_position / 2, 0, 0), color=ToolHandle.XAxisSelectionColor) mb.addCube(width=self._active_line_width, height=self._active_line_width, depth=self._active_line_length, center=Vector(0, 0, self._active_handle_position / 2), color=ToolHandle.ZAxisSelectionColor) #SELECTIONMESH -> HANDLES mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, 0), color=ToolHandle.AllAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, self._active_handle_position, 0), color=ToolHandle.YAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(self._active_handle_position, 0, 0), color=ToolHandle.XAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, self._active_handle_position), color=ToolHandle.ZAxisSelectionColor) self.setSelectionMesh(mb.build())
def rebuild(self): if not self._width or not self._height or not self._depth: return min_w = -self._width / 2 max_w = self._width / 2 min_h = 0.0 max_h = self._height min_d = -self._depth / 2 max_d = self._depth / 2 z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting if self._shape != "elliptic": # Outline 'cube' of the build volume mb = MeshBuilder() mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) self.setMeshData(mb.build()) # Build plate grid mesh mb = MeshBuilder() mb.addQuad( Vector(min_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, max_d), Vector(min_w, min_h - z_fight_distance, max_d) ) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() else: # Bottom and top 'ellipse' of the build volume aspect = 1.0 scale_matrix = Matrix() if self._width != 0: # Scale circular meshes by aspect ratio if width != height aspect = self._height / self._width scale_matrix.compose(scale = Vector(1, 1, aspect)) mb = MeshBuilder() mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self.VolumeOutlineColor) mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0), color = self.VolumeOutlineColor) self.setMeshData(mb.build().getTransformed(scale_matrix)) # Build plate grid mesh mb = MeshBuilder() mb.addVertex(0, min_h - z_fight_distance, 0) mb.addArc(max_w, Vector.Unit_Y, center = Vector(0, min_h - z_fight_distance, 0)) sections = mb.getVertexCount() - 1 # Center point is not an arc section indices = [] for n in range(0, sections - 1): indices.append([0, n + 2, n + 1]) mb.addIndices(numpy.asarray(indices, dtype = numpy.int32)) mb.calculateNormals() for n in range(0, mb.getVertexCount()): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2] * aspect) self._grid_mesh = mb.build().getTransformed(scale_matrix) # Indication of the machine origin if self._global_container_stack.getProperty("machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb = MeshBuilder() mb.addCube( width = self._origin_line_length, height = self._origin_line_width, depth = self._origin_line_width, center = origin + Vector(self._origin_line_length / 2, 0, 0), color = self.XAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_length, depth = self._origin_line_width, center = origin + Vector(0, self._origin_line_length / 2, 0), color = self.YAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_width, depth = self._origin_line_length, center = origin - Vector(0, 0, self._origin_line_length / 2), color = self.ZAxisColor ) self._origin_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: mb = MeshBuilder() color = Color(0.0, 0.0, 0.0, 0.15) for polygon in self._disallowed_areas: points = polygon.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color = color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min(points[:, 1]) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._disallowed_area_mesh = mb.build() else: self._disallowed_area_mesh = None if self._error_areas: mb = MeshBuilder() for error_area in self._error_areas: color = Color(1.0, 0.0, 0.0, 0.5) points = error_area.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._error_mesh = mb.build() else: self._error_mesh = None self._volume_aabb = AxisAlignedBox( minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h - self._raft_thickness, max_d)) bed_adhesion_size = self._getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum = Vector(min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + bed_adhesion_size - 1) ) Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
def __init__(self, parent = None): super().__init__(parent) self._line_width = 0.5 self._line_length= 40 self._handle_position = 40 self._handle_width = 4 self._active_line_width = 0.8 self._active_line_length = 40 self._active_handle_position = 40 self._active_handle_width = 15 #SOLIDMESH -> LINES mb = MeshBuilder() mb.addCube( width = self._line_width, height = self._line_length, depth = self._line_width, center = Vector(0, self._handle_position/2, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = self._line_length, height = self._line_width, depth = self._line_width, center = Vector(self._handle_position/2, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = self._line_width, height = self._line_width, depth = self._line_length, center = Vector(0, 0, self._handle_position/2), color = ToolHandle.ZAxisColor ) #SOLIDMESH -> HANDLES mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, 0, 0), color = ToolHandle.AllAxisColor ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, self._handle_position, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(self._handle_position, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, 0, self._handle_position), color = ToolHandle.ZAxisColor ) self.setSolidMesh(mb.build()) #SELECTIONMESH -> LINES mb = MeshBuilder() mb.addCube( width = self._active_line_width, height = self._active_line_length, depth = self._active_line_width, center = Vector(0, self._active_handle_position/2, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = self._active_line_length, height = self._active_line_width, depth = self._active_line_width, center = Vector(self._active_handle_position/2, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = self._active_line_width, height = self._active_line_width, depth = self._active_line_length, center = Vector(0, 0, self._active_handle_position/2), color = ToolHandle.ZAxisColor ) #SELECTIONMESH -> HANDLES mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, 0), color = ToolHandle.AllAxisColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, self._active_handle_position, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(self._active_handle_position, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, self._active_handle_position), color = ToolHandle.ZAxisColor ) self.setSelectionMesh(mb.build())
def run(self): if self._build_plate_number is None: self.setResult(StartJobResult.Error) return stack = Application.getInstance().getGlobalContainerStack() if not stack: self.setResult(StartJobResult.Error) return # Don't slice if there is a setting with an error value. if Application.getInstance().getMachineManager().stacksHaveErrors: self.setResult(StartJobResult.SettingError) return if Application.getInstance().getBuildVolume().hasErrors(): self.setResult(StartJobResult.BuildPlateError) return # Don't slice if the buildplate or the nozzle type is incompatible with the materials if not Application.getInstance().getMachineManager().variantBuildplateCompatible and \ not Application.getInstance().getMachineManager().variantBuildplateUsable: self.setResult(StartJobResult.MaterialIncompatible) return for position, extruder_stack in stack.extruders.items(): material = extruder_stack.findContainer({"type": "material"}) if not extruder_stack.isEnabled: continue if material: if material.getMetaDataEntry("compatible") == False: self.setResult(StartJobResult.MaterialIncompatible) return # Don't slice if there is a per object setting with an error value. for node in DepthFirstIterator(self._scene.getRoot()): if not isinstance(node, CuraSceneNode) or not node.isSelectable(): continue if self._checkStackForErrors(node.callDecoration("getStack")): self.setResult(StartJobResult.ObjectSettingError) return with self._scene.getSceneLock(): # Remove old layer data. for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("getLayerData") and node.callDecoration( "getBuildPlateNumber") == self._build_plate_number: node.getParent().removeChild(node) break # Get the objects in their groups to print. object_groups = [] if stack.getProperty("print_sequence", "value") == "one_at_a_time": for node in OneAtATimeIterator(self._scene.getRoot()): temp_list = [] # Node can't be printed, so don't bother sending it. if getattr(node, "_outside_buildarea", False): continue # Filter on current build plate build_plate_number = node.callDecoration( "getBuildPlateNumber") if build_plate_number is not None and build_plate_number != self._build_plate_number: continue children = node.getAllChildren() children.append(node) for child_node in children: if child_node.getMeshData() and child_node.getMeshData( ).getVertices() is not None: temp_list.append(child_node) if temp_list: object_groups.append(temp_list) Job.yieldThread() if len(object_groups) == 0: Logger.log( "w", "No objects suitable for one at a time found, or no correct order found" ) else: temp_list = [] has_printing_mesh = False # print convex hull nodes as "faux-raft" print_convex_hulls = stack.getProperty("blackbelt_raft", "value") for node in DepthFirstIterator(self._scene.getRoot()): slice_node = (print_convex_hulls and type(node) is ConvexHullNode ) or node.callDecoration("isSliceable") if slice_node and node.getMeshData() and node.getMeshData( ).getVertices() is not None: per_object_stack = node.callDecoration("getStack") is_non_printing_mesh = False if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) # Find a reason not to add the node if node.callDecoration( "getBuildPlateNumber" ) != self._build_plate_number and type( node) is not ConvexHullNode: # NB: ConvexHullNodes get none of the usual decorators, so skip checking for them continue if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue temp_list.append(node) if not is_non_printing_mesh: has_printing_mesh = True Job.yieldThread() #If the list doesn't have any model with suitable settings then clean the list # otherwise CuraEngine will crash if not has_printing_mesh: temp_list.clear() if temp_list: object_groups.append(temp_list) extruders_enabled = { position: stack.isEnabled for position, stack in Application.getInstance(). getGlobalContainerStack().extruders.items() } filtered_object_groups = [] for group in object_groups: stack = Application.getInstance().getGlobalContainerStack() skip_group = False for node in group: # ConvexHullNodes get none of the usual decorators. If it made it here, it is meant to be printed if type( node ) is not ConvexHullNode and not extruders_enabled[ node.callDecoration("getActiveExtruderPosition")]: skip_group = True break if not skip_group: filtered_object_groups.append(group) # There are cases when there is nothing to slice. This can happen due to one at a time slicing not being # able to find a possible sequence or because there are no objects on the build plate (or they are outside # the build volume) if not filtered_object_groups: self.setResult(StartJobResult.NothingToSlice) return container_registry = ContainerRegistry.getInstance() stack_id = stack.getId() # Adapt layer_height and material_flow for a slanted gantry gantry_angle = self._scene.getRoot().callDecoration( "getGantryAngle") if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _stack = CuraContainerStack(stack_id + "_temp") index = 0 for container in stack.getContainers(): if container_registry.isReadOnly(container.getId()): _stack.replaceContainer(index, container) else: _stack.replaceContainer(index, copy.deepcopy(container)) index = index + 1 stack = _stack # Make sure CuraEngine does not create any supports # support_enable is set in the frontend so support options are settable, # but CuraEngine support structures don't work for slanted gantry stack.setProperty("support_enable", "value", False) # Make sure CuraEngine does not create a raft (we create one manually) # Adhsion type is used in the frontend to show the raft in the viewport stack.setProperty("adhesion_type", "value", "none") for key in ["layer_height", "layer_height_0"]: current_value = stack.getProperty(key, "value") stack.setProperty(key, "value", current_value / math.sin(gantry_angle)) self._buildGlobalSettingsMessage(stack) self._buildGlobalInheritsStackMessage(stack) # Build messages for extruder stacks for position, extruder_stack in Application.getInstance( ).getGlobalContainerStack().extruders.items(): if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _extruder_stack = CuraContainerStack( extruder_stack.getId() + "_temp") index = 0 for container in extruder_stack.getContainers(): if container_registry.isReadOnly(container.getId()): _extruder_stack.replaceContainer(index, container) else: _extruder_stack.replaceContainer( index, copy.deepcopy(container)) index = index + 1 extruder_stack = _extruder_stack extruder_stack.setNextStack(stack) for key in [ "material_flow", "prime_tower_flow", "spaghetti_flow" ]: if extruder_stack.hasProperty(key, "value"): current_value = extruder_stack.getProperty( key, "value") extruder_stack.setProperty( key, "value", current_value * math.sin(gantry_angle)) self._buildExtruderMessage(extruder_stack) bottom_cutting_meshes = [] raft_meshes = [] if gantry_angle: # not 0 or None # Add a modifier mesh to all printable meshes touching the belt for group in filtered_object_groups: added_meshes = [] for object in group: is_non_printing_mesh = False per_object_stack = object.callDecoration("getStack") if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) # ConvexHullNodes get none of the usual decorators. If it made it here, it is meant to be printed if type(object) is ConvexHullNode: raft_thickness = stack.getProperty( "blackbelt_raft_thickness", "value") raft_margin = stack.getProperty( "blackbelt_raft_margin", "value") mb = MeshBuilder() hull_polygon = object.getHull() if raft_margin > 0: hull_polygon = hull_polygon.getMinkowskiHull( Polygon.approximatedCircle(raft_margin)) mb.addConvexPolygonExtrusion( hull_polygon.getPoints()[::-1], 0, raft_thickness) new_node = self._addMesh(mb, "raftMesh") added_meshes.append(new_node) raft_meshes.append(new_node.getName()) elif not is_non_printing_mesh: extruder_stack_index = object.callDecoration( "getActiveExtruderPosition") if not extruder_stack_index: extruder_stack_index = 0 extruder_stack = ExtruderManager.getInstance( ).getMachineExtruders(Application.getInstance( ).getGlobalContainerStack().getId())[int( extruder_stack_index)] aabb = object.getBoundingBox() if aabb.bottom < 0: # mesh extends below the belt; add a cutting mesh to cut off the part below the bottom height = -aabb.bottom center = Vector(aabb.center.x, -height / 2, aabb.center.z) mb = MeshBuilder() mb.addCube(width=aabb.width, height=height, depth=aabb.depth, center=center) new_node = self._addMesh( mb, "bottomCuttingMesh") added_meshes.append(new_node) bottom_cutting_meshes.append( new_node.getName()) if added_meshes: group += added_meshes transform_matrix = self._scene.getRoot().callDecoration( "getTransformMatrix") front_offset = None raft_offset = 0 raft_speed = None raft_flow = 1.0 if stack.getProperty("blackbelt_raft", "value"): raft_offset = stack.getProperty( "blackbelt_raft_thickness", "value") + stack.getProperty( "blackbelt_raft_gap", "value") raft_speed = stack.getProperty("blackbelt_raft_speed", "value") raft_flow = stack.getProperty("blackbelt_raft_flow", "value") * math.sin(gantry_angle) for group in filtered_object_groups: group_message = self._slice_message.addRepeatedMessage( "object_lists") if group[0].getParent() is not None and group[0].getParent( ).callDecoration("isGroup"): self._handlePerObjectSettings(group[0].getParent(), group_message) for object in group: if type(object) is ConvexHullNode: continue mesh_data = object.getMeshData() rot_scale = object.getWorldTransformation().getTransposed( ).getData()[0:3, 0:3] translate = object.getWorldTransformation().getData()[:3, 3] # offset all non-raft objects if rafts are enabled # air gap is applied here to vertically offset objects from the raft if object.getName() not in raft_meshes: translate[1] = translate[1] + raft_offset # This effectively performs a limited form of MeshData.getTransformed that ignores normals. verts = mesh_data.getVertices() verts = verts.dot(rot_scale) verts += translate if transform_matrix: verts = transformVertices(verts, transform_matrix) is_non_printing_mesh = object.getName( ) in bottom_cutting_meshes or object.getName( ) in raft_meshes if not is_non_printing_mesh: per_object_stack = object.callDecoration( "getStack") if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) if not is_non_printing_mesh: _front_offset = verts[:, 1].min() if front_offset is None or _front_offset < front_offset: front_offset = _front_offset # Convert from Y up axes to Z up axes. Equals a 90 degree rotation. verts[:, [1, 2]] = verts[:, [2, 1]] verts[:, 1] *= -1 obj = group_message.addRepeatedMessage("objects") obj.id = id(object) indices = mesh_data.getIndices() if indices is not None: flat_verts = numpy.take(verts, indices.flatten(), axis=0) else: flat_verts = numpy.array(verts) obj.vertices = flat_verts if object.getName() in raft_meshes: self._addSettingsMessage( obj, { "wall_line_count": 99999999, "speed_wall_0": raft_speed, "speed_wall_x": raft_speed, "material_flow": raft_flow }) elif object.getName() in bottom_cutting_meshes: self._addSettingsMessage( obj, { "cutting_mesh": True, "wall_line_count": 0, "top_layers": 0, "bottom_layers": 0, "infill_line_distance": 0 }) else: self._handlePerObjectSettings(object, obj) Job.yieldThread() # Store the front-most coordinate of the scene so the scene can be moved back into place post slicing # TODO: this should be handled per mesh-group instead of per scene # One-at-a-time printing should be disabled for slanted gantry printers for now self._scene.getRoot().callDecoration("setSceneFrontOffset", front_offset) self.setResult(StartJobResult.Finished)
def __init__(self, parent=None): super().__init__(parent) self._line_width = 0.5 self._line_length = 40 self._handle_position = 40 self._handle_width = 4 self._active_line_width = 0.8 self._active_line_length = 40 self._active_handle_position = 40 self._active_handle_width = 15 #SOLIDMESH -> LINES mb = MeshBuilder() mb.addCube(width=self._line_width, height=self._line_length, depth=self._line_width, center=Vector(0, self._handle_position / 2, 0), color=ToolHandle.YAxisColor) mb.addCube(width=self._line_length, height=self._line_width, depth=self._line_width, center=Vector(self._handle_position / 2, 0, 0), color=ToolHandle.XAxisColor) mb.addCube(width=self._line_width, height=self._line_width, depth=self._line_length, center=Vector(0, 0, self._handle_position / 2), color=ToolHandle.ZAxisColor) #SOLIDMESH -> HANDLES mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, 0, 0), color=ToolHandle.AllAxisColor) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, self._handle_position, 0), color=ToolHandle.YAxisColor) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(self._handle_position, 0, 0), color=ToolHandle.XAxisColor) mb.addCube(width=self._handle_width, height=self._handle_width, depth=self._handle_width, center=Vector(0, 0, self._handle_position), color=ToolHandle.ZAxisColor) self.setSolidMesh(mb.getData()) #SELECTIONMESH -> LINES mb = MeshBuilder() mb.addCube(width=self._active_line_width, height=self._active_line_length, depth=self._active_line_width, center=Vector(0, self._active_handle_position / 2, 0), color=ToolHandle.YAxisColor) mb.addCube(width=self._active_line_length, height=self._active_line_width, depth=self._active_line_width, center=Vector(self._active_handle_position / 2, 0, 0), color=ToolHandle.XAxisColor) mb.addCube(width=self._active_line_width, height=self._active_line_width, depth=self._active_line_length, center=Vector(0, 0, self._active_handle_position / 2), color=ToolHandle.ZAxisColor) #SELECTIONMESH -> HANDLES mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, 0), color=ToolHandle.AllAxisColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, self._active_handle_position, 0), color=ToolHandle.YAxisColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(self._active_handle_position, 0, 0), color=ToolHandle.XAxisColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, self._active_handle_position), color=ToolHandle.ZAxisColor) self.setSelectionMesh(mb.getData())
def __init__(self, parent = None): super().__init__(parent) lines = MeshData() lines.addVertex(0, 0, 0) lines.addVertex(0, 20, 0) lines.addVertex(0, 0, 0) lines.addVertex(20, 0, 0) lines.addVertex(0, 0, 0) lines.addVertex(0, 0, 20) lines.setVertexColor(0, ToolHandle.YAxisColor) lines.setVertexColor(1, ToolHandle.YAxisColor) lines.setVertexColor(2, ToolHandle.XAxisColor) lines.setVertexColor(3, ToolHandle.XAxisColor) lines.setVertexColor(4, ToolHandle.ZAxisColor) lines.setVertexColor(5, ToolHandle.ZAxisColor) self.setLineMesh(lines) mb = MeshBuilder() mb.addCube( width = 2, height = 2, depth = 2, center = Vector(0, 0, 0), color = ToolHandle.AllAxisColor ) mb.addCube( width = 2, height = 2, depth = 2, center = Vector(0, 20, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = 2, height = 2, depth = 2, center = Vector(20, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = 2, height = 2, depth = 2, center = Vector(0, 0, 20), color = ToolHandle.ZAxisColor ) self.setSolidMesh(mb.getData()) mb = MeshBuilder() mb.addCube( width = 4, height = 20, depth = 4, center = Vector(0, 10, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = 4, height = 4, depth = 4, center = Vector(0, 20, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = 20, height = 4, depth = 4, center = Vector(10, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = 4, height = 4, depth = 4, center = Vector(20, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = 4, height = 4, depth = 20, center = Vector(0, 0, 10), color = ToolHandle.ZAxisColor ) mb.addCube( width = 4, height = 4, depth = 4, center = Vector(0, 0, 20), color = ToolHandle.ZAxisColor ) mb.addCube( width = 8, height = 8, depth = 8, center = Vector(0, 0, 0), color = ToolHandle.AllAxisColor ) self.setSelectionMesh(mb.getData())
def _rebuild(self): mb = MeshBuilder() #SOLIDMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube(width=self._lineWidth, height=self._lineLength, depth=self._lineWidth, center=Vector(0, self._handlePosition / 2, 0), color=ToolHandle.YAxisColor) if self.XAxis in self._enabled_axis: mb.addCube(width=self._lineLength, height=self._lineWidth, depth=self._lineWidth, center=Vector(self._handlePosition / 2, 0, 0), color=ToolHandle.XAxisColor) if self.ZAxis in self._enabled_axis: mb.addCube(width=self._lineWidth, height=self._lineWidth, depth=self._lineLength, center=Vector(0, 0, self._handlePosition / 2), color=ToolHandle.ZAxisColor) #SOLIDMESH -> HANDLES if self.YAxis in self._enabled_axis: mb.addPyramid(width=self._handleWidth, height=self._handleHeight, depth=self._handleWidth, center=Vector(0, self._handlePosition, 0), color=ToolHandle.YAxisColor) if self.XAxis in self._enabled_axis: mb.addPyramid(width=self._handleWidth, height=self._handleHeight, depth=self._handleWidth, center=Vector(self._handlePosition, 0, 0), color=ToolHandle.XAxisColor, axis=Vector.Unit_Z, angle=90) if self.ZAxis in self._enabled_axis: mb.addPyramid(width=self._handleWidth, height=self._handleHeight, depth=self._handleWidth, center=Vector(0, 0, self._handlePosition), color=ToolHandle.ZAxisColor, axis=Vector.Unit_X, angle=-90) self.setSolidMesh(mb.getData()) mb = MeshBuilder() #ACTIVEMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube(width=self._activeLineWidth, height=self._activeLineLength, depth=self._activeLineWidth, center=Vector(0, self._activeHandlePosition / 2, 0), color=ToolHandle.YAxisColor) if self.XAxis in self._enabled_axis: mb.addCube(width=self._activeLineLength, height=self._activeLineWidth, depth=self._activeLineWidth, center=Vector(self._activeHandlePosition / 2, 0, 0), color=ToolHandle.XAxisColor) if self.ZAxis in self._enabled_axis: mb.addCube(width=self._activeLineWidth, height=self._activeLineWidth, depth=self._activeLineLength, center=Vector(0, 0, self._activeHandlePosition / 2), color=ToolHandle.ZAxisColor) #SELECTIONMESH -> HANDLES mb.addCube(width=self._activeHandleWidth, height=self._activeHandleWidth, depth=self._activeHandleWidth, center=Vector(0, 0, 0), color=ToolHandle.AllAxisColor) mb.addCube(width=self._activeHandleWidth, height=self._activeHandleWidth, depth=self._activeHandleWidth, center=Vector(0, self._activeHandlePosition, 0), color=ToolHandle.YAxisColor) mb.addCube(width=self._activeHandleWidth, height=self._activeHandleWidth, depth=self._activeHandleWidth, center=Vector(self._activeHandlePosition, 0, 0), color=ToolHandle.XAxisColor) mb.addCube(width=self._activeHandleWidth, height=self._activeHandleWidth, depth=self._activeHandleWidth, center=Vector(0, 0, self._activeHandlePosition), color=ToolHandle.ZAxisColor) self.setSelectionMesh(mb.getData())
def _rebuild(self): if not self._build_volume._width or not self._build_volume._height or not self._build_volume._depth: return if not self._build_volume._engine_ready: return if not self._build_volume._volume_outline_color: theme = Application.getInstance().getTheme() self._build_volume._volume_outline_color = Color( *theme.getColor("volume_outline").getRgb()) self._build_volume._x_axis_color = Color( *theme.getColor("x_axis").getRgb()) self._build_volume._y_axis_color = Color( *theme.getColor("y_axis").getRgb()) self._build_volume._z_axis_color = Color( *theme.getColor("z_axis").getRgb()) self._build_volume._disallowed_area_color = Color( *theme.getColor("disallowed_area").getRgb()) self._build_volume._error_area_color = Color( *theme.getColor("error_area").getRgb()) ### START PATCH # Get a dict from the machine metadata optionally overriding the build volume # Note that CuraEngine is blissfully unaware of this; it is just what the user is shown in Cura limit_buildvolume = self._build_volume._global_container_stack.getMetaDataEntry( "limit_buildvolume", {}) if not isinstance(limit_buildvolume, dict): limit_buildvolume = {} min_w = limit_buildvolume.get("width", {}).get("minimum", -self._build_volume._width / 2) max_w = limit_buildvolume.get("width", {}).get("maximum", self._build_volume._width / 2) min_h = limit_buildvolume.get("height", {}).get("minimum", 0.0) max_h = limit_buildvolume.get("height", {}).get("maximum", self._build_volume._height) min_d = limit_buildvolume.get("depth", {}).get("minimum", -self._build_volume._depth / 2) max_d = limit_buildvolume.get("depth", {}).get("maximum", self._build_volume._depth / 2) ### END PATCH z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting if self._build_volume._shape != "elliptic": # Outline 'cube' of the build volume mb = MeshBuilder() mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color=self._build_volume._volume_outline_color) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color=self._build_volume._volume_outline_color) self._build_volume.setMeshData(mb.build()) # Build plate grid mesh mb = MeshBuilder() mb.addQuad(Vector(min_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, min_d), Vector(max_w, min_h - z_fight_distance, max_d), Vector(min_w, min_h - z_fight_distance, max_d)) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._build_volume._grid_mesh = mb.build() else: # Bottom and top 'ellipse' of the build volume aspect = 1.0 scale_matrix = Matrix() if self._build_volume._width != 0: # Scale circular meshes by aspect ratio if width != height aspect = self._build_volume._depth / self._build_volume._width scale_matrix.compose(scale=Vector(1, 1, aspect)) mb = MeshBuilder() mb.addArc(max_w, Vector.Unit_Y, center=(0, min_h - z_fight_distance, 0), color=self._build_volume._volume_outline_color) mb.addArc(max_w, Vector.Unit_Y, center=(0, max_h, 0), color=self._build_volume._volume_outline_color) self._build_volume.setMeshData( mb.build().getTransformed(scale_matrix)) # Build plate grid mesh mb = MeshBuilder() mb.addVertex(0, min_h - z_fight_distance, 0) mb.addArc(max_w, Vector.Unit_Y, center=Vector(0, min_h - z_fight_distance, 0)) sections = mb.getVertexCount( ) - 1 # Center point is not an arc section indices = [] for n in range(0, sections - 1): indices.append([0, n + 2, n + 1]) mb.addIndices(numpy.asarray(indices, dtype=numpy.int32)) mb.calculateNormals() for n in range(0, mb.getVertexCount()): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2] * aspect) self._build_volume._grid_mesh = mb.build().getTransformed( scale_matrix) # Indication of the machine origin if self._build_volume._global_container_stack.getProperty( "machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb = MeshBuilder() mb.addCube(width=self._build_volume._origin_line_length, height=self._build_volume._origin_line_width, depth=self._build_volume._origin_line_width, center=origin + Vector(self._build_volume._origin_line_length / 2, 0, 0), color=self._build_volume._x_axis_color) mb.addCube(width=self._build_volume._origin_line_width, height=self._build_volume._origin_line_length, depth=self._build_volume._origin_line_width, center=origin + Vector(0, self._build_volume._origin_line_length / 2, 0), color=self._build_volume._y_axis_color) mb.addCube(width=self._build_volume._origin_line_width, height=self._build_volume._origin_line_width, depth=self._build_volume._origin_line_length, center=origin - Vector(0, 0, self._build_volume._origin_line_length / 2), color=self._build_volume._z_axis_color) self._build_volume._origin_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._build_volume._disallowed_areas: mb = MeshBuilder() color = self._build_volume._disallowed_area_color for polygon in self._build_volume._disallowed_areas: points = polygon.getPoints() if len(points) == 0: continue first = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector( self._build_volume._clamp(point[0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min( points[:, 1] ) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs( numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._build_volume._disallowed_area_mesh = mb.build() else: self._build_volume._disallowed_area_mesh = None if self._build_volume._error_areas: mb = MeshBuilder() for error_area in self._build_volume._error_areas: color = self._build_volume._error_area_color points = error_area.getPoints() first = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) previous_point = Vector( self._build_volume._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector( self._build_volume._clamp(point[0], min_w, max_w), disallowed_area_height, self._build_volume._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._build_volume._error_mesh = mb.build() else: self._build_volume._error_mesh = None self._build_volume._volume_aabb = AxisAlignedBox( minimum=Vector(min_w, min_h - 1.0, min_d), maximum=Vector( max_w, max_h - self._build_volume._raft_thickness - self._build_volume._extra_z_clearance, max_d)) bed_adhesion_size = self._build_volume.getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum=Vector( min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum=Vector( max_w - bed_adhesion_size - 1, max_h - self._build_volume._raft_thickness - self._build_volume._extra_z_clearance, max_d - disallowed_area_size + bed_adhesion_size - 1)) Application.getInstance().getController().getScene( )._maximum_bounds = scale_to_max_bounds self._build_volume.updateNodeBoundaryCheck()
def rebuild(self): if not self._width or not self._height or not self._depth: return min_w = -self._width / 2 max_w = self._width / 2 min_h = 0.0 max_h = self._height min_d = -self._depth / 2 max_d = self._depth / 2 mb = MeshBuilder() # Outline 'cube' of the build volume mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor) mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor) self.setMeshData(mb.build()) mb = MeshBuilder() # Indication of the machine origin if self._global_container_stack.getProperty("machine_center_is_zero", "value"): origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2 else: origin = Vector(min_w, min_h, max_d) mb.addCube( width = self._origin_line_length, height = self._origin_line_width, depth = self._origin_line_width, center = origin + Vector(self._origin_line_length / 2, 0, 0), color = self.XAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_length, depth = self._origin_line_width, center = origin + Vector(0, self._origin_line_length / 2, 0), color = self.YAxisColor ) mb.addCube( width = self._origin_line_width, height = self._origin_line_width, depth = self._origin_line_length, center = origin - Vector(0, 0, self._origin_line_length / 2), color = self.ZAxisColor ) self._origin_mesh = mb.build() mb = MeshBuilder() mb.addQuad( Vector(min_w, min_h - 0.2, min_d), Vector(max_w, min_h - 0.2, min_d), Vector(max_w, min_h - 0.2, max_d), Vector(min_w, min_h - 0.2, max_d) ) for n in range(0, 6): v = mb.getVertex(n) mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: mb = MeshBuilder() color = Color(0.0, 0.0, 0.0, 0.15) for polygon in self._disallowed_areas: points = polygon.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color = color) previous_point = new_point # Find the largest disallowed area to exclude it from the maximum scale bounds. # This is a very nasty hack. This pretty much only works for UM machines. # This disallowed area_size needs a -lot- of rework at some point in the future: TODO if numpy.min(points[:, 1]) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area. size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1])) else: size = 0 disallowed_area_size = max(size, disallowed_area_size) self._disallowed_area_mesh = mb.build() else: self._disallowed_area_mesh = None if self._error_areas: mb = MeshBuilder() for error_area in self._error_areas: color = Color(1.0, 0.0, 0.0, 0.5) points = error_area.getPoints() first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d)) for point in points: new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d)) mb.addFace(first, previous_point, new_point, color=color) previous_point = new_point self._error_mesh = mb.build() else: self._error_mesh = None self._volume_aabb = AxisAlignedBox( minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h - self._raft_thickness, max_d)) bed_adhesion_size = self._getEdgeDisallowedSize() # As this works better for UM machines, we only add the disallowed_area_size for the z direction. # This is probably wrong in all other cases. TODO! # The +1 and -1 is added as there is always a bit of extra room required to work properly. scale_to_max_bounds = AxisAlignedBox( minimum = Vector(min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1), maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + bed_adhesion_size - 1) ) Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
def _rebuild(self): mb = MeshBuilder() #SOLIDMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube( width = self._lineWidth, height = self._lineLength, depth = self._lineWidth, center = Vector(0, self._handlePosition/2, 0), color = ToolHandle.YAxisColor ) if self.XAxis in self._enabled_axis: mb.addCube( width = self._lineLength, height = self._lineWidth, depth = self._lineWidth, center = Vector(self._handlePosition/2, 0, 0), color = ToolHandle.XAxisColor ) if self.ZAxis in self._enabled_axis: mb.addCube( width = self._lineWidth, height = self._lineWidth, depth = self._lineLength, center = Vector(0, 0, self._handlePosition/2), color = ToolHandle.ZAxisColor ) #SOLIDMESH -> HANDLES if self.YAxis in self._enabled_axis: mb.addPyramid( width = self._handleWidth, height = self._handleHeight, depth = self._handleWidth, center = Vector(0, self._handlePosition, 0), color = ToolHandle.YAxisColor ) if self.XAxis in self._enabled_axis: mb.addPyramid( width = self._handleWidth, height = self._handleHeight, depth = self._handleWidth, center = Vector(self._handlePosition, 0, 0), color = ToolHandle.XAxisColor, axis = Vector.Unit_Z, angle = 90 ) if self.ZAxis in self._enabled_axis: mb.addPyramid( width = self._handleWidth, height = self._handleHeight, depth = self._handleWidth, center = Vector(0, 0, self._handlePosition), color = ToolHandle.ZAxisColor, axis = Vector.Unit_X, angle = -90 ) self.setSolidMesh(mb.getData()) mb = MeshBuilder() #ACTIVEMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube( width = self._activeLineWidth, height = self._activeLineLength, depth = self._activeLineWidth, center = Vector(0, self._activeHandlePosition/2, 0), color = ToolHandle.YAxisColor ) if self.XAxis in self._enabled_axis: mb.addCube( width = self._activeLineLength, height = self._activeLineWidth, depth = self._activeLineWidth, center = Vector(self._activeHandlePosition/2, 0, 0), color = ToolHandle.XAxisColor ) if self.ZAxis in self._enabled_axis: mb.addCube( width = self._activeLineWidth, height = self._activeLineWidth, depth = self._activeLineLength, center = Vector(0, 0, self._activeHandlePosition/2), color = ToolHandle.ZAxisColor ) #SELECTIONMESH -> HANDLES mb.addCube( width = self._activeHandleWidth, height = self._activeHandleWidth, depth = self._activeHandleWidth, center = Vector(0, 0, 0), color = ToolHandle.AllAxisColor ) mb.addCube( width = self._activeHandleWidth, height = self._activeHandleWidth, depth = self._activeHandleWidth, center = Vector(0, self._activeHandlePosition, 0), color = ToolHandle.YAxisColor ) mb.addCube( width = self._activeHandleWidth, height = self._activeHandleWidth, depth = self._activeHandleWidth, center = Vector(self._activeHandlePosition, 0, 0), color = ToolHandle.XAxisColor ) mb.addCube( width = self._activeHandleWidth, height = self._activeHandleWidth, depth = self._activeHandleWidth, center = Vector(0, 0, self._activeHandlePosition), color = ToolHandle.ZAxisColor ) self.setSelectionMesh(mb.getData())
def beginRendering(self): # Convenience setup scene = self.getController().getScene() renderer = self.getRenderer() if not self._shader: self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader")) self._shader.setUniformValue("u_color", Color(32, 32, 32, 170)) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): # For now we only render nodes that indicate that they need rendering. if node.getMeshData(): # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh = self._getAxisMesh(node), transparent = True) # Render transparent MeshData renderer.queueNode(node, shader = self._shader, transparent = True) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": node.getParent().getName(), "has_mesh": "True"}) # Handle group nodes if node.callDecoration("isGroup"): # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh=self._getAxisMesh(node), transparent = True) # Render bounding box of this node renderer.queueNode(scene.getRoot(), mesh=node.getBoundingBoxMesh(), mode=Renderer.RenderLines) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": node.getParent().getName(), "has_mesh": node.getMeshData() is not None}) # We sometimes have nodes that are not groups, but have children. Also draw them elif not node.getMeshData() and len(node.getChildren()) != 0: # Render origin of this node. renderer.queueNode(scene.getRoot(), mesh=self._getAxisMesh(node), transparent = True) billboard_node = self._ensureNodeHasBillboard(node) # Update the displayed data on the billboard. data = self._matrixToHtml(node.getLocalTransformation()) parent_name = node.getParent().getName() if node.getParent() else "" billboard_node.setDisplayData({"name": node.getName(), "matrix": data, "depth": node.getDepth(), "parent_name": parent_name, "has_mesh": "False"}) bounding_box = node.getBoundingBox() if bounding_box: mesh_builder = MeshBuilder() mesh_builder.addCube( width=bounding_box.width, height=bounding_box.height, depth=bounding_box.depth, center=bounding_box.center, color=Color(0.0, 0.0, 1.0, 1.0) ) mesh = mesh_builder.build() renderer.queueNode(scene.getRoot(), mesh=mesh, mode=Renderer.RenderLines)
def run(self) -> None: if self._build_plate_number is None: self.setResult(StartJobResult.Error) return stack = CuraApplication.getInstance().getGlobalContainerStack() if not stack: self.setResult(StartJobResult.Error) return # Don't slice if there is a setting with an error value. if CuraApplication.getInstance().getMachineManager().stacksHaveErrors: self.setResult(StartJobResult.SettingError) return if CuraApplication.getInstance().getBuildVolume().hasErrors(): self.setResult(StartJobResult.BuildPlateError) return # Don't slice if the buildplate or the nozzle type is incompatible with the materials if not CuraApplication.getInstance().getMachineManager().variantBuildplateCompatible and \ not CuraApplication.getInstance().getMachineManager().variantBuildplateUsable: self.setResult(StartJobResult.MaterialIncompatible) return for position, extruder_stack in stack.extruders.items(): material = extruder_stack.findContainer({"type": "material"}) if not extruder_stack.isEnabled: continue if material: if material.getMetaDataEntry("compatible") == False: self.setResult(StartJobResult.MaterialIncompatible) return # Don't slice if there is a per object setting with an error value. for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if not isinstance(node, CuraSceneNode) or not node.isSelectable(): continue if self._checkStackForErrors(node.callDecoration("getStack")): self.setResult(StartJobResult.ObjectSettingError) return with self._scene.getSceneLock(): # Remove old layer data. for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if node.callDecoration("getLayerData") and node.callDecoration( "getBuildPlateNumber") == self._build_plate_number: node.getParent().removeChild(node) break global_enable_support = stack.getProperty("support_enable", "value") # Get the objects in their groups to print. object_groups = [] if stack.getProperty("print_sequence", "value") == "one_at_a_time": # note that one_at_a_time printing is disabled on belt printers due to collission risk for node in OneAtATimeIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. temp_list = [] # Node can't be printed, so don't bother sending it. if getattr(node, "_outside_buildarea", False): continue # Filter on current build plate build_plate_number = node.callDecoration( "getBuildPlateNumber") if build_plate_number is not None and build_plate_number != self._build_plate_number: continue children = node.getAllChildren() children.append(node) for child_node in children: if child_node.getMeshData() and child_node.getMeshData( ).getVertices() is not None: temp_list.append(child_node) if temp_list: object_groups.append(temp_list) Job.yieldThread() if len(object_groups) == 0: Logger.log( "w", "No objects suitable for one at a time found, or no correct order found" ) else: temp_list = [] has_printing_mesh = False # print convex hull nodes as "faux-raft" print_convex_hulls = self._preferences.getValue( "BeltPlugin/raft") for node in DepthFirstIterator( self._scene.getRoot() ): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. slice_node = (print_convex_hulls and type(node) is ConvexHullNode ) or node.callDecoration("isSliceable") if slice_node and node.getMeshData() and node.getMeshData( ).getVertices() is not None: per_object_stack = node.callDecoration("getStack") is_non_printing_mesh = False if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) # Find a reason not to add the node if node.callDecoration( "getBuildPlateNumber" ) != self._build_plate_number and type( node) is not ConvexHullNode: # NB: ConvexHullNodes get none of the usual decorators, so skip checking for them continue if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue temp_list.append(node) if not is_non_printing_mesh: has_printing_mesh = True Job.yieldThread() #If the list doesn't have any model with suitable settings then clean the list # otherwise CuraEngine will crash if not has_printing_mesh: temp_list.clear() if temp_list: object_groups.append(temp_list) global_stack = CuraApplication.getInstance( ).getGlobalContainerStack() if not global_stack: return extruders_enabled = { position: stack.isEnabled for position, stack in global_stack.extruders.items() } filtered_object_groups = [] has_model_with_disabled_extruders = False associated_disabled_extruders = set() for group in object_groups: stack = global_stack skip_group = False for node in group: # Only check if the printing extruder is enabled for printing meshes is_non_printing_mesh = node.callDecoration( "evaluateIsNonPrintingMesh") extruder_position = node.callDecoration( "getActiveExtruderPosition") if extruder_position is None: # raft meshes may not have an extruder position (yet) extruder_position = "0" if not is_non_printing_mesh and not extruders_enabled[ extruder_position]: skip_group = True has_model_with_disabled_extruders = True associated_disabled_extruders.add(extruder_position) if not skip_group: filtered_object_groups.append(group) if has_model_with_disabled_extruders: self.setResult(StartJobResult.ObjectsWithDisabledExtruder) associated_disabled_extruders = { str(c) for c in sorted( [int(p) + 1 for p in associated_disabled_extruders]) } self.setMessage(", ".join(associated_disabled_extruders)) return # There are cases when there is nothing to slice. This can happen due to one at a time slicing not being # able to find a possible sequence or because there are no objects on the build plate (or they are outside # the build volume) if not filtered_object_groups: self.setResult(StartJobResult.NothingToSlice) return container_registry = ContainerRegistry.getInstance() stack_id = stack.getId() # Adapt layer_height and material_flow for a slanted gantry gantry_angle = self._scene.getRoot().callDecoration( "getGantryAngle") #gantry_angle = float(self._preferences.getValue("BeltPlugin/gantry_angle")) if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _stack = CuraContainerStack(stack_id + "_temp") for index, container in enumerate(stack.getContainers()): if container_registry.isReadOnly(container.getId()): _stack.replaceContainer(index, container) else: _stack.replaceContainer(index, copy.deepcopy(container)) stack = _stack # Make sure CuraEngine does not create any supports # support_enable is set in the frontend so support options are settable, # but CuraEngine support structures don't work for slanted gantry stack.setProperty("support_enable", "value", False) # Make sure CuraEngine does not create a raft (we create one manually) # Adhesion type is used in the frontend to show the raft in the viewport stack.setProperty("adhesion_type", "value", "none") for key in ["layer_height", "layer_height_0"]: current_value = stack.getProperty(key, "value") stack.setProperty(key, "value", current_value / math.sin(gantry_angle)) self._buildGlobalSettingsMessage(stack) self._buildGlobalInheritsStackMessage(stack) # Build messages for extruder stacks # Send the extruder settings in the order of extruder positions. Somehow, if you send e.g. extruder 3 first, # then CuraEngine can slice with the wrong settings. This I think should be fixed in CuraEngine as well. extruder_stack_list = sorted(list(global_stack.extruders.items()), key=lambda item: int(item[0])) for _, extruder_stack in extruder_stack_list: if gantry_angle: # not 0 or None # Act on a copy of the stack, so these changes don't cause a reslice _extruder_stack = CuraContainerStack( extruder_stack.getId() + "_temp") for index, container in enumerate( extruder_stack.getContainers()): if container_registry.isReadOnly(container.getId()): _extruder_stack.replaceContainer(index, container) else: _extruder_stack.replaceContainer( index, copy.deepcopy(container)) extruder_stack = _extruder_stack extruder_stack.setNextStack(stack) for key in [ "material_flow", "prime_tower_flow", "spaghetti_flow" ]: if extruder_stack.hasProperty(key, "value"): current_value = extruder_stack.getProperty( key, "value") extruder_stack.setProperty( key, "value", current_value * math.sin(gantry_angle)) self._buildExtruderMessage(extruder_stack) bottom_cutting_meshes = [] raft_meshes = [] support_meshes = [] if gantry_angle: # not 0 or None for group in filtered_object_groups: added_meshes = [] for object in group: is_non_printing_mesh = False per_object_stack = object.callDecoration("getStack") # ConvexHullNodes get none of the usual decorators. If it made it here, it is meant to be printed if type(object) is ConvexHullNode: raft_thickness = self._preferences.getValue( "BeltPlugin/raft_thickness") raft_margin = self._preferences.getValue( "BeltPlugin/raft_margin") mb = MeshBuilder() hull_polygon = object.getHull() if raft_margin > 0: hull_polygon = hull_polygon.getMinkowskiHull( Polygon.approximatedCircle(raft_margin)) mb.addConvexPolygonExtrusion( hull_polygon.getPoints()[::-1], 0, raft_thickness) new_node = self._addMeshFromBuilder(mb, "raftMesh") added_meshes.append(new_node) raft_meshes.append(new_node.getName()) elif not is_non_printing_mesh: # add support mesh if needed belt_support_gantry_angle_bias = None belt_support_minimum_island_area = None if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) node_enable_support = per_object_stack.getProperty( "support_enable", "value") if per_object_stack.getProperty( "support_mesh", "value"): node_enable_support = node_enable_support or per_object_stack.getProperty( "support_mesh_drop_down", "value") add_support_mesh = node_enable_support if node_enable_support is not None else global_enable_support belt_support_gantry_angle_bias = self._preferences.getValue( "BeltPlugin/support_gantry_angle_bias") belt_support_minimum_island_area = self._preferences.getValue( "BeltPlugin/support_minimum_island_area") else: add_support_mesh = global_enable_support if add_support_mesh: #preferences = Application.getInstance().getPreferences() if belt_support_gantry_angle_bias is None: belt_support_gantry_angle_bias = self._preferences.getValue( "BeltPlugin/support_gantry_angle_bias") biased_down_angle = math.radians( belt_support_gantry_angle_bias) if belt_support_minimum_island_area is None: belt_support_minimum_island_area = self._preferences.getValue( "BeltPlugin/support_minimum_island_area" ) support_mesh_data = SupportMeshCreator( down_vector=numpy.array([ 0, -math.cos( math.radians(biased_down_angle)), -math.sin(biased_down_angle) ]), bottom_cut_off=stack.getProperty( "wall_line_width_0", "value") / 2, minimum_island_area= belt_support_minimum_island_area ).createSupportMeshForNode(object) if support_mesh_data: new_node = self._addMeshFromData( support_mesh_data, "generatedSupportMesh") added_meshes.append(new_node) support_meshes.append(new_node.getName()) # check if the bottom needs to be cut off aabb = object.getBoundingBox() if aabb.bottom < 0: # mesh extends below the belt; add a cutting mesh to cut off the part below the bottom height = -aabb.bottom center = Vector(aabb.center.x, -height / 2, aabb.center.z) mb = MeshBuilder() mb.addCube(width=aabb.width, height=height, depth=aabb.depth, center=center) new_node = self._addMeshFromBuilder( mb, "bottomCuttingMesh") added_meshes.append(new_node) bottom_cutting_meshes.append( new_node.getName()) if added_meshes: group += added_meshes transform_matrix = self._scene.getRoot().callDecoration( "getTransformMatrix") front_offset = None raft_offset = 0 raft_speed = None raft_flow = 1.0 if self._preferences.getValue("BeltPlugin/raft"): raft_offset = self._preferences.getValue( "BeltPlugin/raft_thickness") raft_speed = self._preferences.getValue( "BeltPlugin/raft_speed") raft_flow = self._preferences.getValue( "BeltPlugin/raft_flow") * math.sin(gantry_angle) adhesion_extruder_nr = stack.getProperty("adhesion_extruder_nr", "value") support_extruder_nr = stack.getProperty("support_extruder_nr", "value") for group in filtered_object_groups: group_message = self._slice_message.addRepeatedMessage( "object_lists") if group[0].getParent() is not None and group[0].getParent( ).callDecoration("isGroup"): self._handlePerObjectSettings(group[0].getParent(), group_message) if transform_matrix: scene_front = None for object in group: if type(object) is ConvexHullNode: continue is_non_printing_mesh = object.getName( ) in bottom_cutting_meshes or object.getName( ) in raft_meshes if not is_non_printing_mesh: per_object_stack = object.callDecoration( "getStack") if per_object_stack: is_non_printing_mesh = any( per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) if not is_non_printing_mesh: _front = object.getBoundingBox().back if scene_front is None or _front < scene_front: scene_front = _front if scene_front is not None: front_offset = transformVertices( numpy.array([[0, 0, scene_front]]), transform_matrix)[0][1] for object in group: if type(object) is ConvexHullNode: continue mesh_data = object.getMeshData() rot_scale = object.getWorldTransformation().getTransposed( ).getData()[0:3, 0:3] translate = object.getWorldTransformation().getData()[:3, 3] # offset all non-raft objects if rafts are enabled # air gap is applied here to vertically offset objects from the raft if object.getName() not in raft_meshes: translate[1] += raft_offset if front_offset: translate[2] -= front_offset # This effectively performs a limited form of MeshData.getTransformed that ignores normals. verts = mesh_data.getVertices() verts = verts.dot(rot_scale) verts += translate if transform_matrix: verts = transformVertices(verts, transform_matrix) # Convert from Y up axes to Z up axes. Equals a 90 degree rotation. verts[:, [1, 2]] = verts[:, [2, 1]] verts[:, 1] *= -1 obj = group_message.addRepeatedMessage("objects") obj.id = id(object) obj.name = object.getName() indices = mesh_data.getIndices() if indices is not None: flat_verts = numpy.take(verts, indices.flatten(), axis=0) else: flat_verts = numpy.array(verts) obj.vertices = flat_verts if object.getName() in raft_meshes: self._addSettingsMessage( obj, { "wall_line_count": 99999999, "speed_wall_0": raft_speed, "speed_wall_x": raft_speed, "material_flow": raft_flow, "extruder_nr": adhesion_extruder_nr }) elif object.getName() in support_meshes: self._addSettingsMessage( obj, { "support_mesh": "True", "support_mesh_drop_down": "False", "extruder_nr": support_extruder_nr }) elif object.getName() in bottom_cutting_meshes: self._addSettingsMessage( obj, { "cutting_mesh": True, "wall_line_count": 0, "top_layers": 0, "bottom_layers": 0, "infill_line_distance": 0, "extruder_nr": 0 }) else: self._handlePerObjectSettings(object, obj) Job.yieldThread() # Store the front-most coordinate of the scene so the scene can be moved back into place post slicing # TODO: this should be handled per mesh-group instead of per scene # One-at-a-time printing should be disabled for slanted gantry printers for now self._scene.getRoot().callDecoration("setSceneFrontOffset", front_offset) self.setResult(StartJobResult.Finished)
def _rebuild(self): lines = MeshData() offset = 0 if self.YAxis in self._enabled_axis: lines.addVertex(0, 0, 0) lines.addVertex(0, 20, 0) lines.setVertexColor(offset, ToolHandle.YAxisColor) lines.setVertexColor(offset + 1, ToolHandle.YAxisColor) offset += 2 if self.XAxis in self._enabled_axis: lines.addVertex(0, 0, 0) lines.addVertex(20, 0, 0) lines.setVertexColor(offset, ToolHandle.XAxisColor) lines.setVertexColor(offset + 1, ToolHandle.XAxisColor) offset += 2 if self.ZAxis in self._enabled_axis: lines.addVertex(0, 0, 0) lines.addVertex(0, 0, 20) lines.setVertexColor(offset, ToolHandle.ZAxisColor) lines.setVertexColor(offset + 1, ToolHandle.ZAxisColor) offset += 2 self.setLineMesh(lines) mb = MeshBuilder() if self.YAxis in self._enabled_axis: mb.addPyramid( width = 2, height = 4, depth = 2, center = Vector(0, 20, 0), color = ToolHandle.YAxisColor ) if self.XAxis in self._enabled_axis: mb.addPyramid( width = 2, height = 4, depth = 2, center = Vector(20, 0, 0), color = ToolHandle.XAxisColor, axis = Vector.Unit_Z, angle = 90 ) if self.ZAxis in self._enabled_axis: mb.addPyramid( width = 2, height = 4, depth = 2, center = Vector(0, 0, 20), color = ToolHandle.ZAxisColor, axis = Vector.Unit_X, angle = -90 ) self.setSolidMesh(mb.getData()) mb = MeshBuilder() if self.YAxis in self._enabled_axis: mb.addCube( width = 4, height = 20, depth = 4, center = Vector(0, 10, 0), color = ToolHandle.YAxisColor ) mb.addPyramid( width = 4, height = 8, depth = 4, center = Vector(0, 20, 0), color = ToolHandle.YAxisColor ) if self.XAxis in self._enabled_axis: mb.addCube( width = 20, height = 4, depth = 4, center = Vector(10, 0, 0), color = ToolHandle.XAxisColor ) mb.addPyramid( width = 4, height = 8, depth = 4, center = Vector(20, 0, 0), color = ToolHandle.XAxisColor, axis = Vector.Unit_Z, angle = 90 ) if self.ZAxis in self._enabled_axis: mb.addCube( width = 4, height = 4, depth = 20, center = Vector(0, 0, 10), color = ToolHandle.ZAxisColor ) mb.addPyramid( width = 4, height = 8, depth = 4, center = Vector(0, 0, 20), color = ToolHandle.ZAxisColor, axis = Vector.Unit_X, angle = -90 ) self.setSelectionMesh(mb.getData())
def buildMesh(self): mb = MeshBuilder() #SOLIDMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube(width=self._line_width, height=self._line_length, depth=self._line_width, center=Vector(0, self._handle_position / 2, 0), color=self._y_axis_color) if self.XAxis in self._enabled_axis: mb.addCube(width=self._line_length, height=self._line_width, depth=self._line_width, center=Vector(self._handle_position / 2, 0, 0), color=self._x_axis_color) if self.ZAxis in self._enabled_axis: mb.addCube(width=self._line_width, height=self._line_width, depth=self._line_length, center=Vector(0, 0, self._handle_position / 2), color=self._z_axis_color) #SOLIDMESH -> HANDLES if self.YAxis in self._enabled_axis: mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, self._handle_position, 0), color=self._y_axis_color) if self.XAxis in self._enabled_axis: mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(self._handle_position, 0, 0), color=self._x_axis_color, axis=Vector.Unit_Z, angle=90) if self.ZAxis in self._enabled_axis: mb.addPyramid(width=self._handle_width, height=self._handle_height, depth=self._handle_width, center=Vector(0, 0, self._handle_position), color=self._z_axis_color, axis=Vector.Unit_X, angle=-90) self.setSolidMesh(mb.build()) mb = MeshBuilder() #SELECTIONMESH -> LINES if self.YAxis in self._enabled_axis: mb.addCube(width=self._active_line_width, height=self._active_line_length, depth=self._active_line_width, center=Vector(0, self._active_handle_position / 2, 0), color=self._y_axis_color) if self.XAxis in self._enabled_axis: mb.addCube(width=self._active_line_length, height=self._active_line_width, depth=self._active_line_width, center=Vector(self._active_handle_position / 2, 0, 0), color=self._x_axis_color) if self.ZAxis in self._enabled_axis: mb.addCube(width=self._active_line_width, height=self._active_line_width, depth=self._active_line_length, center=Vector(0, 0, self._active_handle_position / 2), color=self._z_axis_color) #SELECTIONMESH -> HANDLES mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, 0), color=ToolHandle.AllAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, self._active_handle_position, 0), color=ToolHandle.YAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(self._active_handle_position, 0, 0), color=ToolHandle.XAxisSelectionColor) mb.addCube(width=self._active_handle_width, height=self._active_handle_width, depth=self._active_handle_width, center=Vector(0, 0, self._active_handle_position), color=ToolHandle.ZAxisSelectionColor) self.setSelectionMesh(mb.build())
def buildMesh(self): #SOLIDMESH -> LINES mb = MeshBuilder() mb.addCube( width = self._line_width, height = self._line_length, depth = self._line_width, center = Vector(0, self._handle_position/2, 0), color = self._y_axis_color ) mb.addCube( width = self._line_length, height = self._line_width, depth = self._line_width, center = Vector(self._handle_position/2, 0, 0), color = self._x_axis_color ) mb.addCube( width = self._line_width, height = self._line_width, depth = self._line_length, center = Vector(0, 0, self._handle_position/2), color = self._z_axis_color ) #SOLIDMESH -> HANDLES mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, 0, 0), color = self._all_axis_color ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, self._handle_position, 0), color = self._y_axis_color ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(self._handle_position, 0, 0), color = self._x_axis_color ) mb.addCube( width = self._handle_width, height = self._handle_width, depth = self._handle_width, center = Vector(0, 0, self._handle_position), color = self._z_axis_color ) self.setSolidMesh(mb.build()) #SELECTIONMESH -> LINES mb = MeshBuilder() mb.addCube( width = self._active_line_width, height = self._active_line_length, depth = self._active_line_width, center = Vector(0, self._active_handle_position/2, 0), color = ToolHandle.YAxisSelectionColor ) mb.addCube( width = self._active_line_length, height = self._active_line_width, depth = self._active_line_width, center = Vector(self._active_handle_position/2, 0, 0), color = ToolHandle.XAxisSelectionColor ) mb.addCube( width = self._active_line_width, height = self._active_line_width, depth = self._active_line_length, center = Vector(0, 0, self._active_handle_position/2), color = ToolHandle.ZAxisSelectionColor ) #SELECTIONMESH -> HANDLES mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, 0), color = ToolHandle.AllAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, self._active_handle_position, 0), color = ToolHandle.YAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(self._active_handle_position, 0, 0), color = ToolHandle.XAxisSelectionColor ) mb.addCube( width = self._active_handle_width, height = self._active_handle_width, depth = self._active_handle_width, center = Vector(0, 0, self._active_handle_position), color = ToolHandle.ZAxisSelectionColor ) self.setSelectionMesh(mb.build())