Ejemplo n.º 1
0
    def _fixMaterialDiameterAndNozzleSize(self, global_stack, extruder_stack_list):
        keys_to_copy = ["material_diameter", "machine_nozzle_size"]  # these will be copied over to all extruders

        extruder_positions_to_update = set()
        for extruder_stack in extruder_stack_list:
            for key in keys_to_copy:
                # Only copy the value when this extruder doesn't have the value.
                if extruder_stack.definitionChanges.hasProperty(key, "value"):
                    continue

                setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty(key, "value")
                setting_value_in_global_def = global_stack.definition.getProperty(key, "value")
                setting_value = setting_value_in_global_def
                if setting_value_in_global_def_changes is not None:
                    setting_value = setting_value_in_global_def_changes
                if setting_value == extruder_stack.definition.getProperty(key, "value"):
                    continue

                setting_definition = global_stack.getSettingDefinition(key)
                new_instance = SettingInstance(setting_definition, extruder_stack.definitionChanges)
                new_instance.setProperty("value", setting_value)
                new_instance.resetState()  # Ensure that the state is not seen as a user state.
                extruder_stack.definitionChanges.addInstance(new_instance)
                extruder_stack.definitionChanges.setDirty(True)

                # Make sure the material diameter is up to date for the extruder stack.
                if key == "material_diameter":
                    position = int(extruder_stack.getMetaDataEntry("position"))
                    extruder_positions_to_update.add(position)

        # We have to remove those settings here because we know that those values have been copied to all
        # the extruders at this point.
        for key in keys_to_copy:
            if global_stack.definitionChanges.hasProperty(key, "value"):
                global_stack.definitionChanges.removeInstance(key, postpone_emit = True)
Ejemplo n.º 2
0
    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 = AddSceneNodeOperation(node, parent)
        op.push()
        node.setPosition(position, CuraSceneNode.TransformSpace.World)

        Application.getInstance().getController().getScene().sceneChanged.emit(node)
Ejemplo n.º 3
0
    def _createEraserMesh(self, parent: CuraSceneNode, position: Vector):
        node = CuraSceneNode()

        node.setName("Eraser")
        node.setSelectable(True)
        node.setCalculateBoundingBox(True)
        mesh = self._createCube(10)
        node.setMeshData(mesh.build())
        node.calculateBoundingBoxMesh()

        active_build_plate = CuraApplication.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)

        CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
Ejemplo n.º 4
0
    def setNextStack(self, stack: ContainerStack) -> None:
        super().setNextStack(stack)
        stack.addExtruder(self)
        self.addMetaDataEntry("machine", stack.id)

        # For backward compatibility: Register the extruder with the Extruder Manager
        ExtruderManager.getInstance().registerExtruder(self, stack.id)

        # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific
        # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to
        # the this extruder's definition_changes.
        #
        # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade,
        # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as
        # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in
        # the latest format.
        if self.getMetaDataEntry("position") == "0":
            for key in _EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS:
                setting_value = stack.definitionChanges.getProperty(
                    key, "value")
                if setting_value is None:
                    continue

                setting_definition = stack.getSettingDefinition(key)
                new_instance = SettingInstance(setting_definition,
                                               self.definitionChanges)
                new_instance.setProperty("value", setting_value)
                new_instance.resetState(
                )  # Ensure that the state is not seen as a user state.
                self.definitionChanges.addInstance(new_instance)
                self.definitionChanges.setDirty(True)

                stack.definitionChanges.removeInstance(key, postpone_emit=True)
Ejemplo n.º 5
0
    def setMeshType(self, mesh_type):
        selected_object = Selection.getSelectedObject(0)
        stack = selected_object.callDecoration(
            "getStack"
        )  #Don't try to get the active extruder since it may be None anyway.
        if not stack:
            selected_object.addDecorator(SettingOverrideDecorator())
            stack = selected_object.callDecoration("getStack")

        settings = stack.getTop()
        for property_key in [
                "infill_mesh", "cutting_mesh", "support_mesh",
                "anti_overhang_mesh"
        ]:
            if property_key != mesh_type:
                if settings.getInstance(property_key):
                    settings.removeInstance(property_key)
            else:
                if not (settings.getInstance(property_key)
                        and settings.getProperty(property_key, "value")):
                    definition = stack.getSettingDefinition(property_key)
                    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)
Ejemplo n.º 6
0
    def setVisible(self, visible):
        if not self._node:
            return

        if not self._stack:
            self._node.addDecorator(SettingOverrideDecorator())
            self._stack = self._node.callDecoration("getStack")

        settings = self._stack.getTop()
        all_instances = settings.findInstances()
        visibility_changed = False  # Flag to check if at the end the signal needs to be emitted

        # Remove all instances that are not in visibility list
        for instance in all_instances:
            # exceptionally skip setting
            if instance.definition.key in self._skip_reset_setting_set:
                continue
            if instance.definition.key not in visible:
                settings.removeInstance(instance.definition.key)
                visibility_changed = True

        # Add all instances that are not added, but are in visibility list
        for item in visible:
            if not settings.getInstance(item): # Setting was not added already.
                definition = self._stack.getSettingDefinition(item)
                if definition:
                    new_instance = SettingInstance(definition, settings)
                    stack_nr = -1
                    stack = None
                    # Check from what stack we should copy the raw property of the setting from.
                    if self._stack.getProperty("machine_extruder_count", "value") > 1:
                        if definition.limit_to_extruder != "-1":
                            # A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use.
                            stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder")))))

                        # Check if the found stack_number is in the extruder list of extruders.
                        if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None:
                            stack_nr = -1

                        # Use the found stack number to get the right stack to copy the value from.
                        if stack_nr in ExtruderManager.getInstance().extruderIds:
                            stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
                    else:
                        stack = self._stack

                    # Use the raw property to set the value (so the inheritance doesn't break)
                    if stack is not None:
                        new_instance.setProperty("value", stack.getRawProperty(item, "value"))
                    else:
                        new_instance.setProperty("value", None)
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    visibility_changed = True
                else:
                    Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item)

        if visibility_changed:
            self.visibilityChanged.emit()
Ejemplo n.º 7
0
    def setMeshType(self, mesh_type: str) -> bool:
        old_mesh_type = self.getMeshType()
        if old_mesh_type == mesh_type:
            return False

        selected_object = Selection.getSelectedObject(0)
        if selected_object is None:
            Logger.log(
                "w",
                "Tried setting the mesh type of the selected object, but no object was selected"
            )
            return False

        stack = selected_object.callDecoration(
            "getStack"
        )  #Don't try to get the active extruder since it may be None anyway.
        if not stack:
            selected_object.addDecorator(SettingOverrideDecorator())
            stack = selected_object.callDecoration("getStack")

        settings = stack.getTop()
        for property_key in [
                "infill_mesh", "cutting_mesh", "support_mesh",
                "anti_overhang_mesh"
        ]:
            if property_key != mesh_type:
                if settings.getInstance(property_key):
                    settings.removeInstance(property_key)
            else:
                if not (settings.getInstance(property_key)
                        and settings.getProperty(property_key, "value")):
                    definition = stack.getSettingDefinition(property_key)
                    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)

        for property_key in ["top_bottom_thickness", "wall_thickness"]:
            if mesh_type == "infill_mesh":
                if settings.getInstance(property_key) is None:
                    definition = stack.getSettingDefinition(property_key)
                    new_instance = SettingInstance(definition, settings)
                    new_instance.setProperty("value", 0)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    visible = self.visibility_handler.getVisible()
                    visible.add(property_key)
                    self.visibility_handler.setVisible(visible)
            elif old_mesh_type == "infill_mesh" and settings.getInstance(
                    property_key) and settings.getProperty(
                        property_key, "value") == 0:
                settings.removeInstance(property_key)

        self.propertyChanged.emit()
        return True
    def setVisible(self, visible):
        if not self._node:
            return

        if not self._stack:
            self._node.addDecorator(SettingOverrideDecorator())
            self._stack = self._node.callDecoration("getStack")

        settings = self._stack.getTop()
        all_instances = settings.findInstances()
        visibility_changed = False  # Flag to check if at the end the signal needs to be emitted

        # Remove all instances that are not in visibility list
        for instance in all_instances:
            if instance.definition.key not in visible:
                settings.removeInstance(instance.definition.key)
                visibility_changed = True

        # Add all instances that are not added, but are in visibility list
        for item in visible:
            if not settings.getInstance(item):
                definition = self._stack.getSettingDefinition(item)
                if definition:
                    new_instance = SettingInstance(definition, settings)
                    stack_nr = -1
                    if definition.limit_to_extruder and self._stack.getProperty("machine_extruder_count", "value") > 1:
                        # Obtain the value from the correct container stack. Only once, upon adding the setting.
                        stack_nr = str(
                            int(round(float(self._stack.getProperty(item, "limit_to_extruder"))))
                        )  # Stack to get the setting from. Round it and remove the fractional part.
                    if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty(
                        "extruder_nr", "value"
                    ):  # Property not defined, but we have an extruder number.
                        stack_nr = str(int(round(float(self._stack.getProperty("extruder_nr", "value")))))
                    if (
                        stack_nr in ExtruderManager.getInstance().extruderIds
                    ):  # We have either a limit_to_extruder or an extruder_nr.
                        stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(
                            id=ExtruderManager.getInstance().extruderIds[stack_nr]
                        )[0]
                    else:
                        stack = UM.Application.getInstance().getGlobalContainerStack()
                    new_instance.setProperty("value", stack.getRawProperty(item, "value"))
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    visibility_changed = True
                else:
                    Logger.log(
                        "w",
                        "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition",
                        item,
                    )

        if visibility_changed:
            self.visibilityChanged.emit()
Ejemplo n.º 9
0
    def setNextStack(self, stack: ContainerStack) -> None:
        super().setNextStack(stack)
        stack.addExtruder(self)
        self.addMetaDataEntry("machine", stack.id)

        # For backward compatibility: Register the extruder with the Extruder Manager
        ExtruderManager.getInstance().registerExtruder(self, stack.id)

        # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific
        # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to
        # the this extruder's definition_changes.
        #
        # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade,
        # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as
        # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in
        # the latest format.
        #
        # MORE:
        # For single-extrusion machines, nozzle size is saved in the global stack, so the nozzle size value should be
        # carried to the first extruder.
        # For material diameter, it was supposed to be applied to all extruders, so its value should be copied to all
        # extruders.

        keys_to_copy = ["material_diameter", "machine_nozzle_size"
                        ]  # these will be copied over to all extruders

        for key in keys_to_copy:
            # Since material_diameter is not on the extruder definition, we need to add it here
            # WARNING: this might be very dangerous and should be refactored ASAP!
            definition = stack.getSettingDefinition(key)
            if definition:
                self.definition.addDefinition(definition)

            # Only copy the value when this extruder doesn't have the value.
            if self.definitionChanges.hasProperty(key, "value"):
                continue

            setting_value = stack.definitionChanges.getProperty(key, "value")
            if setting_value is None:
                continue

            setting_definition = stack.getSettingDefinition(key)
            new_instance = SettingInstance(setting_definition,
                                           self.definitionChanges)
            new_instance.setProperty("value", setting_value)
            new_instance.resetState(
            )  # Ensure that the state is not seen as a user state.
            self.definitionChanges.addInstance(new_instance)
            self.definitionChanges.setDirty(True)

            # Make sure the material diameter is up to date for the extruder stack.
            if key == "material_diameter":
                position = self.getMetaDataEntry("position", "0")
                Application.getInstance().getExtruderManager(
                ).updateMaterialForDiameter(position)
    def setVisible(self, visible):
        if not self._node:
            return

        if not self._stack:
            self._node.addDecorator(SettingOverrideDecorator())
            self._stack = self._node.callDecoration("getStack")

        settings = self._stack.getTop()
        all_instances = settings.findInstances()
        visibility_changed = False  # Flag to check if at the end the signal needs to be emitted

        # Remove all instances that are not in visibility list
        for instance in all_instances:
            if instance.definition.key not in visible:
                settings.removeInstance(instance.definition.key)
                visibility_changed = True

        # Add all instances that are not added, but are in visibility list
        for item in visible:
            if not settings.getInstance(item): # Setting was not added already.
                definition = self._stack.getSettingDefinition(item)
                if definition:
                    new_instance = SettingInstance(definition, settings)
                    stack_nr = -1
                    stack = None
                    # Check from what stack we should copy the raw property of the setting from.
                    if self._stack.getProperty("machine_extruder_count", "value") > 1:
                        if definition.limit_to_extruder != "-1":
                            # A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use.
                            stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder")))))

                        # Check if the found stack_number is in the extruder list of extruders.
                        if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None:
                            stack_nr = -1

                        # Use the found stack number to get the right stack to copy the value from.
                        if stack_nr in ExtruderManager.getInstance().extruderIds:
                            stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
                    else:
                        stack = self._stack

                    # Use the raw property to set the value (so the inheritance doesn't break)
                    if stack is not None:
                        new_instance.setProperty("value", stack.getRawProperty(item, "value"))
                    else:
                        new_instance.setProperty("value", None)
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    visibility_changed = True
                else:
                    Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item)

        if visibility_changed:
            self.visibilityChanged.emit()
Ejemplo n.º 11
0
    def _fixMaterialDiameterAndNozzleSize(self, global_stack,
                                          extruder_stack_list):
        keys_to_copy = ["material_diameter", "machine_nozzle_size"
                        ]  # these will be copied over to all extruders

        extruder_positions_to_update = set()
        for extruder_stack in extruder_stack_list:
            for key in keys_to_copy:
                # Only copy the value when this extruder doesn't have the value.
                if extruder_stack.definitionChanges.hasProperty(key, "value"):
                    continue

                setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty(
                    key, "value")
                setting_value_in_global_def = global_stack.definition.getProperty(
                    key, "value")
                setting_value = setting_value_in_global_def
                if setting_value_in_global_def_changes is not None:
                    setting_value = setting_value_in_global_def_changes
                if setting_value == extruder_stack.definition.getProperty(
                        key, "value"):
                    continue

                setting_definition = global_stack.getSettingDefinition(key)
                new_instance = SettingInstance(
                    setting_definition, extruder_stack.definitionChanges)
                new_instance.setProperty("value", setting_value)
                new_instance.resetState(
                )  # Ensure that the state is not seen as a user state.
                extruder_stack.definitionChanges.addInstance(new_instance)
                extruder_stack.definitionChanges.setDirty(True)

                # Make sure the material diameter is up to date for the extruder stack.
                if key == "material_diameter":
                    position = int(extruder_stack.getMetaDataEntry("position"))
                    extruder_positions_to_update.add(position)

        # We have to remove those settings here because we know that those values have been copied to all
        # the extruders at this point.
        for key in keys_to_copy:
            if global_stack.definitionChanges.hasProperty(key, "value"):
                global_stack.definitionChanges.removeInstance(
                    key, postpone_emit=True)

        # Update material diameter for extruders
        for position in extruder_positions_to_update:
            self.updateMaterialForDiameter(position, global_stack=global_stack)
Ejemplo n.º 12
0
    def setVisible(self, visible):
        if not self._node:
            return

        if not self._stack:
            self._node.addDecorator(SettingOverrideDecorator())
            self._stack = self._node.callDecoration("getStack")

        settings = self._stack.getTop()
        all_instances = settings.findInstances()
        visibility_changed = False  # Flag to check if at the end the signal needs to be emitted

        # Remove all instances that are not in visibility list
        for instance in all_instances:
            if instance.definition.key not in visible:
                settings.removeInstance(instance.definition.key)
                visibility_changed = True

        # Add all instances that are not added, but are in visibility list
        for item in visible:
            if not settings.getInstance(item):
                definition = self._stack.getSettingDefinition(item)
                if definition:
                    new_instance = SettingInstance(definition, settings)
                    stack_nr = -1
                    if definition.global_inherits_stack and self._stack.getProperty("machine_extruder_count", "value") > 1:
                        #Obtain the value from the correct container stack. Only once, upon adding the setting.
                        stack_nr = str(int(round(float(self._stack.getProperty(item, "global_inherits_stack"))))) #Stack to get the setting from. Round it and remove the fractional part.
                    if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value"): #Property not defined, but we have an extruder number.
                        stack_nr = str(int(round(float(self._stack.getProperty("extruder_nr", "value")))))
                    if stack_nr in ExtruderManager.getInstance().extruderIds: #We have either a global_inherits_stack or an extruder_nr.
                        stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
                    else:
                        stack = UM.Application.getInstance().getGlobalContainerStack()
                    new_instance.setProperty("value", stack.getProperty(item, "value"))
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    visibility_changed = True
                else:
                    Logger.log("w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item)

        if visibility_changed:
            self.visibilityChanged.emit()
Ejemplo n.º 13
0
    def setMeshType(self, mesh_type):
        selected_object = Selection.getSelectedObject(0)
        stack = selected_object.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
        if not stack:
            selected_object.addDecorator(SettingOverrideDecorator())
            stack = selected_object.callDecoration("getStack")

        settings = stack.getTop()
        for property_key in ["infill_mesh", "cutting_mesh", "support_mesh", "anti_overhang_mesh"]:
            if property_key != mesh_type:
                if settings.getInstance(property_key):
                    settings.removeInstance(property_key)
            else:
                if not (settings.getInstance(property_key) and settings.getProperty(property_key, "value")):
                    definition = stack.getSettingDefinition(property_key)
                    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)
Ejemplo n.º 14
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)
Ejemplo n.º 15
0
    def _createSupportMesh(self, parent: CuraSceneNode, position: Vector):
        node = CuraSceneNode()
        node.setSelectable(True)
        
        if self._SupportType == 'cylinder':
            height = position.y
            node.setName("CustomSupportCylinder")
            mesh = self._createCylinder(self._SupportSize,22.5,height)
            node_position = Vector(position.x,position.y,position.z)
        else:
            node.setName("CustomSupportCube")
            height = position.y-self._SupportSize/2+self._SupportSize*0.1
            mesh =  self._createCube(self._SupportSize,height)
            node_position = Vector(position.x,position.y-self._SupportSize/2+self._SupportSize*0.1,position.z)
        node.setMeshData(mesh.build())

        active_build_plate = CuraApplication.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()

        for key in ["support_mesh", "support_mesh_drop_down"]:
            definition = stack.getSettingDefinition(key)
            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 support 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(node_position, CuraSceneNode.TransformSpace.World)

        CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
Ejemplo n.º 16
0
    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())
        node.setPosition(position)

        active_build_plate = Application.getInstance().getMultiBuildPlateModel(
        ).activeBuildPlate

        node.addDecorator(SettingOverrideDecorator())
        node.addDecorator(BuildPlateDecorator(active_build_plate))
        node.addDecorator(SliceableObjectDecorator())

        stack = node.callDecoration(
            "getStack")  # created by SettingOverrideDecorator
        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)

        root = self._controller.getScene().getRoot()

        op = GroupedOperation()
        # First add the node to the scene, so it gets the expected transform
        op.addOperation(AddSceneNodeOperation(node, root))
        op.addOperation(SetParentOperation(node, parent))
        op.push()

        Application.getInstance().getController().getScene().sceneChanged.emit(
            node)
Ejemplo n.º 17
0
    def _node(self, mesh, settings):
        node = CuraSceneNode()
        node.setMeshData(mesh)
        node.setSelectable(True)
        node.addDecorator(SliceableObjectDecorator())

        if len(settings) > 0:
            node.addDecorator(SettingOverrideDecorator())
            stack = node.callDecoration('getStack')
            top = stack.getTop()

            for k, v in settings.items():
                if k == 'extruder':
                    node.callDecoration('setActiveExtruder', v)
                else:
                    definition = stack.getSettingDefinition(k)
                    instance = SettingInstance(definition, top)
                    instance.setProperty("value", v)
                    instance.resetState()
                    top.addInstance(instance)

        Logger.log('d', 'node: {0}'.format(node))
        return node
Ejemplo n.º 18
0
    def setMeshType(self, mesh_type: str) -> bool:
        """Returns True when the mesh_type was changed, False when current mesh_type == mesh_type"""

        old_mesh_type = self.getMeshType()
        if old_mesh_type == mesh_type:
            return False

        selected_object = Selection.getSelectedObject(0)
        if selected_object is None:
            Logger.log(
                "w",
                "Tried setting the mesh type of the selected object, but no object was selected"
            )
            return False

        stack = selected_object.callDecoration(
            "getStack"
        )  #Don't try to get the active extruder since it may be None anyway.
        if not stack:
            selected_object.addDecorator(SettingOverrideDecorator())
            stack = selected_object.callDecoration("getStack")

        settings_visibility_changed = False
        settings = stack.getTop()
        for property_key in [
                "infill_mesh", "cutting_mesh", "support_mesh",
                "anti_overhang_mesh"
        ]:
            if property_key != mesh_type:
                if settings.getInstance(property_key):
                    settings.removeInstance(property_key)
            else:
                if not (settings.getInstance(property_key)
                        and settings.getProperty(property_key, "value")):
                    definition = stack.getSettingDefinition(property_key)
                    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)

        for property_key in [
                "top_bottom_thickness", "wall_thickness", "wall_line_count"
        ]:
            if mesh_type == "infill_mesh":
                if settings.getInstance(property_key) is None:
                    definition = stack.getSettingDefinition(property_key)
                    new_instance = SettingInstance(definition, settings)
                    # We just want the wall_line count to be there in case it was overriden in the global stack.
                    # as such, we don't need to set a value.
                    if property_key != "wall_line_count":
                        new_instance.setProperty("value", 0)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    settings_visibility_changed = True

            elif old_mesh_type == "infill_mesh" and settings.getInstance(
                    property_key) and (settings.getProperty(
                        property_key, "value") == 0
                                       or property_key == "wall_line_count"):
                settings.removeInstance(property_key)
                settings_visibility_changed = True

        if settings_visibility_changed:
            self.visibility_handler.forceVisibilityChanged()

        self.propertyChanged.emit()
        return True
Ejemplo n.º 19
0
    def run(self) -> None:
        if self._build_plate_number is None:
            self.setResult(StartJobResult.Error)
            return

        stack = SteSlicerApplication.getInstance().getGlobalContainerStack()
        if not stack:
            self.setResult(StartJobResult.Error)
            return

        # Don't slice if there is a setting with an error value.
        if SteSlicerApplication.getInstance().getMachineManager(
        ).stacksHaveErrors:
            self.setResult(StartJobResult.SettingError)
            return

        if SteSlicerApplication.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 SteSlicerApplication.getInstance().getMachineManager().variantBuildplateCompatible and \
                not SteSlicerApplication.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.
        # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
        for node in DepthFirstIterator(self._scene.getRoot()):
            if not isinstance(node,
                              SteSlicerSceneNode) or not node.isSelectable():
                continue

            if self._checkStackForErrors(node.callDecoration("getStack")):
                self.setResult(StartJobResult.ObjectSettingError)
                return

        with self._scene.getSceneLock():
            # Remove old layer data.
            # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
            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 = []
            printing_mode = stack.getProperty("printing_mode", "value")
            if printing_mode == "classic":
                if stack.getProperty("print_sequence",
                                     "value") == "one_at_a_time":
                    # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
                    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
                    # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
                    for node in DepthFirstIterator(self._scene.getRoot()):
                        if node.callDecoration(
                                "isSliceable") 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:
                                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)
            elif printing_mode in ["cylindrical_full", "spherical_full"]:
                temp_list = []
                has_printing_mesh = False

                for node in DepthFirstIterator(
                        self._scene.getRoot()
                ):  # type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
                    if node.callDecoration("isSliceable") 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:
                            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()

            else:
                self.setResult(StartJobResult.ObjectSettingError)
                return

        if temp_list and printing_mode in [
                "cylindrical_full", "spherical_full"
        ]:
            cut_list = []
            for node in temp_list:
                if printing_mode == "cylindrical_full":
                    radius = SteSlicerApplication.getInstance(
                    ).getGlobalContainerStack().getProperty(
                        "cylindrical_mode_base_diameter", "value") / 2
                    height = node.getBoundingBox().height * 2
                    cutting_mesh = trimesh.primitives.Cylinder(radius=radius,
                                                               height=height,
                                                               sections=64)
                    cutting_mesh.apply_transform(
                        trimesh.transformations.rotation_matrix(
                            numpy.pi / 2, [1, 0, 0]))
                elif printing_mode == "spherical_full":
                    radius = SteSlicerApplication.getInstance(
                    ).getGlobalContainerStack().getProperty(
                        "spherical_mode_base_radius", "value")
                    cutting_mesh = trimesh.primitives.Sphere(radius=radius,
                                                             subdivisions=3)
                else:
                    cutting_mesh = None

                mesh_data = node.getMeshData()
                if mesh_data.hasIndices():
                    faces = mesh_data.getIndices()
                else:
                    num_verts = mesh_data.getVertexCount()
                    faces = numpy.empty((int(num_verts / 3 + 1), 3),
                                        numpy.int32)
                    for i in range(0, num_verts - 2, 3):
                        faces[int(i / 3):] = [i, i + 1, i + 2]
                verts = mesh_data.getVertices()
                rot_scale = node.getWorldTransformation().getTransposed(
                ).getData()[0:3, 0:3]
                translate = node.getWorldTransformation().getData()[:3, 3]
                verts = verts.dot(rot_scale)
                verts += translate
                mesh = trimesh.Trimesh(vertices=verts, faces=faces)
                try:
                    mesh.fill_holes()
                    mesh.fix_normals()
                    cutting_result = mesh.intersection(cutting_mesh,
                                                       engine="scad")
                    if cutting_result:
                        cutting_result.fill_holes()
                        cutting_result.fix_normals()

                        data = MeshData.MeshData(
                            vertices=cutting_result.vertices.astype('float32'),
                            normals=cutting_result.face_normals.astype(
                                'float32'),
                            indices=cutting_result.faces.astype('int64'))
                        cutting_node = SteSlicerSceneNode(
                            node.getParent(), no_setting_override=True)
                        cutting_node.addDecorator(
                            node.getDecorator(SettingOverrideDecorator))
                except Exception as e:
                    Logger.log("e", "Failed to intersect model! %s", e)
                    cutting_result = cutting_mesh
                    if cutting_result:
                        cutting_result.fill_holes()
                        cutting_result.fix_normals()

                        data = MeshData.MeshData(
                            vertices=cutting_result.vertices.astype('float32'),
                            normals=cutting_result.face_normals.astype(
                                'float32'),
                            indices=cutting_result.faces.astype('int64'))
                        cutting_node = SteSlicerSceneNode(
                            node.getParent(), no_setting_override=True)
                        stack = cutting_node.callDecoration(
                            "getStack"
                        )  # Don't try to get the active extruder since it may be None anyway.
                        if not stack:
                            cutting_node.addDecorator(
                                SettingOverrideDecorator())
                            stack = cutting_node.callDecoration("getStack")
                        settings = stack.getTop()
                        if not (settings.getInstance("support_mesh") and
                                settings.getProperty("support_mesh", "value")):
                            definition = stack.getSettingDefinition(
                                "support_mesh")
                            new_instance = SettingInstance(
                                definition, settings)
                            new_instance.setProperty("value",
                                                     True,
                                                     emit_signals=False)
                            # Ensure that the state is not seen as a user state.
                            new_instance.resetState()
                            settings.addInstance(new_instance)
                if cutting_node is not None:
                    cutting_node.setName("cut_" + node.getName())
                    cutting_node.setMeshData(data)

                    cut_list.append(cutting_node)

            object_groups.append(cut_list)

        global_stack = SteSlicerApplication.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 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

        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:
            self._buildExtruderMessage(extruder_stack)

        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:
                mesh_data = object.getMeshData()
                rot_scale = object.getWorldTransformation().getTransposed(
                ).getData()[0:3, 0:3]
                translate = object.getWorldTransformation().getData()[:3, 3]

                # This effectively performs a limited form of MeshData.getTransformed that ignores normals.
                verts = mesh_data.getVertices()
                verts = verts.dot(rot_scale)
                if printing_mode == "classic":
                    verts += translate

                # 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

                self._handlePerObjectSettings(object, obj)

                Job.yieldThread()

        self.setResult(StartJobResult.Finished)
Ejemplo n.º 20
0
    def importProfile(self, file_name):
        Logger.log("d", "Attempting to import profile %s", file_name)
        if not file_name:
            return {
                "status":
                "error",
                "message":
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename> or <message>!",
                    "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
                    file_name, "Invalid path")
            }

        plugin_registry = PluginRegistry.getInstance()
        extension = file_name.split(".")[-1]

        global_container_stack = Application.getInstance(
        ).getGlobalContainerStack()
        if not global_container_stack:
            return

        machine_extruders = list(
            ExtruderManager.getInstance().getMachineExtruders(
                global_container_stack.getId()))
        machine_extruders.sort(key=lambda k: k.getMetaDataEntry("position"))

        for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
            if meta_data["profile_reader"][0]["extension"] != extension:
                continue
            profile_reader = plugin_registry.getPluginObject(plugin_id)
            try:
                profile_or_list = profile_reader.read(
                    file_name)  # Try to open the file with the profile reader.
            except Exception as e:
                # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                Logger.log(
                    "e",
                    "Failed to import profile from %s: %s while using profile reader. Got exception %s",
                    file_name, profile_reader.getPluginId(), str(e))
                return {
                    "status":
                    "error",
                    "message":
                    catalog.i18nc(
                        "@info:status Don't translate the XML tags <filename> or <message>!",
                        "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
                        file_name, "\n" + str(e))
                }

            if profile_or_list:
                # Ensure it is always a list of profiles
                if not isinstance(profile_or_list, list):
                    profile_or_list = [profile_or_list]

                # First check if this profile is suitable for this machine
                global_profile = None
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                else:
                    for profile in profile_or_list:
                        if not profile.getMetaDataEntry("extruder"):
                            global_profile = profile
                            break
                if not global_profile:
                    Logger.log(
                        "e",
                        "Incorrect profile [%s]. Could not find global profile",
                        file_name)
                    return {
                        "status":
                        "error",
                        "message":
                        catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename> or <message>!",
                            "This profile <filename>{0}</filename> contains incorrect data, could not import it.",
                            file_name)
                    }
                profile_definition = global_profile.getMetaDataEntry(
                    "definition")
                expected_machine_definition = "fdmprinter"
                if parseBool(
                        global_container_stack.getMetaDataEntry(
                            "has_machine_quality", "False")):
                    expected_machine_definition = global_container_stack.getMetaDataEntry(
                        "quality_definition")
                    if not expected_machine_definition:
                        expected_machine_definition = global_container_stack.definition.getId(
                        )
                if expected_machine_definition is not None and profile_definition is not None and profile_definition != expected_machine_definition:
                    Logger.log(
                        "e",
                        "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile",
                        file_name, profile_definition,
                        expected_machine_definition)
                    return {
                        "status":
                        "error",
                        "message":
                        catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename> or <message>!",
                            "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.",
                            file_name, profile_definition,
                            expected_machine_definition)
                    }

                name_seed = os.path.splitext(os.path.basename(file_name))[0]
                new_name = self.uniqueName(name_seed)

                # Ensure it is always a list of profiles
                if type(profile_or_list) is not list:
                    profile_or_list = [profile_or_list]

                # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                    extruder_profiles = []
                    for idx, extruder in enumerate(
                            global_container_stack.extruders.values()):
                        profile_id = ContainerRegistry.getInstance(
                        ).uniqueName(global_container_stack.getId() +
                                     "_extruder_" + str(idx + 1))
                        profile = InstanceContainer(profile_id)
                        profile.setName(global_profile.getName())
                        profile.addMetaDataEntry(
                            "setting_version", CuraApplication.SettingVersion)
                        profile.addMetaDataEntry("type", "quality_changes")
                        profile.addMetaDataEntry(
                            "definition",
                            global_profile.getMetaDataEntry("definition"))
                        profile.addMetaDataEntry(
                            "quality_type",
                            global_profile.getMetaDataEntry("quality_type"))
                        profile.addMetaDataEntry("extruder", extruder.getId())
                        profile.setDirty(True)
                        if idx == 0:
                            # move all per-extruder settings to the first extruder's quality_changes
                            for qc_setting_key in global_profile.getAllKeys():
                                settable_per_extruder = global_container_stack.getProperty(
                                    qc_setting_key, "settable_per_extruder")
                                if settable_per_extruder:
                                    setting_value = global_profile.getProperty(
                                        qc_setting_key, "value")

                                    setting_definition = global_container_stack.getSettingDefinition(
                                        qc_setting_key)
                                    new_instance = SettingInstance(
                                        setting_definition, profile)
                                    new_instance.setProperty(
                                        "value", setting_value)
                                    new_instance.resetState(
                                    )  # Ensure that the state is not seen as a user state.
                                    profile.addInstance(new_instance)
                                    profile.setDirty(True)

                                    global_profile.removeInstance(
                                        qc_setting_key, postpone_emit=True)
                        extruder_profiles.append(profile)

                    for profile in extruder_profiles:
                        profile_or_list.append(profile)

                # Import all profiles
                for profile_index, profile in enumerate(profile_or_list):
                    if profile_index == 0:
                        # This is assumed to be the global profile
                        profile_id = (
                            global_container_stack.getBottom().getId() + "_" +
                            name_seed).lower().replace(" ", "_")

                    elif profile_index < len(machine_extruders) + 1:
                        # This is assumed to be an extruder profile
                        extruder_id = Application.getInstance(
                        ).getMachineManager().getQualityDefinitionId(
                            machine_extruders[profile_index - 1].getBottom())
                        if not profile.getMetaDataEntry("extruder"):
                            profile.addMetaDataEntry("extruder", extruder_id)
                        else:
                            profile.setMetaDataEntry("extruder", extruder_id)
                        profile_id = (extruder_id + "_" +
                                      name_seed).lower().replace(" ", "_")

                    else:  #More extruders in the imported file than in the machine.
                        continue  #Delete the additional profiles.

                    result = self._configureProfile(profile, profile_id,
                                                    new_name)
                    if result is not None:
                        return {
                            "status":
                            "error",
                            "message":
                            catalog.i18nc(
                                "@info:status Don't translate the XML tags <filename> or <message>!",
                                "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
                                file_name, result)
                        }

                return {
                    "status":
                    "ok",
                    "message":
                    catalog.i18nc("@info:status",
                                  "Successfully imported profile {0}",
                                  profile_or_list[0].getName())
                }

            # This message is throw when the profile reader doesn't find any profile in the file
            return {
                "status":
                "error",
                "message":
                catalog.i18nc("@info:status",
                              "File {0} does not contain any valid profile.",
                              file_name)
            }

        # If it hasn't returned by now, none of the plugins loaded the profile successfully.
        return {
            "status":
            "error",
            "message":
            catalog.i18nc(
                "@info:status",
                "Profile {0} has an unknown file type or is corrupted.",
                file_name)
        }
Ejemplo n.º 21
0
    def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id, new_global_quality_changes = None, create_new_ids = True):
        new_extruder_id = extruder_id

        application = CuraApplication.getInstance()

        extruder_definitions = self.findDefinitionContainers(id = new_extruder_id)
        if not extruder_definitions:
            Logger.log("w", "Could not find definition containers for extruder %s", new_extruder_id)
            return

        extruder_definition = extruder_definitions[0]
        unique_name = self.uniqueName(machine.getName() + " " + new_extruder_id) if create_new_ids else machine.getName() + " " + new_extruder_id

        extruder_stack = ExtruderStack.ExtruderStack(unique_name)
        extruder_stack.setName(extruder_definition.getName())
        extruder_stack.setDefinition(extruder_definition)
        extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))

        # create a new definition_changes container for the extruder stack
        definition_changes_id = self.uniqueName(extruder_stack.getId() + "_settings") if create_new_ids else extruder_stack.getId() + "_settings"
        definition_changes_name = definition_changes_id
        definition_changes = InstanceContainer(definition_changes_id, parent = application)
        definition_changes.setName(definition_changes_name)
        definition_changes.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
        definition_changes.addMetaDataEntry("type", "definition_changes")
        definition_changes.addMetaDataEntry("definition", extruder_definition.getId())

        # move definition_changes settings if exist
        for setting_key in definition_changes.getAllKeys():
            if machine.definition.getProperty(setting_key, "settable_per_extruder"):
                setting_value = machine.definitionChanges.getProperty(setting_key, "value")
                if setting_value is not None:
                    # move it to the extruder stack's definition_changes
                    setting_definition = machine.getSettingDefinition(setting_key)
                    new_instance = SettingInstance(setting_definition, definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    definition_changes.addInstance(new_instance)
                    definition_changes.setDirty(True)

                    machine.definitionChanges.removeInstance(setting_key, postpone_emit = True)

        self.addContainer(definition_changes)
        extruder_stack.setDefinitionChanges(definition_changes)

        # create empty user changes container otherwise
        user_container_id = self.uniqueName(extruder_stack.getId() + "_user") if create_new_ids else extruder_stack.getId() + "_user"
        user_container_name = user_container_id
        user_container = InstanceContainer(user_container_id, parent = application)
        user_container.setName(user_container_name)
        user_container.addMetaDataEntry("type", "user")
        user_container.addMetaDataEntry("machine", machine.getId())
        user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
        user_container.setDefinition(machine.definition.getId())
        user_container.setMetaDataEntry("position", extruder_stack.getMetaDataEntry("position"))

        if machine.userChanges:
            # for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
            # container to the extruder stack.
            for user_setting_key in machine.userChanges.getAllKeys():
                settable_per_extruder = machine.getProperty(user_setting_key, "settable_per_extruder")
                if settable_per_extruder:
                    setting_value = machine.getProperty(user_setting_key, "value")

                    setting_definition = machine.getSettingDefinition(user_setting_key)
                    new_instance = SettingInstance(setting_definition, definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                    user_container.addInstance(new_instance)
                    user_container.setDirty(True)

                    machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)

        self.addContainer(user_container)
        extruder_stack.setUserChanges(user_container)

        empty_variant = application.empty_variant_container
        empty_material = application.empty_material_container
        empty_quality = application.empty_quality_container

        if machine.variant.getId() not in ("empty", "empty_variant"):
            variant = machine.variant
        else:
            variant = empty_variant
        extruder_stack.variant = variant

        if machine.material.getId() not in ("empty", "empty_material"):
            material = machine.material
        else:
            material = empty_material
        extruder_stack.material = material

        if machine.quality.getId() not in ("empty", "empty_quality"):
            quality = machine.quality
        else:
            quality = empty_quality
        extruder_stack.quality = quality

        machine_quality_changes = machine.qualityChanges
        if new_global_quality_changes is not None:
            machine_quality_changes = new_global_quality_changes

        if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"):
            extruder_quality_changes_container = self.findInstanceContainers(name = machine_quality_changes.getName(), extruder = extruder_id)
            if extruder_quality_changes_container:
                extruder_quality_changes_container = extruder_quality_changes_container[0]

                quality_changes_id = extruder_quality_changes_container.getId()
                extruder_stack.qualityChanges = self.findInstanceContainers(id = quality_changes_id)[0]
            else:
                # Some extruder quality_changes containers can be created at runtime as files in the qualities
                # folder. Those files won't be loaded in the registry immediately. So we also need to search
                # the folder to see if the quality_changes exists.
                extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine_quality_changes.getName())
                if extruder_quality_changes_container:
                    quality_changes_id = extruder_quality_changes_container.getId()
                    extruder_quality_changes_container.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
                    extruder_stack.qualityChanges = self.findInstanceContainers(id = quality_changes_id)[0]
                else:
                    # if we still cannot find a quality changes container for the extruder, create a new one
                    container_name = machine_quality_changes.getName()
                    container_id = self.uniqueName(extruder_stack.getId() + "_qc_" + container_name)
                    extruder_quality_changes_container = InstanceContainer(container_id, parent = application)
                    extruder_quality_changes_container.setName(container_name)
                    extruder_quality_changes_container.addMetaDataEntry("type", "quality_changes")
                    extruder_quality_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
                    extruder_quality_changes_container.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
                    extruder_quality_changes_container.addMetaDataEntry("quality_type", machine_quality_changes.getMetaDataEntry("quality_type"))
                    extruder_quality_changes_container.setDefinition(machine_quality_changes.getDefinition().getId())

                    self.addContainer(extruder_quality_changes_container)
                    extruder_stack.qualityChanges = extruder_quality_changes_container

            if not extruder_quality_changes_container:
                Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]",
                           machine_quality_changes.getName(), extruder_stack.getId())
            else:
                # move all per-extruder settings to the extruder's quality changes
                for qc_setting_key in machine_quality_changes.getAllKeys():
                    settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        setting_value = machine_quality_changes.getProperty(qc_setting_key, "value")

                        setting_definition = machine.getSettingDefinition(qc_setting_key)
                        new_instance = SettingInstance(setting_definition, definition_changes)
                        new_instance.setProperty("value", setting_value)
                        new_instance.resetState()  # Ensure that the state is not seen as a user state.
                        extruder_quality_changes_container.addInstance(new_instance)
                        extruder_quality_changes_container.setDirty(True)

                        machine_quality_changes.removeInstance(qc_setting_key, postpone_emit=True)
        else:
            extruder_stack.qualityChanges = self.findInstanceContainers(id = "empty_quality_changes")[0]

        self.addContainer(extruder_stack)

        # Also need to fix the other qualities that are suitable for this machine. Those quality changes may still have
        # per-extruder settings in the container for the machine instead of the extruder.
        if machine_quality_changes.getId() not in ("empty", "empty_quality_changes"):
            quality_changes_machine_definition_id = machine_quality_changes.getDefinition().getId()
        else:
            whole_machine_definition = machine.definition
            machine_entry = machine.definition.getMetaDataEntry("machine")
            if machine_entry is not None:
                container_registry = ContainerRegistry.getInstance()
                whole_machine_definition = container_registry.findDefinitionContainers(id = machine_entry)[0]

            quality_changes_machine_definition_id = "fdmprinter"
            if whole_machine_definition.getMetaDataEntry("has_machine_quality"):
                quality_changes_machine_definition_id = machine.definition.getMetaDataEntry("quality_definition",
                                                                                            whole_machine_definition.getId())
        qcs = self.findInstanceContainers(type = "quality_changes", definition = quality_changes_machine_definition_id)
        qc_groups = {}  # map of qc names -> qc containers
        for qc in qcs:
            qc_name = qc.getName()
            if qc_name not in qc_groups:
                qc_groups[qc_name] = []
            qc_groups[qc_name].append(qc)
            # try to find from the quality changes cura directory too
            quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine_quality_changes.getName())
            if quality_changes_container:
                qc_groups[qc_name].append(quality_changes_container)

        for qc_name, qc_list in qc_groups.items():
            qc_dict = {"global": None, "extruders": []}
            for qc in qc_list:
                extruder_position = qc.getMetaDataEntry("position")
                if extruder_position is not None:
                    qc_dict["extruders"].append(qc)
                else:
                    qc_dict["global"] = qc
            if qc_dict["global"] is not None and len(qc_dict["extruders"]) == 1:
                # move per-extruder settings
                for qc_setting_key in qc_dict["global"].getAllKeys():
                    settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        setting_value = qc_dict["global"].getProperty(qc_setting_key, "value")

                        setting_definition = machine.getSettingDefinition(qc_setting_key)
                        new_instance = SettingInstance(setting_definition, definition_changes)
                        new_instance.setProperty("value", setting_value)
                        new_instance.resetState()  # Ensure that the state is not seen as a user state.
                        qc_dict["extruders"][0].addInstance(new_instance)
                        qc_dict["extruders"][0].setDirty(True)

                        qc_dict["global"].removeInstance(qc_setting_key, postpone_emit=True)

        # Set next stack at the end
        extruder_stack.setNextStack(machine)

        return extruder_stack
Ejemplo n.º 22
0
    def importProfile(self, file_name):
        Logger.log("d", "Attempting to import profile %s", file_name)
        if not file_name:
            return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")}

        plugin_registry = PluginRegistry.getInstance()
        extension = file_name.split(".")[-1]

        global_stack = Application.getInstance().getGlobalContainerStack()
        if not global_stack:
            return

        machine_extruders = []
        for position in sorted(global_stack.extruders):
            machine_extruders.append(global_stack.extruders[position])

        for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
            if meta_data["profile_reader"][0]["extension"] != extension:
                continue
            profile_reader = plugin_registry.getPluginObject(plugin_id)
            try:
                profile_or_list = profile_reader.read(file_name)  # Try to open the file with the profile reader.
            except NoProfileException:
                return { "status": "ok", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "No custom profile to import in file <filename>{0}</filename>", file_name)}
            except Exception as e:
                # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e))
                return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "\n" + str(e))}

            if profile_or_list:
                # Ensure it is always a list of profiles
                if not isinstance(profile_or_list, list):
                    profile_or_list = [profile_or_list]

                # First check if this profile is suitable for this machine
                global_profile = None
                extruder_profiles = []
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                else:
                    for profile in profile_or_list:
                        if not profile.getMetaDataEntry("position"):
                            global_profile = profile
                        else:
                            extruder_profiles.append(profile)
                extruder_profiles = sorted(extruder_profiles, key = lambda x: int(x.getMetaDataEntry("position")))
                profile_or_list = [global_profile] + extruder_profiles

                if not global_profile:
                    Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name)
                    return { "status": "error",
                             "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)}
                profile_definition = global_profile.getMetaDataEntry("definition")

                # Make sure we have a profile_definition in the file:
                if profile_definition is None:
                    break
                machine_definition = self.findDefinitionContainers(id = profile_definition)
                if not machine_definition:
                    Logger.log("e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition)
                    return {"status": "error",
                            "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)
                            }
                machine_definition = machine_definition[0]

                # Get the expected machine definition.
                # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode...
                profile_definition = getMachineDefinitionIDForQualitySearch(machine_definition)
                expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_stack.definition)

                # And check if the profile_definition matches either one (showing error if not):
                if profile_definition != expected_machine_definition:
                    Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition)
                    return { "status": "error",
                             "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)}

                # Fix the global quality profile's definition field in case it's not correct
                global_profile.setMetaDataEntry("definition", expected_machine_definition)
                quality_name = global_profile.getName()
                quality_type = global_profile.getMetaDataEntry("quality_type")

                name_seed = os.path.splitext(os.path.basename(file_name))[0]
                new_name = self.uniqueName(name_seed)

                # Ensure it is always a list of profiles
                if type(profile_or_list) is not list:
                    profile_or_list = [profile_or_list]

                # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                    extruder_profiles = []
                    for idx, extruder in enumerate(global_stack.extruders.values()):
                        profile_id = ContainerRegistry.getInstance().uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1))
                        profile = InstanceContainer(profile_id)
                        profile.setName(quality_name)
                        profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
                        profile.addMetaDataEntry("type", "quality_changes")
                        profile.addMetaDataEntry("definition", expected_machine_definition)
                        profile.addMetaDataEntry("quality_type", quality_type)
                        profile.addMetaDataEntry("position", "0")
                        profile.setDirty(True)
                        if idx == 0:
                            # move all per-extruder settings to the first extruder's quality_changes
                            for qc_setting_key in global_profile.getAllKeys():
                                settable_per_extruder = global_stack.getProperty(qc_setting_key,
                                                                                           "settable_per_extruder")
                                if settable_per_extruder:
                                    setting_value = global_profile.getProperty(qc_setting_key, "value")

                                    setting_definition = global_stack.getSettingDefinition(qc_setting_key)
                                    new_instance = SettingInstance(setting_definition, profile)
                                    new_instance.setProperty("value", setting_value)
                                    new_instance.resetState()  # Ensure that the state is not seen as a user state.
                                    profile.addInstance(new_instance)
                                    profile.setDirty(True)

                                    global_profile.removeInstance(qc_setting_key, postpone_emit=True)
                        extruder_profiles.append(profile)

                    for profile in extruder_profiles:
                        profile_or_list.append(profile)

                # Import all profiles
                for profile_index, profile in enumerate(profile_or_list):
                    if profile_index == 0:
                        # This is assumed to be the global profile
                        profile_id = (global_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")

                    elif profile_index < len(machine_extruders) + 1:
                        # This is assumed to be an extruder profile
                        extruder_id = machine_extruders[profile_index - 1].definition.getId()
                        extruder_position = str(profile_index - 1)
                        if not profile.getMetaDataEntry("position"):
                            profile.addMetaDataEntry("position", extruder_position)
                        else:
                            profile.setMetaDataEntry("position", extruder_position)
                        profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_")

                    else: #More extruders in the imported file than in the machine.
                        continue #Delete the additional profiles.

                    result = self._configureProfile(profile, profile_id, new_name, expected_machine_definition)
                    if result is not None:
                        return {"status": "error", "message": catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename> or <message>!",
                            "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>",
                            file_name, result)}

                return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}

            # This message is throw when the profile reader doesn't find any profile in the file
            return {"status": "error", "message": catalog.i18nc("@info:status", "File {0} does not contain any valid profile.", file_name)}

        # If it hasn't returned by now, none of the plugins loaded the profile successfully.
        return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name)}
Ejemplo n.º 23
0
    def _constructSupport(self, buffer: QImage) -> None:
        depth_pass = PickingPass(
            buffer.width(), buffer.height()
        )  #Instead of using the picking pass to pick for us, we need to bulk-pick digits so do this in Numpy.
        depth_pass.render()
        depth_image = depth_pass.getOutput()
        camera = CuraApplication.getInstance().getController().getScene(
        ).getActiveCamera()

        #to_support = qimage2ndarray.raw_view(buffer)
        #to_support= _qimageview(_qt.QImage(buffer))
        to_support = self._raw_view(buffer)

        #depth = qimage2ndarray.recarray_view(depth_image)
        depth = self._recarray_view(depth_image)

        depth.a = 0  #Discard alpha channel.
        depth = depth.view(dtype=_np.int32).astype(
            _np.float32
        ) / 1000  #Conflate the R, G and B channels to one 24-bit (cast to 32) float. Divide by 1000 to get mm.
        support_positions_2d = _np.array(
            _np.where(_np.bitwise_and(to_support == 255, depth < 16777))
        )  #All the 2D coordinates on the screen where we want support. The 16777 is for points that don't land on a model.
        support_depths = _np.take(
            depth, support_positions_2d[0, :] * depth.shape[1] +
            support_positions_2d[1, :])  #The depth at those pixels.
        support_positions_2d = support_positions_2d.transpose(
        )  #We want rows with pixels, not columns with pixels.
        if len(support_positions_2d) == 0:
            Logger.log(
                "i",
                "Support was not drawn on the surface of any objects. Not creating support."
            )
            return
        support_positions_2d[:, [0, 1]] = support_positions_2d[:, [
            1, 0
        ]]  #Swap columns to get OpenGL's coordinate system.
        camera_viewport = _np.array(
            [camera.getViewportWidth(),
             camera.getViewportHeight()])
        support_positions_2d = support_positions_2d * 2.0 / camera_viewport - 1.0  #Scale to view coordinates (range -1 to 1).
        inverted_projection = _np.linalg.inv(
            camera.getProjectionMatrix().getData())
        transformation = camera.getWorldTransformation().getData()
        transformation[:,
                       1] = -transformation[:,
                                            1]  #Invert Z to get OpenGL's coordinate system.

        #For each pixel, get the near and far plane.
        near = _np.ndarray((support_positions_2d.shape[0], 4))
        near.fill(1)
        near[0:support_positions_2d.shape[0],
             0:support_positions_2d.shape[1]] = support_positions_2d
        near[:, 2].fill(-1)
        near = _np.dot(inverted_projection, near.transpose())
        near = _np.dot(transformation, near)
        near = near[0:3] / near[3]
        far = _np.ndarray((support_positions_2d.shape[0], 4))
        far.fill(1)
        far[0:support_positions_2d.shape[0],
            0:support_positions_2d.shape[1]] = support_positions_2d
        far = _np.dot(inverted_projection, far.transpose())
        far = _np.dot(transformation, far)
        far = far[0:3] / far[3]

        #Direction is from near plane pixel to far plane pixel, normalised.
        direction = near - far
        direction /= _np.linalg.norm(direction, axis=0)

        #Final position is in the direction of the pixel, moving with <depth> mm away from the camera position.
        support_positions_3d = (
            support_depths - 1
        ) * direction  #We want the support to appear just before the surface, not behind the surface, so - 1.
        support_positions_3d = support_positions_3d.transpose()
        camera_position_data = camera.getPosition().getData()
        support_positions_3d = support_positions_3d + camera_position_data

        #Create the vertices for the 3D mesh.
        #This mesh consists of a diamond-shape for each position that we traced.
        n = support_positions_3d.shape[0]
        Logger.log(
            "i",
            "Adding support in {num_pixels} locations.".format(num_pixels=n))
        vertices = support_positions_3d.copy().astype(_np.float32)
        vertices = _np.resize(vertices,
                              (n * 6, support_positions_3d.shape[1]
                               ))  #Resize will repeat all coordinates 6 times.
        #For each position, create a diamond shape around the position with 6 vertices.
        vertices[
            n * 0:n * 1,
            0] -= support_depths * 0.001 * self.globule_size  #First corner (-x, +y).
        vertices[n * 0:n * 1, 2] += support_depths * 0.001 * self.globule_size
        vertices[
            n * 1:n * 2,
            0] += support_depths * 0.001 * self.globule_size  #Second corner (+x, +y).
        vertices[n * 1:n * 2, 2] += support_depths * 0.001 * self.globule_size
        vertices[
            n * 2:n * 3,
            0] -= support_depths * 0.001 * self.globule_size  #Third corner (-x, -y).
        vertices[n * 2:n * 3, 2] -= support_depths * 0.001 * self.globule_size
        vertices[
            n * 3:n * 4,
            0] += support_depths * 0.001 * self.globule_size  #Fourth corner (+x, -y)
        vertices[n * 3:n * 4, 2] -= support_depths * 0.001 * self.globule_size
        vertices[n * 4:n * 5,
                 1] += support_depths * 0.001 * self.globule_size  #Top side.
        vertices[
            n * 5:n * 6,
            1] -= support_depths * 0.001 * self.globule_size  #Bottom side.

        #Create the faces of the diamond.
        indices = _np.arange(n, dtype=_np.int32)
        indices = _np.kron(indices, _np.ones(
            (3, 1))).astype(_np.int32).transpose()
        indices = _np.resize(
            indices, (n * 8, 3)
        )  #Creates 8 triangles using 3 times the same vertex, for each position: [[0, 0, 0], [1, 1, 1], ... , [0, 0, 0], [1, 1, 1], ... ]

        #indices[n * 0: n * 1, 0] += n * 0 #First corner.
        indices[n * 0:n * 1, 1] += n * 1  #Second corner.
        indices[n * 0:n * 1, 2] += n * 4  #Top side.

        indices[n * 1:n * 2, 0] += n * 1  #Second corner.
        indices[n * 1:n * 2, 1] += n * 3  #Fourth corner.
        indices[n * 1:n * 2, 2] += n * 4  #Top side.

        indices[n * 2:n * 3, 0] += n * 3  #Fourth corner.
        indices[n * 2:n * 3, 1] += n * 2  #Third corner.
        indices[n * 2:n * 3, 2] += n * 4  #Top side.

        indices[n * 3:n * 4, 0] += n * 2  #Third corner.
        #indices[n * 3: n * 4, 1] += n * 0 #First corner.
        indices[n * 3:n * 4, 2] += n * 4  #Top side.

        indices[n * 4:n * 5, 0] += n * 1  #Second corner.
        #indices[n * 4: n * 5, 1] += n * 0 #First corner.
        indices[n * 4:n * 5, 2] += n * 5  #Bottom side.

        indices[n * 5:n * 6, 0] += n * 3  #Fourth corner.
        indices[n * 5:n * 6, 1] += n * 1  #Second corner.
        indices[n * 5:n * 6, 2] += n * 5  #Bottom side.

        indices[n * 6:n * 7, 0] += n * 2  #Third corner.
        indices[n * 6:n * 7, 1] += n * 3  #Fourth corner.
        indices[n * 6:n * 7, 2] += n * 5  #Bottom side.

        #indices[n * 7: n * 8, 0] += n * 0 #First corner.
        indices[n * 7:n * 8, 1] += n * 2  #Third corner.
        indices[n * 7:n * 8, 2] += n * 5  #Bottom side.

        builder = MeshBuilder()
        builder.addVertices(vertices)
        builder.addIndices(indices)

        #Create the scene node.
        scene = CuraApplication.getInstance().getController().getScene()
        new_node = CuraSceneNode(parent=scene.getRoot(), name="BrushSupport")
        new_node.setSelectable(False)
        new_node.setMeshData(builder.build())
        new_node.addDecorator(
            BuildPlateDecorator(CuraApplication.getInstance().
                                getMultiBuildPlateModel().activeBuildPlate))
        new_node.addDecorator(SliceableObjectDecorator())
        operation = GroupedOperation()

        #Figure out which mesh this piece of support belongs to.
        #TODO: You can draw support in one stroke over multiple meshes. The support would belong to an arbitrary one of these.
        selection_pass = CuraApplication.getInstance().getRenderer(
        ).getRenderPass("selection")
        parent_id = selection_pass.getIdAtPosition(
            support_positions_2d[0][0], support_positions_2d[0]
            [1])  #Find the selection under the first support pixel.
        parent_node = scene.getRoot()
        if not parent_id:
            Logger.log("d", "Can't link custom support to any scene node.")
        else:
            for node in BreadthFirstIterator(scene.getRoot()):
                if id(node) == parent_id:
                    parent_node = node
                    break

        #Add the appropriate per-object settings.
        stack = new_node.callDecoration(
            "getStack"
        )  #Created by SettingOverrideDecorator that is automatically added to CuraSceneNode.
        settings = stack.getTop()
        support_mesh_instance = SettingInstance(
            stack.getSettingDefinition("support_mesh"), settings)
        support_mesh_instance.setProperty("value", True)
        support_mesh_instance.resetState()
        settings.addInstance(support_mesh_instance)
        drop_down_instance = SettingInstance(
            stack.getSettingDefinition("support_mesh_drop_down"), settings)
        drop_down_instance.setProperty("value", True)
        drop_down_instance.resetState()
        settings.addInstance(drop_down_instance)

        #Add the scene node to the scene (and allow for undo).
        operation.addOperation(
            AddSceneNodeOperation(new_node, scene.getRoot())
        )  #Set the parent to root initially, then change the parent, so that we don't have to alter the transformation.
        operation.addOperation(SetParentOperation(new_node, parent_node))
        operation.push()

        scene.sceneChanged.emit(new_node)
Ejemplo n.º 24
0
    def setMeshType(self, mesh_type: str) -> bool:
        """Returns True when the mesh_type was changed, False when current mesh_type == mesh_type"""

        old_mesh_type = self.getMeshType()
        if old_mesh_type == mesh_type:
            return False

        selected_object = Selection.getSelectedObject(0)
        if selected_object is None:
            Logger.log(
                "w",
                "Tried setting the mesh type of the selected object, but no object was selected"
            )
            return False

        stack = selected_object.callDecoration(
            "getStack"
        )  #Don't try to get the active extruder since it may be None anyway.
        if not stack:
            selected_object.addDecorator(SettingOverrideDecorator())
            stack = selected_object.callDecoration("getStack")

        settings_visibility_changed = False
        settings = stack.getTop()
        for property_key in [
                "infill_mesh", "cutting_mesh", "support_mesh",
                "anti_overhang_mesh"
        ]:
            if property_key != mesh_type:
                if settings.getInstance(property_key):
                    settings.removeInstance(property_key)
            else:
                if not (settings.getInstance(property_key)
                        and settings.getProperty(property_key, "value")):
                    definition = stack.getSettingDefinition(property_key)
                    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)

        # Override some settings to ensure that the infill mesh by default adds no skin or walls. Or remove them if not an infill mesh.
        specialized_settings = {
            "top_bottom_thickness":
            0,
            "top_thickness":
            "=top_bottom_thickness",
            "bottom_thickness":
            "=top_bottom_thickness",
            "top_layers":
            "=0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / resolveOrValue('layer_height'), 4))",
            "bottom_layers":
            "=0 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / resolveOrValue('layer_height'), 4))",
            "wall_thickness":
            0,
            "wall_line_count":
            "=max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1) if wall_thickness != 0 else 0"
        }
        for property_key in specialized_settings:
            if mesh_type == "infill_mesh":
                if settings.getInstance(property_key) is None:
                    definition = stack.getSettingDefinition(property_key)
                    new_instance = SettingInstance(definition, settings)
                    new_instance.setProperty(
                        "value", specialized_settings[property_key])
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    settings.addInstance(new_instance)
                    settings_visibility_changed = True

            elif old_mesh_type == "infill_mesh" and settings.getInstance(
                    property_key) and property_key in specialized_settings:
                settings.removeInstance(property_key)
                settings_visibility_changed = True

        if settings_visibility_changed:
            self.visibility_handler.forceVisibilityChanged()

        self.propertyChanged.emit()
        return True
Ejemplo n.º 25
0
    def importProfile(self, file_name: str) -> Dict[str, str]:
        Logger.log("d", "Attempting to import profile %s", file_name)
        if not file_name:
            return {
                "status":
                "error",
                "message":
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename>!",
                    "Failed to import profile from <filename>{0}</filename>: {1}",
                    file_name, "Invalid path")
            }

        global_stack = Application.getInstance().getGlobalContainerStack()
        if not global_stack:
            return {
                "status":
                "error",
                "message":
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename>!",
                    "Can't import profile from <filename>{0}</filename> before a printer is added.",
                    file_name)
            }

        machine_extruders = []
        for position in sorted(global_stack.extruders):
            machine_extruders.append(global_stack.extruders[position])

        plugin_registry = PluginRegistry.getInstance()
        extension = file_name.split(".")[-1]

        for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
            if meta_data["profile_reader"][0]["extension"] != extension:
                continue
            profile_reader = cast(ProfileReader,
                                  plugin_registry.getPluginObject(plugin_id))
            try:
                profile_or_list = profile_reader.read(
                    file_name)  # Try to open the file with the profile reader.
            except NoProfileException:
                return {
                    "status":
                    "ok",
                    "message":
                    catalog.i18nc(
                        "@info:status Don't translate the XML tags <filename>!",
                        "No custom profile to import in file <filename>{0}</filename>",
                        file_name)
                }
            except Exception as e:
                # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                Logger.log(
                    "e",
                    "Failed to import profile from %s: %s while using profile reader. Got exception %s",
                    file_name, profile_reader.getPluginId(), str(e))
                return {
                    "status":
                    "error",
                    "message":
                    catalog.i18nc(
                        "@info:status Don't translate the XML tags <filename>!",
                        "Failed to import profile from <filename>{0}</filename>:",
                        file_name) + "\n<message>" + str(e) + "</message>"
                }

            if profile_or_list:
                # Ensure it is always a list of profiles
                if not isinstance(profile_or_list, list):
                    profile_or_list = [profile_or_list]

                # First check if this profile is suitable for this machine
                global_profile = None
                extruder_profiles = []
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                else:
                    for profile in profile_or_list:
                        if not profile.getMetaDataEntry("position"):
                            global_profile = profile
                        else:
                            extruder_profiles.append(profile)
                extruder_profiles = sorted(
                    extruder_profiles,
                    key=lambda x: int(x.getMetaDataEntry("position")))
                profile_or_list = [global_profile] + extruder_profiles

                if not global_profile:
                    Logger.log(
                        "e",
                        "Incorrect profile [%s]. Could not find global profile",
                        file_name)
                    return {
                        "status":
                        "error",
                        "message":
                        catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename>!",
                            "This profile <filename>{0}</filename> contains incorrect data, could not import it.",
                            file_name)
                    }
                profile_definition = global_profile.getMetaDataEntry(
                    "definition")

                # Make sure we have a profile_definition in the file:
                if profile_definition is None:
                    break
                machine_definitions = self.findDefinitionContainers(
                    id=profile_definition)
                if not machine_definitions:
                    Logger.log(
                        "e",
                        "Incorrect profile [%s]. Unknown machine type [%s]",
                        file_name, profile_definition)
                    return {
                        "status":
                        "error",
                        "message":
                        catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename>!",
                            "This profile <filename>{0}</filename> contains incorrect data, could not import it.",
                            file_name)
                    }
                machine_definition = machine_definitions[0]

                # Get the expected machine definition.
                # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode...
                profile_definition = getMachineDefinitionIDForQualitySearch(
                    machine_definition)
                expected_machine_definition = getMachineDefinitionIDForQualitySearch(
                    global_stack.definition)

                # And check if the profile_definition matches either one (showing error if not):
                if profile_definition != expected_machine_definition:
                    Logger.log(
                        "e",
                        "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile",
                        file_name, profile_definition,
                        expected_machine_definition)
                    return {
                        "status":
                        "error",
                        "message":
                        catalog.i18nc(
                            "@info:status Don't translate the XML tags <filename>!",
                            "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.",
                            file_name, profile_definition,
                            expected_machine_definition)
                    }

                # Fix the global quality profile's definition field in case it's not correct
                global_profile.setMetaDataEntry("definition",
                                                expected_machine_definition)
                quality_name = global_profile.getName()
                quality_type = global_profile.getMetaDataEntry("quality_type")

                name_seed = os.path.splitext(os.path.basename(file_name))[0]
                new_name = self.uniqueName(name_seed)

                # Ensure it is always a list of profiles
                if type(profile_or_list) is not list:
                    profile_or_list = [profile_or_list]

                # Make sure that there are also extruder stacks' quality_changes, not just one for the global stack
                if len(profile_or_list) == 1:
                    global_profile = profile_or_list[0]
                    extruder_profiles = []
                    for idx, extruder in enumerate(
                            global_stack.extruders.values()):
                        profile_id = ContainerRegistry.getInstance(
                        ).uniqueName(global_stack.getId() + "_extruder_" +
                                     str(idx + 1))
                        profile = InstanceContainer(profile_id)
                        profile.setName(quality_name)
                        profile.setMetaDataEntry(
                            "setting_version", cura.CuraApplication.
                            CuraApplication.SettingVersion)
                        profile.setMetaDataEntry("type", "quality_changes")
                        profile.setMetaDataEntry("definition",
                                                 expected_machine_definition)
                        profile.setMetaDataEntry("quality_type", quality_type)
                        profile.setMetaDataEntry("position", "0")
                        profile.setDirty(True)
                        if idx == 0:
                            # Move all per-extruder settings to the first extruder's quality_changes
                            for qc_setting_key in global_profile.getAllKeys():
                                settable_per_extruder = global_stack.getProperty(
                                    qc_setting_key, "settable_per_extruder")
                                if settable_per_extruder:
                                    setting_value = global_profile.getProperty(
                                        qc_setting_key, "value")

                                    setting_definition = global_stack.getSettingDefinition(
                                        qc_setting_key)
                                    if setting_definition is not None:
                                        new_instance = SettingInstance(
                                            setting_definition, profile)
                                        new_instance.setProperty(
                                            "value", setting_value)
                                        new_instance.resetState(
                                        )  # Ensure that the state is not seen as a user state.
                                        profile.addInstance(new_instance)
                                        profile.setDirty(True)

                                    global_profile.removeInstance(
                                        qc_setting_key, postpone_emit=True)
                        extruder_profiles.append(profile)

                    for profile in extruder_profiles:
                        profile_or_list.append(profile)

                # Import all profiles
                for profile_index, profile in enumerate(profile_or_list):
                    if profile_index == 0:
                        # This is assumed to be the global profile
                        profile_id = (cast(ContainerInterface,
                                           global_stack.getBottom()).getId() +
                                      "_" + name_seed).lower().replace(
                                          " ", "_")

                    elif profile_index < len(machine_extruders) + 1:
                        # This is assumed to be an extruder profile
                        extruder_id = machine_extruders[profile_index -
                                                        1].definition.getId()
                        extruder_position = str(profile_index - 1)
                        if not profile.getMetaDataEntry("position"):
                            profile.setMetaDataEntry("position",
                                                     extruder_position)
                        else:
                            profile.setMetaDataEntry("position",
                                                     extruder_position)
                        profile_id = (extruder_id + "_" +
                                      name_seed).lower().replace(" ", "_")

                    else:  # More extruders in the imported file than in the machine.
                        continue  # Delete the additional profiles.

                    result = self._configureProfile(
                        profile, profile_id, new_name,
                        expected_machine_definition)
                    if result is not None:
                        return {
                            "status":
                            "error",
                            "message":
                            catalog.i18nc(
                                "@info:status Don't translate the XML tags <filename> or <message>!",
                                "Failed to import profile from <filename>{0}</filename>:",
                                file_name) + " <message>" + result +
                            "</message>"
                        }

                return {
                    "status":
                    "ok",
                    "message":
                    catalog.i18nc("@info:status",
                                  "Successfully imported profile {0}",
                                  profile_or_list[0].getName())
                }

            # This message is throw when the profile reader doesn't find any profile in the file
            return {
                "status":
                "error",
                "message":
                catalog.i18nc("@info:status",
                              "File {0} does not contain any valid profile.",
                              file_name)
            }

        # If it hasn't returned by now, none of the plugins loaded the profile successfully.
        return {
            "status":
            "error",
            "message":
            catalog.i18nc(
                "@info:status",
                "Profile {0} has an unknown file type or is corrupted.",
                file_name)
        }
Ejemplo n.º 26
0
    def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id):
        new_extruder_id = extruder_id

        extruder_definitions = self.findDefinitionContainers(
            id=new_extruder_id)
        if not extruder_definitions:
            Logger.log("w",
                       "Could not find definition containers for extruder %s",
                       new_extruder_id)
            return

        extruder_definition = extruder_definitions[0]
        unique_name = self.uniqueName(machine.getName() + " " +
                                      new_extruder_id)

        extruder_stack = ExtruderStack.ExtruderStack(unique_name)
        extruder_stack.setName(extruder_definition.getName())
        extruder_stack.setDefinition(extruder_definition)
        extruder_stack.addMetaDataEntry(
            "position", extruder_definition.getMetaDataEntry("position"))

        from cura.CuraApplication import CuraApplication

        # create a new definition_changes container for the extruder stack
        definition_changes_id = self.uniqueName(extruder_stack.getId() +
                                                "_settings")
        definition_changes_name = definition_changes_id
        definition_changes = InstanceContainer(definition_changes_id)
        definition_changes.setName(definition_changes_name)
        definition_changes.addMetaDataEntry("setting_version",
                                            CuraApplication.SettingVersion)
        definition_changes.addMetaDataEntry("type", "definition_changes")
        definition_changes.addMetaDataEntry("definition",
                                            extruder_definition.getId())

        # move definition_changes settings if exist
        for setting_key in definition_changes.getAllKeys():
            if machine.definition.getProperty(setting_key,
                                              "settable_per_extruder"):
                setting_value = machine.definitionChanges.getProperty(
                    setting_key, "value")
                if setting_value is not None:
                    # move it to the extruder stack's definition_changes
                    setting_definition = machine.getSettingDefinition(
                        setting_key)
                    new_instance = SettingInstance(setting_definition,
                                                   definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    definition_changes.addInstance(new_instance)
                    definition_changes.setDirty(True)

                    machine.definitionChanges.removeInstance(
                        setting_key, postpone_emit=True)

        self.addContainer(definition_changes)
        extruder_stack.setDefinitionChanges(definition_changes)

        # create empty user changes container otherwise
        user_container_id = self.uniqueName(extruder_stack.getId() + "_user")
        user_container_name = user_container_id
        user_container = InstanceContainer(user_container_id)
        user_container.setName(user_container_name)
        user_container.addMetaDataEntry("type", "user")
        user_container.addMetaDataEntry("machine", extruder_stack.getId())
        user_container.addMetaDataEntry("setting_version",
                                        CuraApplication.SettingVersion)
        user_container.setDefinition(machine.definition.getId())

        if machine.userChanges:
            # for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
            # container to the extruder stack.
            for user_setting_key in machine.userChanges.getAllKeys():
                settable_per_extruder = machine.getProperty(
                    user_setting_key, "settable_per_extruder")
                if settable_per_extruder:
                    setting_value = machine.getProperty(
                        user_setting_key, "value")

                    setting_definition = machine.getSettingDefinition(
                        user_setting_key)
                    new_instance = SettingInstance(setting_definition,
                                                   definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    user_container.addInstance(new_instance)
                    user_container.setDirty(True)

                    machine.userChanges.removeInstance(user_setting_key,
                                                       postpone_emit=True)

        self.addContainer(user_container)
        extruder_stack.setUserChanges(user_container)

        variant_id = "default"
        if machine.variant.getId() not in ("empty", "empty_variant"):
            variant_id = machine.variant.getId()
        else:
            variant_id = "empty_variant"
        extruder_stack.setVariantById(variant_id)

        material_id = "default"
        if machine.material.getId() not in ("empty", "empty_material"):
            material_id = machine.material.getId()
        else:
            material_id = "empty_material"
        extruder_stack.setMaterialById(material_id)

        quality_id = "default"
        if machine.quality.getId() not in ("empty", "empty_quality"):
            quality_id = machine.quality.getId()
        else:
            quality_id = "empty_quality"
        extruder_stack.setQualityById(quality_id)

        if machine.qualityChanges.getId() not in ("empty",
                                                  "empty_quality_changes"):
            extruder_quality_changes_container = self.findInstanceContainers(
                name=machine.qualityChanges.getName(), extruder=extruder_id)
            if extruder_quality_changes_container:
                extruder_quality_changes_container = extruder_quality_changes_container[
                    0]
                quality_changes_id = extruder_quality_changes_container.getId()
                extruder_stack.setQualityChangesById(quality_changes_id)
            else:
                # Some extruder quality_changes containers can be created at runtime as files in the qualities
                # folder. Those files won't be loaded in the registry immediately. So we also need to search
                # the folder to see if the quality_changes exists.
                extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder(
                    machine.qualityChanges.getName())
                if extruder_quality_changes_container:
                    quality_changes_id = extruder_quality_changes_container.getId(
                    )
                    extruder_stack.setQualityChangesById(quality_changes_id)

            if not extruder_quality_changes_container:
                Logger.log(
                    "w",
                    "Could not find quality_changes named [%s] for extruder [%s]",
                    machine.qualityChanges.getName(), extruder_stack.getId())
        else:
            extruder_stack.setQualityChangesById("empty_quality_changes")

        self.addContainer(extruder_stack)

        # Set next stack at the end
        extruder_stack.setNextStack(machine)

        return extruder_stack
Ejemplo n.º 27
0
    def _createSupportMesh(self, parent: CuraSceneNode, position: Vector , position2: Vector):
        node = CuraSceneNode()

        if self._SType == 'cylinder':
            node.setName("CustomSupportCylinder")
        elif self._SType == 'tube':
            node.setName("CustomSupportTube")
        elif self._SType == 'cube':
            node.setName("CustomSupportCube")
        elif self._SType == 'abutment':
            node.setName("CustomSupportAbutment")
        elif self._SType == 'freeform':
            node.setName("CustomSupportFreeForm")            
        else:
            node.setName("CustomSupportCustom")
            
        node.setSelectable(True)
        
        # long=Support Height
        long=position.y
                
                
        if self._SType == 'cylinder':
            # Cylinder creation Diameter , Increment angle 2°, length
            mesh = self._createCylinder(self._UseSize,self._MaxSize,2,long,self._UseAngle)
        elif self._SType == 'tube':
            # Tube creation Diameter , Diameter Int, Increment angle 2°, length
            mesh =  self._createTube(self._UseSize,self._MaxSize,self._UseISize,2,long,self._UseAngle)
        elif self._SType == 'cube':
            # Cube creation Size , length
            mesh =  self._createCube(self._UseSize,self._MaxSize,long,self._UseAngle)
        elif self._SType == 'freeform':
            # Cube creation Size , length
            mesh = MeshBuilder()  
            MName = self._SubType + ".stl"
            model_definition_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "models", MName)
            # Logger.log('d', 'Model_definition_path : ' + str(model_definition_path)) 
            load_mesh = trimesh.load(model_definition_path)
            origin = [0, 0, 0]
            DirX = [1, 0, 0]
            DirY = [0, 1, 0]
            DirZ = [0, 0, 1]
            load_mesh.apply_transform(trimesh.transformations.scale_matrix(self._UseSize, origin, DirX))
            load_mesh.apply_transform(trimesh.transformations.scale_matrix(self._UseSize, origin, DirY))   
            load_mesh.apply_transform(trimesh.transformations.scale_matrix(long, origin, DirZ)) 
            if self._MirrorSupport == True :   
                load_mesh.apply_transform(trimesh.transformations.rotation_matrix(math.radians(180), [0, 0, 1]))
            if self._UseYDirection == True :
                load_mesh.apply_transform(trimesh.transformations.rotation_matrix(math.radians(90), [0, 0, 1]))

            mesh =  self._toMeshData(load_mesh)
            
        elif self._SType == 'abutment':
            # Abutement creation Size , length , top
            if self._EqualizeHeights == True :
                Logger.log('d', 'SHeights : ' + str(self._SHeights)) 
                if self._SHeights==0 :
                    self._SHeights=position.y 
                top=self._UseSize+(self._SHeights-position.y)

            else:
                top=self._UseSize
                self._SHeights=0
            
            # Logger.log('d', 'top : ' + str(top))
            mesh =  self._createAbutment(self._UseSize,self._MaxSize,long,top,self._UseAngle,self._UseYDirection)
        else:           
            # Custom creation Size , P1 as vector P2 as vector
            # Get support_interface_height as extra distance 
            extruder_stack = self._application.getExtruderManager().getActiveExtruderStacks()[0]
            extra_top=extruder_stack.getProperty("support_interface_height", "value")            
            mesh =  self._createCustom(self._UseSize,self._MaxSize,position,position2,self._UseAngle,extra_top)

        # Mesh Freeform are loaded via trimesh doesn't aheve the Build method
        if self._SType != 'freeform':
            node.setMeshData(mesh.build())
        else:
            node.setMeshData(mesh)

        # test for init position
        node_transform = Matrix()
        node_transform.setToIdentity()
        node.setTransformation(node_transform)
        
        active_build_plate = CuraApplication.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()

        # Define the new mesh as "support_mesh" or "support_mesh_drop_down"
        # Must be set for this 2 types
        # for key in ["support_mesh", "support_mesh_drop_down"]:
        # Don't fix
        
        definition = stack.getSettingDefinition("support_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)

        definition = stack.getSettingDefinition("support_mesh_drop_down")
        new_instance = SettingInstance(definition, settings)
        new_instance.setProperty("value", False)
        new_instance.resetState()  # Ensure that the state is not seen as a user state.
        settings.addInstance(new_instance)

        global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()    
        
        s_p = global_container_stack.getProperty("support_type", "value")
        if s_p ==  'buildplate' :
            Message(text = "Info modification support_type new value : everywhere", title = catalog.i18nc("@info:title", "Custom Supports Cylinder")).show()
            Logger.log('d', 'support_type different : ' + str(s_p))
            # Define support_type=everywhere
            global_container_stack.setProperty("support_type", "value", 'everywhere')
            
        op = GroupedOperation()
        # First add node to the scene at the correct position/scale, before parenting, so the support 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)

        CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
Ejemplo n.º 28
0
    def addExtruderStackForSingleExtrusionMachine(
            self,
            machine,
            extruder_id,
            new_global_quality_changes=None,
            create_new_ids=True):
        new_extruder_id = extruder_id

        application = cura.CuraApplication.CuraApplication.getInstance()

        extruder_definitions = self.findDefinitionContainers(
            id=new_extruder_id)
        if not extruder_definitions:
            Logger.log("w",
                       "Could not find definition containers for extruder %s",
                       new_extruder_id)
            return

        extruder_definition = extruder_definitions[0]
        unique_name = self.uniqueName(
            machine.getName() + " " + new_extruder_id
        ) if create_new_ids else machine.getName() + " " + new_extruder_id

        extruder_stack = ExtruderStack.ExtruderStack(unique_name)
        extruder_stack.setName(extruder_definition.getName())
        extruder_stack.setDefinition(extruder_definition)
        extruder_stack.setMetaDataEntry(
            "position", extruder_definition.getMetaDataEntry("position"))

        # create a new definition_changes container for the extruder stack
        definition_changes_id = self.uniqueName(
            extruder_stack.getId() + "_settings"
        ) if create_new_ids else extruder_stack.getId() + "_settings"
        definition_changes_name = definition_changes_id
        definition_changes = InstanceContainer(definition_changes_id,
                                               parent=application)
        definition_changes.setName(definition_changes_name)
        definition_changes.setMetaDataEntry("setting_version",
                                            application.SettingVersion)
        definition_changes.setMetaDataEntry("type", "definition_changes")
        definition_changes.setMetaDataEntry("definition",
                                            extruder_definition.getId())

        # move definition_changes settings if exist
        for setting_key in definition_changes.getAllKeys():
            if machine.definition.getProperty(setting_key,
                                              "settable_per_extruder"):
                setting_value = machine.definitionChanges.getProperty(
                    setting_key, "value")
                if setting_value is not None:
                    # move it to the extruder stack's definition_changes
                    setting_definition = machine.getSettingDefinition(
                        setting_key)
                    new_instance = SettingInstance(setting_definition,
                                                   definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    definition_changes.addInstance(new_instance)
                    definition_changes.setDirty(True)

                    machine.definitionChanges.removeInstance(
                        setting_key, postpone_emit=True)

        self.addContainer(definition_changes)
        extruder_stack.setDefinitionChanges(definition_changes)

        # create empty user changes container otherwise
        user_container_id = self.uniqueName(
            extruder_stack.getId() +
            "_user") if create_new_ids else extruder_stack.getId() + "_user"
        user_container_name = user_container_id
        user_container = InstanceContainer(user_container_id,
                                           parent=application)
        user_container.setName(user_container_name)
        user_container.setMetaDataEntry("type", "user")
        user_container.setMetaDataEntry("machine", machine.getId())
        user_container.setMetaDataEntry("setting_version",
                                        application.SettingVersion)
        user_container.setDefinition(machine.definition.getId())
        user_container.setMetaDataEntry(
            "position", extruder_stack.getMetaDataEntry("position"))

        if machine.userChanges:
            # For the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
            # container to the extruder stack.
            for user_setting_key in machine.userChanges.getAllKeys():
                settable_per_extruder = machine.getProperty(
                    user_setting_key, "settable_per_extruder")
                if settable_per_extruder:
                    setting_value = machine.getProperty(
                        user_setting_key, "value")

                    setting_definition = machine.getSettingDefinition(
                        user_setting_key)
                    new_instance = SettingInstance(setting_definition,
                                                   definition_changes)
                    new_instance.setProperty("value", setting_value)
                    new_instance.resetState(
                    )  # Ensure that the state is not seen as a user state.
                    user_container.addInstance(new_instance)
                    user_container.setDirty(True)

                    machine.userChanges.removeInstance(user_setting_key,
                                                       postpone_emit=True)

        self.addContainer(user_container)
        extruder_stack.setUserChanges(user_container)

        empty_variant = application.empty_variant_container
        empty_material = application.empty_material_container
        empty_quality = application.empty_quality_container

        if machine.variant.getId() not in ("empty", "empty_variant"):
            variant = machine.variant
        else:
            variant = empty_variant
        extruder_stack.variant = variant

        if machine.material.getId() not in ("empty", "empty_material"):
            material = machine.material
        else:
            material = empty_material
        extruder_stack.material = material

        if machine.quality.getId() not in ("empty", "empty_quality"):
            quality = machine.quality
        else:
            quality = empty_quality
        extruder_stack.quality = quality

        machine_quality_changes = machine.qualityChanges
        if new_global_quality_changes is not None:
            machine_quality_changes = new_global_quality_changes

        if machine_quality_changes.getId() not in ("empty",
                                                   "empty_quality_changes"):
            extruder_quality_changes_container = self.findInstanceContainers(
                name=machine_quality_changes.getName(), extruder=extruder_id)
            if extruder_quality_changes_container:
                extruder_quality_changes_container = extruder_quality_changes_container[
                    0]

                quality_changes_id = extruder_quality_changes_container.getId()
                extruder_stack.qualityChanges = self.findInstanceContainers(
                    id=quality_changes_id)[0]
            else:
                # Some extruder quality_changes containers can be created at runtime as files in the qualities
                # folder. Those files won't be loaded in the registry immediately. So we also need to search
                # the folder to see if the quality_changes exists.
                extruder_quality_changes_container = self._findQualityChangesContainerInCuraFolder(
                    machine_quality_changes.getName())
                if extruder_quality_changes_container:
                    quality_changes_id = extruder_quality_changes_container.getId(
                    )
                    extruder_quality_changes_container.setMetaDataEntry(
                        "position",
                        extruder_definition.getMetaDataEntry("position"))
                    extruder_stack.qualityChanges = self.findInstanceContainers(
                        id=quality_changes_id)[0]
                else:
                    # If we still cannot find a quality changes container for the extruder, create a new one
                    container_name = machine_quality_changes.getName()
                    container_id = self.uniqueName(extruder_stack.getId() +
                                                   "_qc_" + container_name)
                    extruder_quality_changes_container = InstanceContainer(
                        container_id, parent=application)
                    extruder_quality_changes_container.setName(container_name)
                    extruder_quality_changes_container.setMetaDataEntry(
                        "type", "quality_changes")
                    extruder_quality_changes_container.setMetaDataEntry(
                        "setting_version", application.SettingVersion)
                    extruder_quality_changes_container.setMetaDataEntry(
                        "position",
                        extruder_definition.getMetaDataEntry("position"))
                    extruder_quality_changes_container.setMetaDataEntry(
                        "quality_type",
                        machine_quality_changes.getMetaDataEntry(
                            "quality_type"))
                    extruder_quality_changes_container.setDefinition(
                        machine_quality_changes.getDefinition().getId())

                    self.addContainer(extruder_quality_changes_container)
                    extruder_stack.qualityChanges = extruder_quality_changes_container

            if not extruder_quality_changes_container:
                Logger.log(
                    "w",
                    "Could not find quality_changes named [%s] for extruder [%s]",
                    machine_quality_changes.getName(), extruder_stack.getId())
            else:
                # Move all per-extruder settings to the extruder's quality changes
                for qc_setting_key in machine_quality_changes.getAllKeys():
                    settable_per_extruder = machine.getProperty(
                        qc_setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        setting_value = machine_quality_changes.getProperty(
                            qc_setting_key, "value")

                        setting_definition = machine.getSettingDefinition(
                            qc_setting_key)
                        new_instance = SettingInstance(setting_definition,
                                                       definition_changes)
                        new_instance.setProperty("value", setting_value)
                        new_instance.resetState(
                        )  # Ensure that the state is not seen as a user state.
                        extruder_quality_changes_container.addInstance(
                            new_instance)
                        extruder_quality_changes_container.setDirty(True)

                        machine_quality_changes.removeInstance(
                            qc_setting_key, postpone_emit=True)
        else:
            extruder_stack.qualityChanges = self.findInstanceContainers(
                id="empty_quality_changes")[0]

        self.addContainer(extruder_stack)

        # Also need to fix the other qualities that are suitable for this machine. Those quality changes may still have
        # per-extruder settings in the container for the machine instead of the extruder.
        if machine_quality_changes.getId() not in ("empty",
                                                   "empty_quality_changes"):
            quality_changes_machine_definition_id = machine_quality_changes.getDefinition(
            ).getId()
        else:
            whole_machine_definition = machine.definition
            machine_entry = machine.definition.getMetaDataEntry("machine")
            if machine_entry is not None:
                container_registry = ContainerRegistry.getInstance()
                whole_machine_definition = container_registry.findDefinitionContainers(
                    id=machine_entry)[0]

            quality_changes_machine_definition_id = "fdmprinter"
            if whole_machine_definition.getMetaDataEntry(
                    "has_machine_quality"):
                quality_changes_machine_definition_id = machine.definition.getMetaDataEntry(
                    "quality_definition", whole_machine_definition.getId())
        qcs = self.findInstanceContainers(
            type="quality_changes",
            definition=quality_changes_machine_definition_id)
        qc_groups = {}  # map of qc names -> qc containers
        for qc in qcs:
            qc_name = qc.getName()
            if qc_name not in qc_groups:
                qc_groups[qc_name] = []
            qc_groups[qc_name].append(qc)
            # Try to find from the quality changes cura directory too
            quality_changes_container = self._findQualityChangesContainerInCuraFolder(
                machine_quality_changes.getName())
            if quality_changes_container:
                qc_groups[qc_name].append(quality_changes_container)

        for qc_name, qc_list in qc_groups.items():
            qc_dict = {"global": None, "extruders": []}
            for qc in qc_list:
                extruder_position = qc.getMetaDataEntry("position")
                if extruder_position is not None:
                    qc_dict["extruders"].append(qc)
                else:
                    qc_dict["global"] = qc
            if qc_dict["global"] is not None and len(
                    qc_dict["extruders"]) == 1:
                # Move per-extruder settings
                for qc_setting_key in qc_dict["global"].getAllKeys():
                    settable_per_extruder = machine.getProperty(
                        qc_setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        setting_value = qc_dict["global"].getProperty(
                            qc_setting_key, "value")

                        setting_definition = machine.getSettingDefinition(
                            qc_setting_key)
                        new_instance = SettingInstance(setting_definition,
                                                       definition_changes)
                        new_instance.setProperty("value", setting_value)
                        new_instance.resetState(
                        )  # Ensure that the state is not seen as a user state.
                        qc_dict["extruders"][0].addInstance(new_instance)
                        qc_dict["extruders"][0].setDirty(True)

                        qc_dict["global"].removeInstance(qc_setting_key,
                                                         postpone_emit=True)

        # Set next stack at the end
        extruder_stack.setNextStack(machine)

        return extruder_stack
Ejemplo n.º 29
0
    def _createSupportMesh(self, parent: CuraSceneNode, position: Vector):
        node = CuraSceneNode()

        node.setName("RoundTab")
            
        node.setSelectable(True)
        
        # long=Support Height
        _long=position.y

        # get layer_height_0 used to define pastille height
        _id_ex=0
        
        # This function can be triggered in the middle of a machine change, so do not proceed if the machine change
        # has not done yet.
        global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
        #extruder = global_container_stack.extruderList[int(_id_ex)] 
        extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks()[0]        
        _layer_h_i = extruder_stack.getProperty("layer_height_0", "value")
        _layer_height = extruder_stack.getProperty("layer_height", "value")
        _line_w = extruder_stack.getProperty("line_width", "value")
        # Logger.log('d', 'layer_height_0 : ' + str(_layer_h_i))
        _layer_h = (_layer_h_i * 1.2) + (_layer_height * (self._Nb_Layer -1) )
        _line_w = _line_w * 1.2 
        
        if self._AsCapsule:
             # Capsule creation Diameter , Increment angle 4°, length, layer_height_0*1.2 , line_width
            mesh = self._createCapsule(self._UseSize,4,_long,_layer_h,_line_w)       
        else:
            # Cylinder creation Diameter , Increment angle 4°, length, layer_height_0*1.2
            mesh = self._createPastille(self._UseSize,4,_long,_layer_h)
        
        node.setMeshData(mesh.build())

        active_build_plate = CuraApplication.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()

        # support_mesh type
        definition = stack.getSettingDefinition("support_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)

        definition = stack.getSettingDefinition("support_mesh_drop_down")
        new_instance = SettingInstance(definition, settings)
        new_instance.setProperty("value", False)
        new_instance.resetState()  # Ensure that the state is not seen as a user state.
        settings.addInstance(new_instance)
 
        if self._AsCapsule:
            s_p = global_container_stack.getProperty("support_type", "value")
            if s_p ==  'buildplate' :
                Message(text = "Info modification current profile support_type parameter\nNew value : everywhere", title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show()
                Logger.log('d', 'support_type different : ' + str(s_p))
                # Define support_type=everywhere
                global_container_stack.setProperty("support_type", "value", 'everywhere')
                
            
        # Define support_xy_distance
        definition = stack.getSettingDefinition("support_xy_distance")
        new_instance = SettingInstance(definition, settings)
        new_instance.setProperty("value", self._UseOffset)
        # new_instance.resetState()  # Ensure that the state is not seen as a user state.
        settings.addInstance(new_instance)

        # Fix some settings in Cura to get a better result
        id_ex=0
        global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
        extruder_stack = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks()[0]
        #extruder = global_container_stack.extruderList[int(id_ex)]    
        
        # hop to fix it in a futur release
        # https://github.com/Ultimaker/Cura/issues/9882
        # if self.Major < 5 or ( self.Major == 5 and self.Minor < 1 ) :
        _xy_distance = extruder_stack.getProperty("support_xy_distance", "value")
        if self._UseOffset !=  _xy_distance :
            _msg = "New value : %8.3f" % (self._UseOffset) 
            Message(text = "Info modification current profile support_xy_distance parameter\nNew value : %8.3f" % (self._UseOffset), title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show()
            Logger.log('d', 'support_xy_distance different : ' + str(_xy_distance))
            # Define support_xy_distance
            extruder_stack.setProperty("support_xy_distance", "value", self._UseOffset)
 
        if self._Nb_Layer >1 :
            s_p = int(extruder_stack.getProperty("support_infill_rate", "value"))
            Logger.log('d', 'support_infill_rate actual : ' + str(s_p))
            if s_p < 99 :
                Message(text = "Info modification current profile support_infill_rate parameter\nNew value : 100%", title = catalog.i18nc("@info:title", "Warning ! Tab Anti Warping")).show()
                Logger.log('d', 'support_infill_rate different : ' + str(s_p))
                # Define support_infill_rate=100%
                extruder_stack.setProperty("support_infill_rate", "value", 100)
                
        
        
        op = GroupedOperation()
        # First add node to the scene at the correct position/scale, before parenting, so the support 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)

        CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
    def updateSceneFromOptimizationResult(
            self, analysis: pywim.smartslice.result.Analysis):

        type_map = {
            'int': int,
            'float': float,
            'str': str,
            'enum': str,
            'bool': bool
        }

        our_only_node = getPrintableNodes()[0]
        active_extruder = getNodeActiveExtruder(our_only_node)

        # TODO - Move this into a common class or function to apply an am.Config to GlobalStack/ExtruderStack
        if analysis.print_config.infill:

            infill_density = analysis.print_config.infill.density
            infill_pattern = analysis.print_config.infill.pattern

            if infill_pattern is None or infill_pattern == pywim.am.InfillType.unknown:
                infill_pattern = pywim.am.InfillType.grid

            infill_pattern_name = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[
                infill_pattern]

            extruder_dict = {
                "wall_line_count": analysis.print_config.walls,
                "top_layers": analysis.print_config.top_layers,
                "bottom_layers": analysis.print_config.bottom_layers,
                "infill_sparse_density": analysis.print_config.infill.density,
                "infill_pattern": infill_pattern_name
            }

            Logger.log("d",
                       "Optimized extruder settings: {}".format(extruder_dict))

            for key, value in extruder_dict.items():
                if value is not None:
                    property_type = type_map.get(
                        active_extruder.getProperty(key, "type"))
                    if property_type:
                        active_extruder.setProperty(key,
                                                    "value",
                                                    property_type(value),
                                                    set_from_cache=True)
                        active_extruder.setProperty(key,
                                                    "state",
                                                    InstanceState.User,
                                                    set_from_cache=True)

            Application.getInstance().getMachineManager(
            ).forceUpdateAllSettings()
            self.optimizationResultAppliedToScene.emit()

        # Remove any modifier meshes which are present from a previous result
        mod_meshes = getModifierMeshes()
        if len(mod_meshes) > 0:
            for node in mod_meshes:
                node.addDecorator(SmartSliceRemovedDecorator())
                our_only_node.removeChild(node)
            Application.getInstance().getController().getScene(
            ).sceneChanged.emit(node)

        # Add in the new modifier meshes
        for modifier_mesh in analysis.modifier_meshes:
            # Building the scene node
            modifier_mesh_node = CuraSceneNode()
            modifier_mesh_node.setName("SmartSliceMeshModifier")
            modifier_mesh_node.setSelectable(True)
            modifier_mesh_node.setCalculateBoundingBox(True)

            # Use the data from the SmartSlice engine to translate / rotate / scale the mod mesh
            modifier_mesh_node.setTransformation(
                Matrix(modifier_mesh.transform))

            # Building the mesh

            # # Preparing the data from pywim for MeshBuilder
            modifier_mesh_vertices = [[v.x, v.y, v.z]
                                      for v in modifier_mesh.vertices]
            modifier_mesh_indices = [[triangle.v1, triangle.v2, triangle.v3]
                                     for triangle in modifier_mesh.triangles]

            # Doing the actual build
            modifier_mesh_data = MeshBuilder()
            modifier_mesh_data.setVertices(
                numpy.asarray(modifier_mesh_vertices, dtype=numpy.float32))
            modifier_mesh_data.setIndices(
                numpy.asarray(modifier_mesh_indices, dtype=numpy.int32))
            modifier_mesh_data.calculateNormals()

            modifier_mesh_node.setMeshData(modifier_mesh_data.build())
            modifier_mesh_node.calculateBoundingBoxMesh()

            active_build_plate = Application.getInstance(
            ).getMultiBuildPlateModel().activeBuildPlate
            modifier_mesh_node.addDecorator(
                BuildPlateDecorator(active_build_plate))
            modifier_mesh_node.addDecorator(SliceableObjectDecorator())
            modifier_mesh_node.addDecorator(SmartSliceAddedDecorator())

            bottom = modifier_mesh_node.getBoundingBox().bottom

            z_offset_decorator = ZOffsetDecorator()
            z_offset_decorator.setZOffset(bottom)
            modifier_mesh_node.addDecorator(z_offset_decorator)

            stack = modifier_mesh_node.callDecoration("getStack")
            settings = stack.getTop()

            modifier_mesh_node_infill_pattern = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[
                modifier_mesh.print_config.infill.pattern]
            definition_dict = {
                "infill_mesh": True,
                "infill_pattern": modifier_mesh_node_infill_pattern,
                "infill_sparse_density":
                modifier_mesh.print_config.infill.density,
                "wall_line_count": modifier_mesh.print_config.walls,
                "top_layers": modifier_mesh.print_config.top_layers,
                "bottom_layers": modifier_mesh.print_config.bottom_layers,
            }
            Logger.log(
                "d",
                "Optimized modifier mesh settings: {}".format(definition_dict))

            for key, value in definition_dict.items():
                if value is not None:
                    definition = stack.getSettingDefinition(key)
                    property_type = type_map.get(stack.getProperty(
                        key, "type"))
                    if property_type:
                        new_instance = SettingInstance(definition, settings)

                        new_instance.setProperty("value", property_type(value))

                        new_instance.resetState(
                        )  # Ensure that the state is not seen as a user state.
                        settings.addInstance(new_instance)

            our_only_node.addChild(modifier_mesh_node)

            # emit changes and connect error tracker
            Application.getInstance().getController().getScene(
            ).sceneChanged.emit(modifier_mesh_node)
Ejemplo n.º 31
0
    def setNextStack(self, stack: ContainerStack) -> None:
        super().setNextStack(stack)
        stack.addExtruder(self)
        self.addMetaDataEntry("machine", stack.id)

        # For backward compatibility: Register the extruder with the Extruder Manager
        ExtruderManager.getInstance().registerExtruder(self, stack.id)

        # Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific
        # settings such as nozzle size and material diameter should be moved from the machine's definition_changes to
        # the this extruder's definition_changes.
        #
        # We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade,
        # when we are upgrading a definition_changes container file, there is NO guarantee that other files such as
        # machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in
        # the latest format.
        #
        # MORE:
        # For single-extrusion machines, nozzle size is saved in the global stack, so the nozzle size value should be
        # carried to the first extruder.
        # For material diameter, it was supposed to be applied to all extruders, so its value should be copied to all
        # extruders.

        keys_to_copy = ["material_diameter", "machine_nozzle_size"
                        ]  # these will be copied over to all extruders

        for key in keys_to_copy:
            # Only copy the value when this extruder doesn't have the value.
            if self.definitionChanges.hasProperty(key, "value"):
                continue

            # WARNING: this might be very dangerous and should be refactored ASAP!
            #
            # We cannot add a setting definition of "material_diameter" into the extruder's definition at runtime
            # because all other machines which uses "fdmextruder" as the extruder definition will be affected.
            #
            # The problem is that single extrusion machines have their default material diameter defined in the global
            # definitions. Now we automatically create an extruder stack for those machines using "fdmextruder"
            # definition, which doesn't have the specific "material_diameter" and "machine_nozzle_size" defined for
            # each machine. This results in wrong values which can be found in the MachineSettings dialog.
            #
            # To solve this, we put "material_diameter" back into the "fdmextruder" definition because modifying it in
            # the extruder definition will affect all machines which uses the "fdmextruder" definition. Moreover, now
            # we also check the value defined in the machine definition. If present, the value defined in the global
            # stack's definition changes container will be copied. Otherwise, we will check if the default values in the
            # machine definition and the extruder definition are the same, and if not, the default value in the machine
            # definition will be copied to the extruder stack's definition changes.
            #
            setting_value_in_global_def_changes = stack.definitionChanges.getProperty(
                key, "value")
            setting_value_in_global_def = stack.definition.getProperty(
                key, "value")
            setting_value = setting_value_in_global_def
            if setting_value_in_global_def_changes is not None:
                setting_value = setting_value_in_global_def_changes
            if setting_value == self.definition.getProperty(key, "value"):
                continue

            setting_definition = stack.getSettingDefinition(key)
            new_instance = SettingInstance(setting_definition,
                                           self.definitionChanges)
            new_instance.setProperty("value", setting_value)
            new_instance.resetState(
            )  # Ensure that the state is not seen as a user state.
            self.definitionChanges.addInstance(new_instance)
            self.definitionChanges.setDirty(True)

            # Make sure the material diameter is up to date for the extruder stack.
            if key == "material_diameter":
                from cura.CuraApplication import CuraApplication
                machine_manager = CuraApplication.getInstance(
                ).getMachineManager()
                position = self.getMetaDataEntry("position", "0")
                func = lambda p=position: CuraApplication.getInstance(
                ).getExtruderManager().updateMaterialForDiameter(p)
                machine_manager.machine_extruder_material_update_dict[
                    stack.getId()].append(func)