Ejemplo n.º 1
0
    def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode):
        if mode != MeshWriter.OutputMode.TextMode:
            Logger.log("e", "GCodeWriter does not support non-text mode.")
            self.setInformation(catalog.i18nc("@error:not supported", "GCodeWriter does not support non-text mode."))
            return False

        active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate
        scene = Application.getInstance().getController().getScene()
        if not hasattr(scene, "gcode_dict"):
            self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
            return False
        gcode_dict = getattr(scene, "gcode_dict")
        gcode_list = gcode_dict.get(active_build_plate, None)
        if gcode_list is not None:
            has_settings = False
            for gcode in gcode_list:
                if gcode[:len(self._setting_keyword)] == self._setting_keyword:
                    has_settings = True
                stream.write(gcode)
            # Serialise the current container stack and put it at the end of the file.
            if not has_settings:
                settings = self._serialiseSettings(Application.getInstance().getGlobalContainerStack())
                stream.write(settings)
            return True

        self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
        return False
Ejemplo n.º 2
0
    def moveToNextLevelPosition(self):
        output_devices = self._getPrinterOutputDevices()
        if output_devices:  # We found at least one output device
            output_device = output_devices[0]

            if self._bed_level_position == 0:
                output_device.moveHead(0, 0, 3)
                output_device.homeHead()
                output_device.moveHead(0, 0, 3)
                output_device.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0)
                output_device.moveHead(0, 0, -3)
                self._bed_level_position += 1
            elif self._bed_level_position == 1:
                output_device.moveHead(0, 0, 3)
                output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0)
                output_device.moveHead(0, 0, -3)
                self._bed_level_position += 1
            elif self._bed_level_position == 2:
                output_device.moveHead(0, 0, 3)
                output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0)
                output_device.moveHead(0, 0, -3)
                self._bed_level_position += 1
            elif self._bed_level_position >= 3:
                output_device.sendCommand("M18") # Turn off all motors so the user can move the axes
                self.setFinished()
Ejemplo n.º 3
0
    def setSettingValue(self, key, value):
        if key not in self._settings:
            return

        self._setting_values[key] = value
        self.settingValueChanged.emit(self._settings[key])
        Application.getInstance().getController().getScene().sceneChanged.emit(self.getNode())
Ejemplo n.º 4
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 = GroupedOperation()
        # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent
        op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot()))
        op.addOperation(SetParentOperation(node, parent))
        op.push()
        node.setPosition(position, CuraSceneNode.TransformSpace.World)

        Application.getInstance().getController().getScene().sceneChanged.emit(node)
Ejemplo n.º 5
0
    def _onGlobalContainerChanged(self):
        global_container_stack = Application.getInstance().getGlobalContainerStack()
        if global_container_stack:
            self._multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1

            # Ensure that all extruder data is reset
            if not self._multi_extrusion:
                default_stack_id = global_container_stack.getId()
            else:
                default_stack = ExtruderManager.getInstance().getExtruderStack(0)
                if default_stack:
                    default_stack_id = default_stack.getId()
                else:
                    default_stack_id = global_container_stack.getId()

            root_node = Application.getInstance().getController().getScene().getRoot()
            for node in DepthFirstIterator(root_node):
                new_stack_id = default_stack_id
                # Get position of old extruder stack for this node
                old_extruder_pos = node.callDecoration("getActiveExtruderPosition")
                if old_extruder_pos is not None:
                    # Fetch current (new) extruder stack at position
                    new_stack = ExtruderManager.getInstance().getExtruderStack(old_extruder_pos)
                    if new_stack:
                        new_stack_id = new_stack.getId()
                node.callDecoration("setActiveExtruder", new_stack_id)

            self._updateEnabled()
    def __init__(self) -> None:
        super().__init__()
        self._zero_conf = None # type: Optional[Zeroconf]
        self._browser = None # type: Optional[ServiceBrowser]
        self._instances = {} # type: Dict[str, OctoPrintOutputDevice.OctoPrintOutputDevice]

        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addInstanceSignal.connect(self.addInstance)
        self.removeInstanceSignal.connect(self.removeInstance)
        Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections)

        # Load custom instances from preferences
        self._preferences = Application.getInstance().getPreferences()
        self._preferences.addPreference("octoprint/manual_instances", "{}")

        self._preferences.addPreference("octoprint/use_zeroconf", True)

        try:
            self._manual_instances = json.loads(self._preferences.getValue("octoprint/manual_instances"))
        except ValueError:
            self._manual_instances = {} # type: Dict[str, Any]
        if not isinstance(self._manual_instances, dict):
            self._manual_instances = {} # type: Dict[str, Any]

        self._name_regex = re.compile("OctoPrint instance (\".*\"\.|on )(.*)\.")

        self._keep_alive_timer = QTimer()
        self._keep_alive_timer.setInterval(2000)
        self._keep_alive_timer.setSingleShot(True)
        self._keep_alive_timer.timeout.connect(self._keepDiscoveryAlive)
Ejemplo n.º 7
0
    def __init__(self, node, hull, thickness, parent = None):
        super().__init__(parent)

        self.setCalculateBoundingBox(False)

        self._original_parent = parent

        # Color of the drawn convex hull
        if Application.getInstance().hasGui():
            self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb())
        else:
            self._color = Color(0, 0, 0)

        # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
        self._mesh_height = 0.1

        self._thickness = thickness

        # The node this mesh is "watching"
        self._node = node
        self._convex_hull_head_mesh = None

        self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged)
        self._onNodeDecoratorsChanged(self._node)

        self._hull = hull
        if self._hull:
            hull_mesh_builder = MeshBuilder()

            if hull_mesh_builder.addConvexPolygonExtrusion(
                self._hull.getPoints()[::-1],  # bottom layer is reversed
                self._mesh_height-thickness, self._mesh_height, color=self._color):

                hull_mesh = hull_mesh_builder.build()
                self.setMeshData(hull_mesh)
Ejemplo n.º 8
0
 def activeExtruderStackId(self) -> Optional[str]:
     if not Application.getInstance().getGlobalContainerStack():
         return None # No active machine, so no active extruder.
     try:
         return self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
     except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
         return None
Ejemplo n.º 9
0
 def extruderCount(self):
     if not Application.getInstance().getGlobalContainerStack():
         return 0  # No active machine, so no extruders.
     try:
         return len(self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()])
     except KeyError:
         return 0
    def __init__(self, parent = None, *args, **kwargs):
        super().__init__(parent = parent, *args, **kwargs)

        Application.getInstance().getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
        self._onPreferencesChanged("general/visible_settings")

        self.visibilityChanged.connect(self._onVisibilityChanged)
Ejemplo n.º 11
0
    def addMachine(self, name, definition_id):
        container_registry = UM.Settings.ContainerRegistry.getInstance()
        definitions = container_registry.findDefinitionContainers(id = definition_id)
        if definitions:
            definition = definitions[0]
            name = self._createUniqueName("machine", "", name, definition.getName())
            new_global_stack = UM.Settings.ContainerStack(name)
            new_global_stack.addMetaDataEntry("type", "machine")
            container_registry.addContainer(new_global_stack)

            variant_instance_container = self._updateVariantContainer(definition)
            material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
            quality_instance_container = self._updateQualityContainer(definition, variant_instance_container, material_instance_container)

            current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
            current_settings_instance_container.addMetaDataEntry("machine", name)
            current_settings_instance_container.addMetaDataEntry("type", "user")
            current_settings_instance_container.setDefinition(definitions[0])
            container_registry.addContainer(current_settings_instance_container)

            new_global_stack.addContainer(definition)
            if variant_instance_container:
                new_global_stack.addContainer(variant_instance_container)
            if material_instance_container:
                new_global_stack.addContainer(material_instance_container)
            if quality_instance_container:
                new_global_stack.addContainer(quality_instance_container)

            new_global_stack.addContainer(self._empty_quality_changes_container)
            new_global_stack.addContainer(current_settings_instance_container)

            ExtruderManager.getInstance().addMachineExtruders(definition, new_global_stack.getId())

            Application.getInstance().setGlobalContainerStack(new_global_stack)
Ejemplo n.º 12
0
    def __init__(self, width, height):
        super().__init__("selection", width, height, -999)

        self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "selection.shader"))
        self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
        self._gl = OpenGL.getInstance().getBindingsObject()
        self._scene = Application.getInstance().getController().getScene()

        self._renderer = Application.getInstance().getRenderer()

        self._selection_map = {}
        self._toolhandle_selection_map = {
            self._dropAlpha(ToolHandle.DisabledSelectionColor): ToolHandle.NoAxis,
            self._dropAlpha(ToolHandle.XAxisSelectionColor): ToolHandle.XAxis,
            self._dropAlpha(ToolHandle.YAxisSelectionColor): ToolHandle.YAxis,
            self._dropAlpha(ToolHandle.ZAxisSelectionColor): ToolHandle.ZAxis,
            self._dropAlpha(ToolHandle.AllAxisSelectionColor): ToolHandle.AllAxis,
            ToolHandle.DisabledSelectionColor: ToolHandle.NoAxis,
            ToolHandle.XAxisSelectionColor: ToolHandle.XAxis,
            ToolHandle.YAxisSelectionColor: ToolHandle.YAxis,
            ToolHandle.ZAxisSelectionColor: ToolHandle.ZAxis,
            ToolHandle.AllAxisSelectionColor: ToolHandle.AllAxis
        }

        self._output = None
Ejemplo n.º 13
0
    def beginRendering(self):
        scene = self.getController().getScene()
        renderer = self.getRenderer()

        if not self._enabled_shader:
            self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))

        if not self._disabled_shader:
            self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
            self._disabled_shader.setUniformValue("u_diffuseColor1", [0.48, 0.48, 0.48, 1.0])
            self._disabled_shader.setUniformValue("u_diffuseColor2", [0.68, 0.68, 0.68, 1.0])
            self._disabled_shader.setUniformValue("u_width", 50.0)

        if Application.getInstance().getGlobalContainerStack():
            if Preferences.getInstance().getValue("view/show_overhang"):
                angle = Application.getInstance().getGlobalContainerStack().getProperty("support_angle", "value")
                if angle is not None:
                    self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle)))
                else:
                    self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang.
            else:
                self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))

        for node in DepthFirstIterator(scene.getRoot()):
            if not node.render(renderer):
                if node.getMeshData() and node.isVisible():
                    # TODO: Find a better way to handle this
                    #if node.getBoundingBoxMesh():
                    #    renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)

                    uniforms = {}
                    if self._extruders_model.rowCount() > 0:
                        # Get color to render this mesh in from ExtrudersModel
                        extruder_index = 0
                        extruder_id = node.callDecoration("getActiveExtruder")
                        if extruder_id:
                            extruder_index = max(0, self._extruders_model.find("id", extruder_id))

                        extruder_color = self._extruders_model.getItem(extruder_index)["colour"]
                        try:
                            # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
                            # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
                            uniforms["diffuse_color"] = [
                                int(extruder_color[1:3], 16) / 255,
                                int(extruder_color[3:5], 16) / 255,
                                int(extruder_color[5:7], 16) / 255,
                                1.0
                            ]
                        except ValueError:
                            pass

                    if hasattr(node, "_outside_buildarea"):
                        if node._outside_buildarea:
                            renderer.queueNode(node, shader = self._disabled_shader)
                        else:
                            renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
                    else:
                        renderer.queueNode(node, material = self._enabled_shader, uniforms = uniforms)
                if node.callDecoration("isGroup"):
                    renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = Renderer.RenderLines)
Ejemplo n.º 14
0
    def __init__(self, message):
        super().__init__()
        self._message = message
        self._scene = Application.getInstance().getController().getScene()

        self._progress = None
        Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
Ejemplo n.º 15
0
 def setSelected(self, key):
     for index in range(0,len(self.items)):
         if self.items[index]["key"] == key:
             for node in Application.getInstance().getController().getScene().getRoot().getAllChildren():
                 if id(node) == key:
                     if node not in Selection.getAllSelectedObjects(): #node already selected
                         Selection.add(node)
                         if self.items[index]["depth"] == 1: #Its a group node
                             for child_node in node.getChildren(): 
                                 if child_node not in Selection.getAllSelectedObjects(): #Set all children to parent state (if they arent already)
                                     Selection.add(child_node) 
                     else:
                         Selection.remove(node)
                         if self.items[index]["depth"] == 1: #Its a group
                             for child_node in node.getChildren():
                                 if child_node in Selection.getAllSelectedObjects():
                                     Selection.remove(child_node)    
                        
     all_children_selected = True
     #Check all group nodes to see if all their children are selected (if so, they also need to be selected!)
     for index in range(0,len(self.items)):
         if self.items[index]["depth"] == 1:
             for node in Application.getInstance().getController().getScene().getRoot().getAllChildren():
                 if node.hasChildren():
                     if id(node) == self.items[index]["key"] and id(node) != key: 
                         for index, child_node in enumerate(node.getChildren()):
                             if not Selection.isSelected(child_node):
                                 all_children_selected = False #At least one of its children is not selected, dont change state
                                 break 
                         if all_children_selected:
                             Selection.add(node)
                         else:
                             Selection.remove(node)
     #Force update                  
     self.updateList(Application.getInstance().getController().getScene().getRoot())
Ejemplo n.º 16
0
    def updateHasMaterialsMetadata(self):
        # Updates the has_materials metadata flag after switching gcode flavor
        if not self._global_container_stack:
            return

        definition = self._global_container_stack.getBottom()
        if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry("has_materials", False):
            # In other words: only continue for the UM2 (extended), but not for the UM2+
            return

        has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"

        material_container = self._global_container_stack.material

        if has_materials:
            if "has_materials" in self._global_container_stack.getMetaData():
                self._global_container_stack.setMetaDataEntry("has_materials", True)
            else:
                self._global_container_stack.addMetaDataEntry("has_materials", True)

            # Set the material container to a sane default
            if material_container == self._empty_container:
                search_criteria = { "type": "material", "definition": "fdmprinter", "id": self._global_container_stack.getMetaDataEntry("preferred_material")}
                materials = self._container_registry.findInstanceContainers(**search_criteria)
                if materials:
                    self._global_container_stack.material = materials[0]
        else:
            # The metadata entry is stored in an ini, and ini files are parsed as strings only.
            # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
            if "has_materials" in self._global_container_stack.getMetaData():
                self._global_container_stack.removeMetaDataEntry("has_materials")

            self._global_container_stack.material = ContainerRegistry.getInstance().getEmptyInstanceContainer()

        Application.getInstance().globalContainerStackChanged.emit()
Ejemplo n.º 17
0
    def _onStartSliceCompleted(self, job):
        # Note that cancelled slice jobs can still call this method.
        if self._start_slice_job is job:
            self._start_slice_job = None

        if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error:
            return

        if job.getResult() == StartSliceJob.StartJobResult.SettingError:
            if Application.getInstance().getPlatformActivity:
                self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."), lifetime = 10)
                self._error_message.show()
                self.backendStateChange.emit(BackendState.Error)
            else:
                self.backendStateChange.emit(BackendState.NotStarted)
            return

        if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
            if Application.getInstance().getPlatformActivity:
                self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable objects found."), lifetime = 10)
                self._error_message.show()
                self.backendStateChange.emit(BackendState.Error)
            else:
                self.backendStateChange.emit(BackendState.NotStarted)
            return

        # Preparation completed, send it to the backend.
        self._socket.sendMessage(job.getSliceMessage())
Ejemplo n.º 18
0
    def renameQualityContainer(self, container_id, new_name):
        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality")
        if containers:
            new_name = self._createUniqueName("quality", containers[0].getName(), new_name,
                                              catalog.i18nc("@label", "Custom profile"))

            if containers[0].getName() == new_name:
                # Nothing to do.
                return

            # As we also want the id of the container to be changed (so that profile name is the name of the file
            # on disk. We need to create a new instance and remove it (so the old file of the container is removed)
            # If we don't do that, we might get duplicates & other weird issues.
            new_container = InstanceContainer("")
            new_container.deserialize(containers[0].serialize())

            # Actually set the name
            new_container.setName(new_name)
            new_container._id = new_name  # Todo: Fix proper id change function for this.

            # Add the "new" container.
            UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)

            # Ensure that the renamed profile is saved -before- we remove the old profile.
            Application.getInstance().saveSettings()

            # Actually set & remove new / old quality.
            self.setActiveQuality(new_name)
            self.removeQualityContainer(containers[0].getId())
Ejemplo n.º 19
0
    def __init__(self, parent = None):
        super().__init__(parent)

        self._width = 0
        self._height = 0
        self._depth = 0

        self._shader = None

        self._grid_mesh = None
        self._grid_shader = None

        self._disallowed_areas = []
        self._disallowed_area_mesh = None

        self._prime_tower_area = None
        self._prime_tower_area_mesh = None

        self.setCalculateBoundingBox(False)
        self._volume_aabb = None

        self._raft_thickness = 0.0
        self._adhesion_type = None
        self._platform = Platform(self)

        self._global_container_stack = None
        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
        self._onGlobalContainerStackChanged()

        self._active_extruder_stack = None
        ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
        self._onActiveExtruderStackChanged()

        self._has_errors = False
Ejemplo n.º 20
0
    def _onPrintDurationMessage(self, total_time, material_amounts):
        self._current_print_time.setDuration(total_time)
        self.currentPrintTimeChanged.emit()

        # Material amount is sent as an amount of mm^3, so calculate length from that
        r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
        self._material_lengths = []
        self._material_weights = []
        extruder_stacks = list(
            cura.Settings.ExtruderManager.getInstance().getMachineExtruders(
                Application.getInstance().getGlobalContainerStack().getId()
            )
        )
        for index, amount in enumerate(material_amounts):
            ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
            #  list comprehension filtering to solve this for us.
            if extruder_stacks:  # Multi extrusion machine
                extruder_stack = [
                    extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)
                ][0]
                density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0)
            else:  # Machine with no extruder stacks
                density = (
                    Application.getInstance()
                    .getGlobalContainerStack()
                    .getMetaDataEntry("properties", {})
                    .get("density", 0)
                )

            self._material_weights.append(float(amount) * float(density) / 1000)
            self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2))
        self.materialLengthsChanged.emit()
        self.materialWeightsChanged.emit()
Ejemplo n.º 21
0
    def addMachine(self, name, definition_id):
        definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = definition_id)
        if definitions:
            definition = definitions[0]
            name = self._createUniqueName("machine", "", name, definition.getName())
            new_global_stack = UM.Settings.ContainerStack(name)
            new_global_stack.addMetaDataEntry("type", "machine")
            UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)

            variant_instance_container = self._updateVariantContainer(definition)
            material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
            quality_instance_container = self._updateQualityContainer(definition, material_instance_container)

            current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
            current_settings_instance_container.addMetaDataEntry("machine", name)
            current_settings_instance_container.addMetaDataEntry("type", "user")
            current_settings_instance_container.setDefinition(definitions[0])
            UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_instance_container)

            # If a definition is found, its a list. Should only have one item.
            new_global_stack.addContainer(definition)
            if variant_instance_container:
                new_global_stack.addContainer(variant_instance_container)
            if material_instance_container:
                new_global_stack.addContainer(material_instance_container)
            if quality_instance_container:
                new_global_stack.addContainer(quality_instance_container)
            new_global_stack.addContainer(current_settings_instance_container)

            ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition)

            Application.getInstance().setGlobalContainerStack(new_global_stack)
    def __init__(self):
        super().__init__()
        self._zero_conf = None
        self._browser = None
        self._printers = {}

        self._api_version = "1"
        self._api_prefix = "/api/v" + self._api_version + "/"

        self._network_manager = QNetworkAccessManager()
        self._network_manager.finished.connect(self._onNetworkRequestFinished)

        # List of old printer names. This is used to ensure that a refresh of zeroconf does not needlessly forces
        # authentication requests.
        self._old_printers = []

        # Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
        self.addPrinterSignal.connect(self.addPrinter)
        self.removePrinterSignal.connect(self.removePrinter)
        Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections)

        # Get list of manual printers from preferences
        self._preferences = Preferences.getInstance()
        self._preferences.addPreference("um3networkprinting/manual_instances", "") #  A comma-separated list of ip adresses or hostnames
        self._manual_instances = self._preferences.getValue("um3networkprinting/manual_instances").split(",")
Ejemplo n.º 23
0
    def _onHotendIdChanged(self, index, hotend_id):
        if not self._global_container_stack:
            return

        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = self._global_container_stack.getBottom().getId(), name = hotend_id)
        if containers:
            extruder_manager = ExtruderManager.getInstance()
            old_index = extruder_manager.activeExtruderIndex
            if old_index != index:
                extruder_manager.setActiveExtruderIndex(index)
            else:
                old_index = None

            if self.activeVariantId != containers[0].getId():
                if time.time() - self._auto_change_material_hotend_flood_time > self._auto_change_material_hotend_flood_window:
                    Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the hotend to match the hotend in your printer?"),
                                                         catalog.i18nc("@label", "The hotend on your printer was changed. For best results always slice for the hotend that is inserted in your printer."),
                                                         buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._hotendChangedDialogCallback, callback_arguments = [index, containers[0].getId()])
                else:
                    self._hotendChangedDialogCallback(self._auto_change_material_hotend_flood_last_choice, index, containers[0].getId())
            if old_index is not None:
                extruder_manager.setActiveExtruderIndex(old_index)

        else:
            Logger.log("w", "No variant found for printer definition %s with id %s" % (self._global_container_stack.getBottom().getId(), hotend_id))
Ejemplo n.º 24
0
    def _onMaterialIdChanged(self, index, material_id):
        if not self._global_container_stack:
            return

        definition_id = "fdmprinter"
        if self._global_container_stack.getMetaDataEntry("has_machine_materials", False):
            definition_id = self._global_container_stack.getBottom().getId()

        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition_id, GUID = material_id)
        if containers:
            extruder_manager = ExtruderManager.getInstance()
            old_index = extruder_manager.activeExtruderIndex
            if old_index != index:
                extruder_manager.setActiveExtruderIndex(index)
            else:
                old_index = None

            if self.activeMaterialId != containers[0].getId():
                if time.time() - self._auto_change_material_hotend_flood_time > self._auto_change_material_hotend_flood_window:
                    Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the material to match the material in your printer?"),
                                                         catalog.i18nc("@label", "The material on your printer was changed. For best results always slice for the material that is inserted in your printer."),
                                                         buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialIdChangedDialogCallback, callback_arguments = [index, containers[0].getId()])
                else:
                    self._materialIdChangedDialogCallback(self._auto_change_material_hotend_flood_last_choice, index, containers[0].getId())
            if old_index is not None:
                extruder_manager.setActiveExtruderIndex(old_index)

        else:
            Logger.log("w", "No material definition found for printer definition %s and GUID %s" % (definition_id, material_id))
Ejemplo n.º 25
0
    def setActiveQuality(self, quality_id):
        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id)
        if not containers or not self._active_container_stack:
            return

        old_quality = self._active_container_stack.findContainer({"type": "quality"})
        if old_quality and old_quality != containers[0]:
            old_quality.nameChanged.disconnect(self._onQualityNameChanged)

            quality_index = self._active_container_stack.getContainerIndex(old_quality)

            self._active_container_stack.replaceContainer(quality_index, containers[0])

            containers[0].nameChanged.connect(self._onQualityNameChanged)

            if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
                # Ask the user if the user profile should be cleared or not (discarding the current settings)
                # In Simple Mode we assume the user always wants to keep the (limited) current settings
                details = catalog.i18nc("@label", "You made changes to the following setting(s):")
                user_settings = self._active_container_stack.getTop().findInstances(**{})
                for setting in user_settings:
                    details = details + "\n    " + setting.definition.label

                Application.getInstance().messageBox(catalog.i18nc("@window:title", "Switched profiles"), catalog.i18nc("@label", "Do you want to transfer your changed settings to this profile?"),
                                                     catalog.i18nc("@label", "If you transfer your settings they will override settings in the profile."), details,
                                                     buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._keepUserSettingsDialogCallback)
        else:
            Logger.log("w", "While trying to set the active quality, no quality was found to replace.")
Ejemplo n.º 26
0
 def _createViewFromQML(self):
     path = QUrl.fromLocalFile(
         os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), self._qml_url))
     self._component = QQmlComponent(Application.getInstance()._engine, path)
     self._context = QQmlContext(Application.getInstance()._engine.rootContext())
     self._context.setContextProperty("manager", self)
     self._view = self._component.create(self._context)
Ejemplo n.º 27
0
    def slice(self):
        self._slice_start_time = time()
        if not self._need_slicing:
            self.processingProgress.emit(1.0)
            self.backendStateChange.emit(BackendState.Done)
            Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.")
            return
        if Application.getInstance().getPrintInformation():
            Application.getInstance().getPrintInformation().setToZeroPrintInformation()

        self._stored_layer_data = []
        self._stored_optimized_layer_data = []

        if self._process is None:
            self._createSocket()
        self.stopSlicing()
        self._engine_is_fresh = False  # Yes we're going to use the engine

        self.processingProgress.emit(0.0)
        self.backendStateChange.emit(BackendState.NotStarted)

        self._scene.gcode_list = []
        self._slicing = True
        self.slicingStarted.emit()

        slice_message = self._socket.createMessage("cura.proto.Slice")
        self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
        self._start_slice_job.start()
        self._start_slice_job.finished.connect(self._onStartSliceCompleted)
Ejemplo n.º 28
0
    def createChangelogWindow(self):
        path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.qml"))

        component = QQmlComponent(Application.getInstance()._engine, path)
        self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext())
        self._changelog_context.setContextProperty("manager", self)
        self._changelog_window = component.create(self._changelog_context)
Ejemplo n.º 29
0
    def __init__(self, parent = None):
        super().__init__(parent = parent)

        self._additional_component = None
        self._additional_components_view = None

        Application.getInstance().engineCreatedSignal.connect(self._createAdditionalComponentsView)
Ejemplo n.º 30
0
    def setHasVariants(self, has_variants = True):
        global_container_stack = Application.getInstance().getGlobalContainerStack()
        if global_container_stack:
            variant_container = global_container_stack.extruders["0"].variant

            if has_variants:
                global_container_stack.setMetaDataEntry("has_variants", True)

                # Set the variant container to a sane default
                empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
                if type(variant_container) == type(empty_container):
                    search_criteria = { "type": "variant", "definition": "ultimaker2", "id": "*0.4*" }
                    containers = self._container_registry.findInstanceContainers(**search_criteria)
                    if containers:
                        global_container_stack.extruders["0"].variant = containers[0]
            else:
                # The metadata entry is stored in an ini, and ini files are parsed as strings only.
                # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
                if "has_variants" in global_container_stack.getMetaData():
                    global_container_stack.removeMetaDataEntry("has_variants")

                # Set the variant container to an empty variant
                global_container_stack.extruders["0"].variant = ContainerRegistry.getInstance().getEmptyInstanceContainer()

            Application.getInstance().globalContainerStackChanged.emit()
            self._reset()
Ejemplo n.º 31
0
 def __init__(self, filename):
     super().__init__(filename)
     from UM.Application import Application
     self._application = Application.getInstance()
     self._handler = Application.getInstance().getMeshFileHandler()
Ejemplo n.º 32
0
    def _rebuild(self):
        if not self._build_volume._width or not self._build_volume._height or not self._build_volume._depth:
            return

        if not Application.getInstance()._engine:
            return

        if not self._build_volume._volume_outline_color:
            theme = Application.getInstance().getTheme()
            self._build_volume._volume_outline_color = Color(
                *theme.getColor("volume_outline").getRgb())
            self._build_volume._x_axis_color = Color(
                *theme.getColor("x_axis").getRgb())
            self._build_volume._y_axis_color = Color(
                *theme.getColor("y_axis").getRgb())
            self._build_volume._z_axis_color = Color(
                *theme.getColor("z_axis").getRgb())
            self._build_volume._disallowed_area_color = Color(
                *theme.getColor("disallowed_area").getRgb())
            self._build_volume._error_area_color = Color(
                *theme.getColor("error_area").getRgb())

        ### START PATCH
        # Get a dict from the machine metadata optionally overriding the build volume
        # Note that CuraEngine is blissfully unaware of this; it is just what the user is shown in Cura
        limit_buildvolume = self._build_volume._global_container_stack.getMetaDataEntry(
            "limit_buildvolume", {})
        if not isinstance(limit_buildvolume, dict):
            limit_buildvolume = {}

        min_w = limit_buildvolume.get("width",
                                      {}).get("minimum",
                                              -self._build_volume._width / 2)
        max_w = limit_buildvolume.get("width",
                                      {}).get("maximum",
                                              self._build_volume._width / 2)
        min_h = limit_buildvolume.get("height", {}).get("minimum", 0.0)
        max_h = limit_buildvolume.get("height",
                                      {}).get("maximum",
                                              self._build_volume._height)
        min_d = limit_buildvolume.get("depth",
                                      {}).get("minimum",
                                              -self._build_volume._depth / 2)
        max_d = limit_buildvolume.get("depth",
                                      {}).get("maximum",
                                              self._build_volume._depth / 2)
        ### END PATCH

        z_fight_distance = 0.2  # Distance between buildplate and disallowed area meshes to prevent z-fighting

        if self._build_volume._shape != "elliptic":
            # Outline 'cube' of the build volume
            mb = MeshBuilder()
            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(max_w, min_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(min_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, min_d),
                       Vector(max_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, min_d),
                       Vector(max_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)

            mb.addLine(Vector(min_w, min_h, max_d),
                       Vector(max_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, min_h, max_d),
                       Vector(min_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, max_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, max_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)

            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(min_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, min_d),
                       Vector(max_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, min_d),
                       Vector(min_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, max_h, min_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)

            self._build_volume.setMeshData(mb.build())

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addQuad(Vector(min_w, min_h - z_fight_distance, min_d),
                       Vector(max_w, min_h - z_fight_distance, min_d),
                       Vector(max_w, min_h - z_fight_distance, max_d),
                       Vector(min_w, min_h - z_fight_distance, max_d))

            for n in range(0, 6):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2])
            self._build_volume._grid_mesh = mb.build()

        else:
            # Bottom and top 'ellipse' of the build volume
            aspect = 1.0
            scale_matrix = Matrix()
            if self._build_volume._width != 0:
                # Scale circular meshes by aspect ratio if width != height
                aspect = self._build_volume._depth / self._build_volume._width
                scale_matrix.compose(scale=Vector(1, 1, aspect))
            mb = MeshBuilder()
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=(0, min_h - z_fight_distance, 0),
                      color=self._build_volume._volume_outline_color)
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=(0, max_h, 0),
                      color=self._build_volume._volume_outline_color)
            self._build_volume.setMeshData(
                mb.build().getTransformed(scale_matrix))

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addVertex(0, min_h - z_fight_distance, 0)
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=Vector(0, min_h - z_fight_distance, 0))
            sections = mb.getVertexCount(
            ) - 1  # Center point is not an arc section
            indices = []
            for n in range(0, sections - 1):
                indices.append([0, n + 2, n + 1])
            mb.addIndices(numpy.asarray(indices, dtype=numpy.int32))
            mb.calculateNormals()

            for n in range(0, mb.getVertexCount()):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2] * aspect)
            self._build_volume._grid_mesh = mb.build().getTransformed(
                scale_matrix)

        # Indication of the machine origin
        if self._build_volume._global_container_stack.getProperty(
                "machine_center_is_zero", "value"):
            origin = (Vector(min_w, min_h, min_d) +
                      Vector(max_w, min_h, max_d)) / 2
        else:
            origin = Vector(min_w, min_h, max_d)

        mb = MeshBuilder()
        mb.addCube(width=self._build_volume._origin_line_length,
                   height=self._build_volume._origin_line_width,
                   depth=self._build_volume._origin_line_width,
                   center=origin +
                   Vector(self._build_volume._origin_line_length / 2, 0, 0),
                   color=self._build_volume._x_axis_color)
        mb.addCube(width=self._build_volume._origin_line_width,
                   height=self._build_volume._origin_line_length,
                   depth=self._build_volume._origin_line_width,
                   center=origin +
                   Vector(0, self._build_volume._origin_line_length / 2, 0),
                   color=self._build_volume._y_axis_color)
        mb.addCube(width=self._build_volume._origin_line_width,
                   height=self._build_volume._origin_line_width,
                   depth=self._build_volume._origin_line_length,
                   center=origin -
                   Vector(0, 0, self._build_volume._origin_line_length / 2),
                   color=self._build_volume._z_axis_color)
        self._build_volume._origin_mesh = mb.build()

        disallowed_area_height = 0.1
        disallowed_area_size = 0
        if self._build_volume._disallowed_areas:
            mb = MeshBuilder()
            color = self._build_volume._disallowed_area_color
            for polygon in self._build_volume._disallowed_areas:
                points = polygon.getPoints()
                if len(points) == 0:
                    continue

                first = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(
                        self._build_volume._clamp(point[0], min_w, max_w),
                        disallowed_area_height,
                        self._build_volume._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color=color)
                    previous_point = new_point

                # Find the largest disallowed area to exclude it from the maximum scale bounds.
                # This is a very nasty hack. This pretty much only works for UM machines.
                # This disallowed area_size needs a -lot- of rework at some point in the future: TODO
                if numpy.min(
                        points[:, 1]
                ) >= 0:  # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area.
                    size = abs(
                        numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
                else:
                    size = 0
                disallowed_area_size = max(size, disallowed_area_size)

            self._build_volume._disallowed_area_mesh = mb.build()
        else:
            self._build_volume._disallowed_area_mesh = None

        if self._build_volume._error_areas:
            mb = MeshBuilder()
            for error_area in self._build_volume._error_areas:
                color = self._build_volume._error_area_color
                points = error_area.getPoints()
                first = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(
                        self._build_volume._clamp(point[0], min_w, max_w),
                        disallowed_area_height,
                        self._build_volume._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color=color)
                    previous_point = new_point
            self._build_volume._error_mesh = mb.build()
        else:
            self._build_volume._error_mesh = None

        self._build_volume._volume_aabb = AxisAlignedBox(
            minimum=Vector(min_w, min_h - 1.0, min_d),
            maximum=Vector(
                max_w, max_h - self._build_volume._raft_thickness -
                self._build_volume._extra_z_clearance, max_d))

        bed_adhesion_size = self._build_volume.getEdgeDisallowedSize()

        # As this works better for UM machines, we only add the disallowed_area_size for the z direction.
        # This is probably wrong in all other cases. TODO!
        # The +1 and -1 is added as there is always a bit of extra room required to work properly.
        scale_to_max_bounds = AxisAlignedBox(
            minimum=Vector(
                min_w + bed_adhesion_size + 1, min_h,
                min_d + disallowed_area_size - bed_adhesion_size + 1),
            maximum=Vector(
                max_w - bed_adhesion_size - 1,
                max_h - self._build_volume._raft_thickness -
                self._build_volume._extra_z_clearance,
                max_d - disallowed_area_size + bed_adhesion_size - 1))

        Application.getInstance().getController().getScene(
        )._maximum_bounds = scale_to_max_bounds

        self._build_volume.updateNodeBoundaryCheck()
Ejemplo n.º 33
0
 def __init__(self, parent = None):
     super().__init__(parent)
     self._current_layer = 0
     self._controller = Application.getInstance().getController()
     self._controller.activeViewChanged.connect(self._onActiveViewChanged)
     self._onActiveViewChanged()
 def _getPrinterOutputDevices(self) -> List[PrinterOutputDevice]:
     return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)]
Ejemplo n.º 35
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.initializeCuraMessagePrintTimeProperties()

        self._material_lengths = {}  # indexed by build plate number
        self._material_weights = {}
        self._material_costs = {}
        self._material_names = {}

        self._pre_sliced = False

        self._backend = Application.getInstance().getBackend()
        if self._backend:
            self._backend.printDurationMessage.connect(
                self._onPrintDurationMessage)
        Application.getInstance().getController().getScene(
        ).sceneChanged.connect(self._onSceneChanged)

        self._base_name = ""
        self._abbr_machine = ""
        self._job_name = ""
        self._project_name = ""
        self._active_build_plate = 0
        self._initVariablesWithBuildPlate(self._active_build_plate)

        Application.getInstance().globalContainerStackChanged.connect(
            self._updateJobName)
        Application.getInstance().fileLoaded.connect(self.setBaseName)
        Application.getInstance().getBuildPlateModel(
        ).activeBuildPlateChanged.connect(self._onActiveBuildPlateChanged)
        Application.getInstance().workspaceLoaded.connect(self.setProjectName)

        Preferences.getInstance().preferenceChanged.connect(
            self._onPreferencesChanged)

        self._active_material_container = None
        Application.getInstance().getMachineManager(
        ).activeMaterialChanged.connect(self._onActiveMaterialChanged)
        self._onActiveMaterialChanged()

        self._material_amounts = []
Ejemplo n.º 36
0
 def _onMaterialMetaDataChanged(self, *args, **kwargs):
     for build_plate_number in range(
             Application.getInstance().getBuildPlateModel().maxBuildPlate +
             1):
         self._calculateInformation(build_plate_number)
Ejemplo n.º 37
0
    def _calculateInformation(self, build_plate_number):
        if Application.getInstance().getGlobalContainerStack() is None:
            return

        # Material amount is sent as an amount of mm^3, so calculate length from that
        radius = Application.getInstance().getGlobalContainerStack(
        ).getProperty("material_diameter", "value") / 2
        self._material_lengths[build_plate_number] = []
        self._material_weights[build_plate_number] = []
        self._material_costs[build_plate_number] = []
        self._material_names[build_plate_number] = []

        material_preference_values = json.loads(
            Preferences.getInstance().getValue("cura/material_settings"))

        extruder_stacks = list(
            ExtruderManager.getInstance().getMachineExtruders(
                Application.getInstance().getGlobalContainerStack().getId()))
        for index, amount in enumerate(self._material_amounts):
            ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
            #  list comprehension filtering to solve this for us.
            material = None
            if extruder_stacks:  # Multi extrusion machine
                extruder_stack = [
                    extruder for extruder in extruder_stacks
                    if extruder.getMetaDataEntry("position") == str(index)
                ][0]
                density = extruder_stack.getMetaDataEntry("properties",
                                                          {}).get(
                                                              "density", 0)
                material = extruder_stack.findContainer({"type": "material"})
            else:  # Machine with no extruder stacks
                density = Application.getInstance().getGlobalContainerStack(
                ).getMetaDataEntry("properties", {}).get("density", 0)
                material = Application.getInstance().getGlobalContainerStack(
                ).findContainer({"type": "material"})

            weight = float(amount) * float(density) / 1000
            cost = 0
            material_name = catalog.i18nc("@label unknown material", "Unknown")
            if material:
                material_guid = material.getMetaDataEntry("GUID")
                material_name = material.getName()
                if material_guid in material_preference_values:
                    material_values = material_preference_values[material_guid]

                    weight_per_spool = float(
                        material_values["spool_weight"] if material_values
                        and "spool_weight" in material_values else 0)
                    cost_per_spool = float(
                        material_values["spool_cost"] if material_values
                        and "spool_cost" in material_values else 0)

                    if weight_per_spool != 0:
                        cost = cost_per_spool * weight / weight_per_spool
                    else:
                        cost = 0

            if radius != 0:
                length = round((amount / (math.pi * radius**2)) / 1000, 2)
            else:
                length = 0
            self._material_weights[build_plate_number].append(weight)
            self._material_lengths[build_plate_number].append(length)
            self._material_costs[build_plate_number].append(cost)
            self._material_names[build_plate_number].append(material_name)

        self.materialLengthsChanged.emit()
        self.materialWeightsChanged.emit()
        self.materialCostsChanged.emit()
        self.materialNamesChanged.emit()
Ejemplo n.º 38
0
 def setSendSliceInfo(self, enabled: bool):
     Application.getInstance().getPreferences().setValue(
         "info/send_slice_info", enabled)
Ejemplo n.º 39
0
    def _onWriteStarted(self, output_device):
        try:
            if not Application.getInstance().getPreferences().getValue(
                    "info/send_slice_info"):
                Logger.log("d", "'info/send_slice_info' is turned off.")
                return  # Do nothing, user does not want to send data

            from cura.CuraApplication import CuraApplication
            application = cast(CuraApplication, Application.getInstance())
            machine_manager = application.getMachineManager()
            print_information = application.getPrintInformation()

            global_stack = machine_manager.activeMachine

            data = dict()  # The data that we're going to submit.
            data["time_stamp"] = time.time()
            data["schema_version"] = 0
            data["cura_version"] = application.getVersion()

            active_mode = Application.getInstance().getPreferences().getValue(
                "cura/active_mode")
            if active_mode == 0:
                data["active_mode"] = "recommended"
            else:
                data["active_mode"] = "custom"

            data["camera_view"] = application.getPreferences().getValue(
                "general/camera_perspective_mode")
            if data["camera_view"] == "orthographic":
                data[
                    "camera_view"] = "orthogonal"  #The database still only recognises the old name "orthogonal".

            definition_changes = global_stack.definitionChanges
            machine_settings_changed_by_user = False
            if definition_changes.getId() != "empty":
                # Now a definition_changes container will always be created for a stack,
                # so we also need to check if there is any instance in the definition_changes container
                if definition_changes.getAllKeys():
                    machine_settings_changed_by_user = True

            data[
                "machine_settings_changed_by_user"] = machine_settings_changed_by_user
            data["language"] = Application.getInstance().getPreferences(
            ).getValue("general/language")
            data["os"] = {
                "type": platform.system(),
                "version": platform.version()
            }

            data["active_machine"] = {
                "definition_id":
                global_stack.definition.getId(),
                "manufacturer":
                global_stack.definition.getMetaDataEntry("manufacturer", "")
            }

            # add extruder specific data to slice info
            data["extruders"] = []
            extruders = list(global_stack.extruders.values())
            extruders = sorted(
                extruders,
                key=lambda extruder: extruder.getMetaDataEntry("position"))

            for extruder in extruders:
                extruder_dict = dict()
                extruder_dict[
                    "active"] = machine_manager.activeStack == extruder
                extruder_dict["material"] = {
                    "GUID": extruder.material.getMetaData().get("GUID", ""),
                    "type":
                    extruder.material.getMetaData().get("material", ""),
                    "brand": extruder.material.getMetaData().get("brand", "")
                }
                extruder_position = int(
                    extruder.getMetaDataEntry("position", "0"))
                if len(print_information.materialLengths) > extruder_position:
                    extruder_dict[
                        "material_used"] = print_information.materialLengths[
                            extruder_position]
                extruder_dict["variant"] = extruder.variant.getName()
                extruder_dict["nozzle_size"] = extruder.getProperty(
                    "machine_nozzle_size", "value")

                extruder_settings = dict()
                extruder_settings["wall_line_count"] = extruder.getProperty(
                    "wall_line_count", "value")
                extruder_settings["retraction_enable"] = extruder.getProperty(
                    "retraction_enable", "value")
                extruder_settings[
                    "infill_sparse_density"] = extruder.getProperty(
                        "infill_sparse_density", "value")
                extruder_settings["infill_pattern"] = extruder.getProperty(
                    "infill_pattern", "value")
                extruder_settings[
                    "gradual_infill_steps"] = extruder.getProperty(
                        "gradual_infill_steps", "value")
                extruder_settings[
                    "default_material_print_temperature"] = extruder.getProperty(
                        "default_material_print_temperature", "value")
                extruder_settings[
                    "material_print_temperature"] = extruder.getProperty(
                        "material_print_temperature", "value")
                extruder_dict["extruder_settings"] = extruder_settings
                data["extruders"].append(extruder_dict)

            data["quality_profile"] = global_stack.quality.getMetaData().get(
                "quality_type")

            data[
                "user_modified_setting_keys"] = self._getUserModifiedSettingKeys(
                )

            data["models"] = []
            # Listing all files placed on the build plate
            for node in DepthFirstIterator(
                    application.getController().getScene().getRoot()):
                if node.callDecoration("isSliceable"):
                    model = dict()
                    model["hash"] = node.getMeshData().getHash()
                    bounding_box = node.getBoundingBox()
                    if not bounding_box:
                        continue
                    model["bounding_box"] = {
                        "minimum": {
                            "x": bounding_box.minimum.x,
                            "y": bounding_box.minimum.y,
                            "z": bounding_box.minimum.z
                        },
                        "maximum": {
                            "x": bounding_box.maximum.x,
                            "y": bounding_box.maximum.y,
                            "z": bounding_box.maximum.z
                        }
                    }
                    model["transformation"] = {
                        "data":
                        str(node.getWorldTransformation().getData()).replace(
                            "\n", "")
                    }
                    extruder_position = node.callDecoration(
                        "getActiveExtruderPosition")
                    model[
                        "extruder"] = 0 if extruder_position is None else int(
                            extruder_position)

                    model_settings = dict()
                    model_stack = node.callDecoration("getStack")
                    if model_stack:
                        model_settings[
                            "support_enabled"] = model_stack.getProperty(
                                "support_enable", "value")
                        model_settings["support_extruder_nr"] = int(
                            model_stack.getExtruderPositionValueWithDefault(
                                "support_extruder_nr"))

                        # Mesh modifiers;
                        model_settings[
                            "infill_mesh"] = model_stack.getProperty(
                                "infill_mesh", "value")
                        model_settings[
                            "cutting_mesh"] = model_stack.getProperty(
                                "cutting_mesh", "value")
                        model_settings[
                            "support_mesh"] = model_stack.getProperty(
                                "support_mesh", "value")
                        model_settings[
                            "anti_overhang_mesh"] = model_stack.getProperty(
                                "anti_overhang_mesh", "value")

                        model_settings[
                            "wall_line_count"] = model_stack.getProperty(
                                "wall_line_count", "value")
                        model_settings[
                            "retraction_enable"] = model_stack.getProperty(
                                "retraction_enable", "value")

                        # Infill settings
                        model_settings[
                            "infill_sparse_density"] = model_stack.getProperty(
                                "infill_sparse_density", "value")
                        model_settings[
                            "infill_pattern"] = model_stack.getProperty(
                                "infill_pattern", "value")
                        model_settings[
                            "gradual_infill_steps"] = model_stack.getProperty(
                                "gradual_infill_steps", "value")

                    model["model_settings"] = model_settings

                    data["models"].append(model)

            print_times = print_information.printTimes()
            data["print_times"] = {
                "travel":
                int(print_times["travel"].getDisplayString(
                    DurationFormat.Format.Seconds)),
                "support":
                int(print_times["support"].getDisplayString(
                    DurationFormat.Format.Seconds)),
                "infill":
                int(print_times["infill"].getDisplayString(
                    DurationFormat.Format.Seconds)),
                "total":
                int(
                    print_information.currentPrintTime.getDisplayString(
                        DurationFormat.Format.Seconds))
            }

            print_settings = dict()
            print_settings["layer_height"] = global_stack.getProperty(
                "layer_height", "value")

            # Support settings
            print_settings["support_enabled"] = global_stack.getProperty(
                "support_enable", "value")
            print_settings["support_extruder_nr"] = int(
                global_stack.getExtruderPositionValueWithDefault(
                    "support_extruder_nr"))

            # Platform adhesion settings
            print_settings["adhesion_type"] = global_stack.getProperty(
                "adhesion_type", "value")

            # Shell settings
            print_settings["wall_line_count"] = global_stack.getProperty(
                "wall_line_count", "value")
            print_settings["retraction_enable"] = global_stack.getProperty(
                "retraction_enable", "value")

            # Prime tower settings
            print_settings["prime_tower_enable"] = global_stack.getProperty(
                "prime_tower_enable", "value")

            # Infill settings
            print_settings["infill_sparse_density"] = global_stack.getProperty(
                "infill_sparse_density", "value")
            print_settings["infill_pattern"] = global_stack.getProperty(
                "infill_pattern", "value")
            print_settings["gradual_infill_steps"] = global_stack.getProperty(
                "gradual_infill_steps", "value")

            print_settings["print_sequence"] = global_stack.getProperty(
                "print_sequence", "value")

            data["print_settings"] = print_settings

            # Send the name of the output device type that is used.
            data["output_to"] = type(output_device).__name__

            # Convert data to bytes
            binary_data = json.dumps(data).encode("utf-8")

            # Sending slice info non-blocking
            reportJob = SliceInfoJob(self.info_url, binary_data)
            reportJob.start()
        except Exception:
            # We really can't afford to have a mistake here, as this would break the sending of g-code to a device
            # (Either saving or directly to a printer). The functionality of the slice data is not *that* important.
            Logger.logException(
                "e", "Exception raised while sending slice info."
            )  # But we should be notified about these problems of course.
Ejemplo n.º 40
0
    def event(self, event):
        if event.type == Event.ViewActivateEvent:
            # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching.
            # This can happen when you do the following steps:
            #   1. Start Cura
            #   2. Load a model
            #   3. Switch to Custom mode
            #   4. Select the model and click on the per-object tool icon
            #   5. Switch view to Layer view or X-Ray
            #   6. Cura will very likely crash
            # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why.
            # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL
            # context is None.
            if Platform.isOSX():
                if QOpenGLContext.currentContext() is None:
                    Logger.log(
                        "d",
                        "current context of OpenGL is empty on Mac OS X, will try to create shaders later"
                    )
                    CuraApplication.getInstance().callLater(
                        lambda e=event: self.event(e))
                    return

            if not self._xray_pass:
                # Currently the RenderPass constructor requires a size > 0
                # This should be fixed in RenderPass's constructor.
                self._xray_pass = XRayPass.XRayPass(1, 1)

            self.getRenderer().addRenderPass(self._xray_pass)

            if not self._xray_composite_shader:
                self._xray_composite_shader = OpenGL.getInstance(
                ).createShaderProgram(
                    Resources.getPath(Resources.Shaders,
                                      "xray_composite.shader"))
                theme = Application.getInstance().getTheme()
                self._xray_composite_shader.setUniformValue(
                    "u_background_color",
                    Color(*theme.getColor("viewport_background").getRgb()))
                self._xray_composite_shader.setUniformValue(
                    "u_outline_color",
                    Color(*theme.getColor("model_selection_outline").getRgb()))
                self._xray_composite_shader.setUniformValue(
                    "u_flat_error_color_mix",
                    1.)  # Show flat error color _only_ in xray-view.

            if not self._composite_pass:
                self._composite_pass = self.getRenderer().getRenderPass(
                    "composite")

            self._old_layer_bindings = self._composite_pass.getLayerBindings()
            self._composite_pass.setLayerBindings(
                ["default", "selection", "xray"])
            self._old_composite_shader = self._composite_pass.getCompositeShader(
            )
            self._composite_pass.setCompositeShader(
                self._xray_composite_shader)

        if event.type == Event.ViewDeactivateEvent:
            self.getRenderer().removeRenderPass(self._xray_pass)
            self._composite_pass.setLayerBindings(self._old_layer_bindings)
            self._composite_pass.setCompositeShader(self._old_composite_shader)
Ejemplo n.º 41
0
 def _onContainerAdded(self, container):
     # Add this action as a supported action to all machine definitions
     if isinstance(container, DefinitionContainer
                   ) and container.getMetaDataEntry("type") == "machine":
         Application.getInstance().getMachineActionManager(
         ).addSupportedAction(container.getId(), self.getKey())
Ejemplo n.º 42
0
 def messageActionTriggered(self, message_id, action_id):
     Application.getInstance().getPreferences().setValue(
         "info/asked_send_slice_info", True)
     if action_id == "MoreInfo":
         self.showMoreInfoDialog()
     self.send_slice_info_message.hide()
Ejemplo n.º 43
0
    def setMachineExtruderCount(self, extruder_count):
        machine_manager = Application.getInstance().getMachineManager()
        extruder_manager = ExtruderManager.getInstance()

        definition_changes_container = self._global_container_stack.definitionChanges
        if not self._global_container_stack or definition_changes_container == self._empty_container:
            return

        previous_extruder_count = self._global_container_stack.getProperty(
            "machine_extruder_count", "value")
        if extruder_count == previous_extruder_count:
            return

        extruder_material_id = None
        extruder_variant_id = None
        if extruder_count == 1:
            # Get the material and variant of the first extruder before setting the number extruders to 1
            if machine_manager.hasMaterials:
                extruder_material_id = machine_manager.allActiveMaterialIds[
                    extruder_manager.extruderIds["0"]]
            if machine_manager.hasVariants:
                extruder_variant_id = machine_manager.allActiveVariantIds[
                    extruder_manager.extruderIds["0"]]

            # Copy any settable_per_extruder setting value from the extruders to the global stack
            extruder_stacks = ExtruderManager.getInstance(
            ).getActiveExtruderStacks()
            extruder_stacks.reverse(
            )  # make sure the first extruder is done last, so its settings override any higher extruder settings

            global_user_container = self._global_container_stack.getTop()
            for extruder_stack in extruder_stacks:
                extruder_index = extruder_stack.getMetaDataEntry("position")
                extruder_user_container = extruder_stack.getTop()
                for setting_instance in extruder_user_container.findInstances(
                ):
                    setting_key = setting_instance.definition.key
                    settable_per_extruder = self._global_container_stack.getProperty(
                        setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        limit_to_extruder = self._global_container_stack.getProperty(
                            setting_key, "limit_to_extruder")

                        if limit_to_extruder == "-1" or limit_to_extruder == extruder_index:
                            global_user_container.setProperty(
                                setting_key, "value",
                                extruder_user_container.getProperty(
                                    setting_key, "value"))
                            extruder_user_container.removeInstance(setting_key)

        # Check to see if any features are set to print with an extruder that will no longer exist
        for setting_key in [
                "adhesion_extruder_nr", "support_extruder_nr",
                "support_extruder_nr_layer_0", "support_infill_extruder_nr",
                "support_interface_extruder_nr"
        ]:
            if int(
                    self._global_container_stack.getProperty(
                        setting_key, "value")) > extruder_count - 1:
                Logger.log("i",
                           "Lowering %s setting to match number of extruders",
                           setting_key)
                self._global_container_stack.getTop().setProperty(
                    setting_key, "value", extruder_count - 1)

        # Check to see if any objects are set to print with an extruder that will no longer exist
        root_node = Application.getInstance().getController().getScene(
        ).getRoot()
        for node in DepthFirstIterator(root_node):
            if node.getMeshData():
                extruder_nr = node.callDecoration("getActiveExtruderPosition")

                if extruder_nr is not None and int(
                        extruder_nr) > extruder_count - 1:
                    node.callDecoration(
                        "setActiveExtruder",
                        extruder_manager.getExtruderStack(extruder_count -
                                                          1).getId())

        definition_changes_container.setProperty("machine_extruder_count",
                                                 "value", extruder_count)
        self.forceUpdate()

        if extruder_count > 1:
            # Multiextrusion

            # Make sure one of the extruder stacks is active
            if extruder_manager.activeExtruderIndex == -1:
                extruder_manager.setActiveExtruderIndex(0)

            # Move settable_per_extruder values out of the global container
            if previous_extruder_count == 1:
                extruder_stacks = ExtruderManager.getInstance(
                ).getActiveExtruderStacks()
                global_user_container = self._global_container_stack.getTop()

                for setting_instance in global_user_container.findInstances():
                    setting_key = setting_instance.definition.key
                    settable_per_extruder = self._global_container_stack.getProperty(
                        setting_key, "settable_per_extruder")
                    if settable_per_extruder:
                        limit_to_extruder = int(
                            self._global_container_stack.getProperty(
                                setting_key, "limit_to_extruder"))
                        extruder_stack = extruder_stacks[max(
                            0, limit_to_extruder)]
                        extruder_stack.getTop().setProperty(
                            setting_key, "value",
                            global_user_container.getProperty(
                                setting_key, "value"))
                        global_user_container.removeInstance(setting_key)
        else:
            # Single extrusion

            # Make sure the machine stack is active
            if extruder_manager.activeExtruderIndex > -1:
                extruder_manager.setActiveExtruderIndex(-1)

            # Restore material and variant on global stack
            # MachineManager._onGlobalContainerChanged removes the global material and variant of multiextruder machines
            if extruder_material_id or extruder_variant_id:
                # Prevent the DiscardOrKeepProfileChangesDialog from popping up (twice) if there are user changes
                # The dialog is not relevant here, since we're restoring the previous situation as good as possible
                preferences = Preferences.getInstance()
                choice_on_profile_override = preferences.getValue(
                    "cura/choice_on_profile_override")
                preferences.setValue("cura/choice_on_profile_override",
                                     "always_keep")

                if extruder_material_id:
                    machine_manager.setActiveMaterial(extruder_material_id)
                if extruder_variant_id:
                    machine_manager.setActiveVariant(extruder_variant_id)

                preferences.setValue("cura/choice_on_profile_override",
                                     choice_on_profile_override)
    def __init__(self):
        super().__init__()

        self._scene_objects = set()
        self._scene = Application.getInstance().getController().getScene()
        self._scene.sceneChanged.connect(self.onSceneChanged)
Ejemplo n.º 45
0
 def __init__(self, file_name):
     super().__init__()
     self._file_name = file_name
     self._mesh_handler = Application.getInstance().getMeshFileHandler()
Ejemplo n.º 46
0
 def forceUpdate(self):
     # Force rebuilding the build volume by reloading the global container stack.
     # This is a bit of a hack, but it seems quick enough.
     Application.getInstance().globalContainerStackChanged.emit()
Ejemplo n.º 47
0
 def __init__(self):
     super().__init__()
     self._shortcut_key = Qt.Key_G
     self._controller = Application.getInstance().getController()
Ejemplo n.º 48
0
    def _onGlobalContainerChanged(self):
        self._global_container_stack = Application.getInstance(
        ).getGlobalContainerStack()

        # This additional emit is needed because we cannot connect a UM.Signal directly to a pyqtSignal
        self.globalContainerChanged.emit()
Ejemplo n.º 49
0
 def startPrint(self):
     self.writeStarted.emit(self)
     gcode_list = getattr(
         Application.getInstance().getController().getScene(), "gcode_list")
     self._updateJobState("printing")
     self.printGCode(gcode_list)
Ejemplo n.º 50
0
    def requestWrite(self, nodes, file_name = None, limit_mimetypes = None, file_handler = None, **kwargs):
        """Request the specified nodes to be written to a file.

        :param nodes: A collection of scene nodes that should be written to the
        file.
        :param file_name: A suggestion for the file name to write
        to. Can be freely ignored if providing a file name makes no sense.
        :param limit_mimetypes: Should we limit the available MIME types to the
        MIME types available to the currently active machine?
        :param kwargs: Keyword arguments.
        """

        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        # Set up and display file dialog
        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None

        if "preferred_mimetypes" in kwargs and kwargs["preferred_mimetypes"] is not None:
            preferred_mimetypes = kwargs["preferred_mimetypes"]
        else:
            preferred_mimetypes = Application.getInstance().getPreferences().getValue("local_file/last_used_type")
        preferred_mimetype_list = preferred_mimetypes.split(";")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key = lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(filter(lambda i: i["mime_type"] in limit_mimetypes, file_types))

        file_types = [ft for ft in file_types if not ft["hide_in_file_dialog"]]

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:warning", "There are no file types available to write with!"))

        # Find the first available preferred mime type
        preferred_mimetype = None
        for mime_type in preferred_mimetype_list:
            if any(ft["mime_type"] == mime_type for ft in file_types):
                preferred_mimetype = mime_type
                break

        extension_added = False
        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"], item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if preferred_mimetype == item["mime_type"]:
                selected_filter = type_filter
                if file_name and not extension_added:
                    extension_added = True
                    file_name += "." + item["extension"]

        # CURA-6411: This code needs to be before dialog.selectFile and the filters, because otherwise in macOS (for some reason) the setDirectory call doesn't work.
        stored_directory = Application.getInstance().getPreferences().getValue("local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        # Add the file name before adding the extension to the dialog
        if file_name is not None:
            dialog.selectFile(file_name)

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Application.getInstance().getPreferences().setValue("local_file/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Application.getInstance().getPreferences().setValue("local_file/last_used_type", selected_type["mime_type"])

        # Get file name from file dialog
        file_name = dialog.selectedFiles()[0]
        Logger.log("d", "Writing to [%s]..." % file_name)

        if os.path.exists(file_name):
            result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"), catalog.i18nc("@label Don't translate the XML tag <filename>!", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        # Actually writing file
        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler().getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode", file_name)
                stream = open(file_name, "wt", encoding = "utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode", file_name)
                stream = open(file_name, "wb")
            else:
                Logger.log("e", "Unrecognised OutputMode.")
                return None

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.setAddToRecentFiles(True)  # The file will be added into the "recent files" list upon success
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(catalog.i18nc("@info:progress Don't translate the XML tags <filename>!", "Saving to <filename>{0}</filename>").format(file_name),
                              0, False, -1 , catalog.i18nc("@info:title", "Saving"))
            message.show()

            job.setMessage(message)
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s", file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(catalog.i18nc("@info:status Don't translate the XML tags <filename>!", "Permission denied when trying to save <filename>{0}</filename>").format(file_name)) from e
        except OSError as e:
            Logger.log("e", "Operating system would not let us write to %s: %s", file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
Ejemplo n.º 51
0
 def _onDontAskMeAgain(self, checked: bool) -> None:
     Application.getInstance().getPreferences().setValue(
         self._show_xray_warning_preference, not checked)
Ejemplo n.º 52
0
 def requestWrite(self, node, file_name=None, filter_by_machine=False):
     Application.getInstance().showPrintMonitor.emit(True)
     self.startPrint()
Ejemplo n.º 53
0
    def _checkSetup(self):
        if not self._extruders_model:
            self._extruders_model = Application.getInstance(
            ).getExtrudersModel()

        if not self._theme:
            self._theme = Application.getInstance().getTheme()

        if not self._enabled_shader:
            self._enabled_shader = OpenGL.getInstance().createShaderProgram(
                Resources.getPath(Resources.Shaders, "overhang.shader"))
            self._enabled_shader.setUniformValue(
                "u_overhangColor",
                Color(*self._theme.getColor("model_overhang").getRgb()))
            self._enabled_shader.setUniformValue("u_renderError", 0.0)

        if not self._disabled_shader:
            self._disabled_shader = OpenGL.getInstance().createShaderProgram(
                Resources.getPath(Resources.Shaders, "striped.shader"))
            self._disabled_shader.setUniformValue(
                "u_diffuseColor1",
                Color(*self._theme.getColor("model_unslicable").getRgb()))
            self._disabled_shader.setUniformValue(
                "u_diffuseColor2",
                Color(*self._theme.getColor("model_unslicable_alt").getRgb()))
            self._disabled_shader.setUniformValue("u_width", 50.0)

        if not self._non_printing_shader:
            self._non_printing_shader = OpenGL.getInstance(
            ).createShaderProgram(
                Resources.getPath(Resources.Shaders,
                                  "transparent_object.shader"))
            self._non_printing_shader.setUniformValue(
                "u_diffuseColor",
                Color(*self._theme.getColor("model_non_printing").getRgb()))
            self._non_printing_shader.setUniformValue("u_opacity", 0.6)

        if not self._support_mesh_shader:
            self._support_mesh_shader = OpenGL.getInstance(
            ).createShaderProgram(
                Resources.getPath(Resources.Shaders, "striped.shader"))
            self._support_mesh_shader.setUniformValue("u_vertical_stripes",
                                                      True)
            self._support_mesh_shader.setUniformValue("u_width", 5.0)

        if not Application.getInstance().getPreferences().getValue(
                self._show_xray_warning_preference):
            self._xray_shader = None
            self._xray_composite_shader = None
            if self._composite_pass and 'xray' in self._composite_pass.getLayerBindings(
            ):
                self._composite_pass.setLayerBindings(self._old_layer_bindings)
                self._composite_pass.setCompositeShader(
                    self._old_composite_shader)
                self._old_layer_bindings = None
                self._old_composite_shader = None
                self._enabled_shader.setUniformValue(
                    "u_renderError", 0.0)  # We don't want any error markers!.
                self._xray_warning_message.hide()
        else:
            if not self._xray_shader:
                self._xray_shader = OpenGL.getInstance().createShaderProgram(
                    Resources.getPath(Resources.Shaders, "xray.shader"))

            if not self._xray_composite_shader:
                self._xray_composite_shader = OpenGL.getInstance(
                ).createShaderProgram(
                    Resources.getPath(Resources.Shaders,
                                      "xray_composite.shader"))
                theme = Application.getInstance().getTheme()
                self._xray_composite_shader.setUniformValue(
                    "u_background_color",
                    Color(*theme.getColor("viewport_background").getRgb()))
                self._xray_composite_shader.setUniformValue(
                    "u_outline_color",
                    Color(*theme.getColor("model_selection_outline").getRgb()))
                self._xray_composite_shader.setUniformValue(
                    "u_flat_error_color_mix",
                    0.)  # Don't show flat error color in solid-view.

            renderer = self.getRenderer()
            if not self._composite_pass or not 'xray' in self._composite_pass.getLayerBindings(
            ):
                # Currently the RenderPass constructor requires a size > 0
                # This should be fixed in RenderPass's constructor.
                self._xray_pass = XRayPass.XRayPass(1, 1)
                self._enabled_shader.setUniformValue(
                    "u_renderError", 1.0)  # We don't want any error markers!.
                renderer.addRenderPass(self._xray_pass)

                if not self._composite_pass:
                    self._composite_pass = self.getRenderer().getRenderPass(
                        "composite")

                self._old_layer_bindings = self._composite_pass.getLayerBindings(
                )
                self._composite_pass.setLayerBindings(
                    ["default", "selection", "xray"])
                self._old_composite_shader = self._composite_pass.getCompositeShader(
                )
                self._composite_pass.setCompositeShader(
                    self._xray_composite_shader)
Ejemplo n.º 54
0
    def requestWrite(self, nodes, file_name=None, filter_by_machine=False):
        filter_by_machine = True  # This plugin is indended to be used by machine (regardless of what it was told to do)
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        # Formats supported by this application (File types that we can actually write)
        file_formats = Application.getInstance().getMeshFileHandler(
        ).getSupportedFileTypesWrite()
        if filter_by_machine:
            container = Application.getInstance().getGlobalContainerStack(
            ).findContainer({"file_formats": "*"})

            # Create a list from supported file formats string
            machine_file_formats = [
                file_type.strip() for file_type in container.getMetaDataEntry(
                    "file_formats").split(";")
            ]

            # Take the intersection between file_formats and machine_file_formats.
            file_formats = list(
                filter(
                    lambda file_format: file_format["mime_type"] in
                    machine_file_formats, file_formats))

        if len(file_formats) == 0:
            Logger.log("e",
                       "There are no file formats available to write with!")
            raise OutputDeviceError.WriteRequestFailedError()

        # Just take the first file format available.
        writer = Application.getInstance().getMeshFileHandler(
        ).getWriterByMimeType(file_formats[0]["mime_type"])
        extension = file_formats[0]["extension"]

        if file_name is None:
            file_name = self._automaticFileName(nodes)

        if extension:  # Not empty string.
            extension = "." + extension
        file_name = os.path.join(self.getId(),
                                 os.path.splitext(file_name)[0] + extension)

        try:
            Logger.log("d", "Writing to %s", file_name)
            # Using buffering greatly reduces the write time for many lines of gcode
            self._stream = open(file_name, "wt", buffering=1, encoding="utf-8")
            job = WriteMeshJob(writer, self._stream, nodes,
                               MeshWriter.OutputMode.TextMode)
            job.setFileName(file_name)
            job.progress.connect(self._onProgress)
            job.finished.connect(self._onFinished)

            message = Message(
                catalog.i18nc(
                    "@info:progress",
                    "Saving to Removable Drive <filename>{0}</filename>").
                format(self.getName()), 0, False, -1)
            message.show()

            self.writeStarted.emit(self)

            job._message = message
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                catalog.i18nc(
                    "@info:status",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format(file_name, str(e))) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:status",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format(file_name, str(e))) from e
Ejemplo n.º 55
0
 def _createViewFromQML(self):
     path = os.path.join(
         PluginRegistry.getInstance().getPluginPath("3MFReader"),
         self._qml_url)
     self._view = Application.getInstance().createQmlComponent(
         path, {"manager": self})
Ejemplo n.º 56
0
    def beginRendering(self):
        scene = self.getController().getScene()
        renderer = self.getRenderer()

        self._checkSetup()

        global_container_stack = Application.getInstance(
        ).getGlobalContainerStack()
        if global_container_stack:
            if Application.getInstance().getPreferences().getValue(
                    "view/show_overhang"):
                # Make sure the overhang angle is valid before passing it to the shader
                if self._support_angle >= 0 and self._support_angle <= 90:
                    self._enabled_shader.setUniformValue(
                        "u_overhangAngle",
                        math.cos(math.radians(90 - self._support_angle)))
                else:
                    self._enabled_shader.setUniformValue(
                        "u_overhangAngle", math.cos(math.radians(0))
                    )  #Overhang angle of 0 causes no area at all to be marked as overhang.
            else:
                self._enabled_shader.setUniformValue("u_overhangAngle",
                                                     math.cos(math.radians(0)))
        self._enabled_shader.setUniformValue("u_lowestPrintableHeight",
                                             self._lowest_printable_height)
        disabled_batch = renderer.createRenderBatch(
            shader=self._disabled_shader)
        normal_object_batch = renderer.createRenderBatch(
            shader=self._enabled_shader)
        renderer.addRenderBatch(disabled_batch)
        renderer.addRenderBatch(normal_object_batch)
        for node in DepthFirstIterator(scene.getRoot()):
            if node.render(renderer):
                continue

            if node.getMeshData() and node.isVisible():
                uniforms = {}
                shade_factor = 1.0

                per_mesh_stack = node.callDecoration("getStack")

                extruder_index = node.callDecoration(
                    "getActiveExtruderPosition")
                if extruder_index is None:
                    extruder_index = "0"
                extruder_index = int(extruder_index)

                try:
                    material_color = self._extruders_model.getItem(
                        extruder_index)["color"]
                except KeyError:
                    material_color = self._extruders_model.defaultColors[0]

                if extruder_index != ExtruderManager.getInstance(
                ).activeExtruderIndex:
                    # Shade objects that are printed with the non-active extruder 25% darker
                    shade_factor = 0.6

                try:
                    # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
                    # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
                    uniforms["diffuse_color"] = [
                        shade_factor * int(material_color[1:3], 16) / 255,
                        shade_factor * int(material_color[3:5], 16) / 255,
                        shade_factor * int(material_color[5:7], 16) / 255, 1.0
                    ]

                    # Color the currently selected face-id. (Disable for now.)
                    #face = Selection.getHoverFace()
                    uniforms[
                        "hover_face"] = -1  #if not face or node != face[0] else face[1]
                except ValueError:
                    pass

                if node.callDecoration("isNonPrintingMesh"):
                    if per_mesh_stack and (
                            node.callDecoration("isInfillMesh")
                            or node.callDecoration("isCuttingMesh")):
                        renderer.queueNode(node,
                                           shader=self._non_printing_shader,
                                           uniforms=uniforms,
                                           transparent=True)
                    else:
                        renderer.queueNode(node,
                                           shader=self._non_printing_shader,
                                           transparent=True)
                elif getattr(node, "_outside_buildarea", False):
                    disabled_batch.addItem(
                        node.getWorldTransformation(copy=False),
                        node.getMeshData(),
                        normal_transformation=node.getCachedNormalMatrix())
                elif per_mesh_stack and node.callDecoration("isSupportMesh"):
                    # Render support meshes with a vertical stripe that is darker
                    shade_factor = 0.6
                    uniforms["diffuse_color_2"] = [
                        uniforms["diffuse_color"][0] * shade_factor,
                        uniforms["diffuse_color"][1] * shade_factor,
                        uniforms["diffuse_color"][2] * shade_factor, 1.0
                    ]
                    renderer.queueNode(node,
                                       shader=self._support_mesh_shader,
                                       uniforms=uniforms)
                else:
                    normal_object_batch.addItem(
                        node.getWorldTransformation(copy=False),
                        node.getMeshData(),
                        uniforms=uniforms,
                        normal_transformation=node.getCachedNormalMatrix())
            if node.callDecoration("isGroup") and Selection.isSelected(node):
                renderer.queueNode(scene.getRoot(),
                                   mesh=node.getBoundingBoxMesh(),
                                   mode=RenderBatch.RenderMode.LineLoop)
Ejemplo n.º 57
0
    def run(self):
        if Application.getInstance().getController().getActiveView(
        ).getPluginId() == "LayerView":
            self._progress = Message(catalog.i18nc("@info", "Layers"), 0,
                                     False, 0)
            self._progress.show()

        Application.getInstance().getController().activeViewChanged.connect(
            self._onActiveViewChanged)

        objectIdMap = {}
        new_node = SceneNode()
        ## Put all nodes in a dict identified by ID
        for node in DepthFirstIterator(self._scene.getRoot()):
            if type(node) is SceneNode and node.getMeshData():
                if node.callDecoration("getLayerData"):
                    #if hasattr(node.getMeshData(), "layerData"):
                    self._scene.getRoot().removeChild(node)
                else:
                    objectIdMap[id(node)] = node

        settings = Application.getInstance().getMachineManager(
        ).getActiveProfile()
        layerHeight = settings.getSettingValue("layer_height")

        center = None
        if not settings.getSettingValue("machine_center_is_zero"):
            center = numpy.array([
                settings.getSettingValue("machine_width") / 2, 0.0,
                -settings.getSettingValue("machine_depth") / 2
            ])
        else:
            center = numpy.array([0.0, 0.0, 0.0])

        if self._progress:
            self._progress.setProgress(2)

        mesh = MeshData()
        layer_data = LayerData.LayerData()
        for object in self._message.objects:
            try:
                node = objectIdMap[object.id]
            except KeyError:
                continue

            for layer in object.layers:
                layer_data.addLayer(layer.id)
                layer_data.setLayerHeight(layer.id, layer.height)
                layer_data.setLayerThickness(layer.id, layer.thickness)
                for polygon in layer.polygons:
                    points = numpy.fromstring(
                        polygon.points,
                        dtype="i8")  # Convert bytearray to numpy array
                    points = points.reshape(
                        (-1, 2)
                    )  # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
                    points = numpy.asarray(points, dtype=numpy.float32)
                    points /= 1000
                    points = numpy.insert(points,
                                          1, (layer.height / 1000),
                                          axis=1)

                    points[:, 2] *= -1

                    points -= numpy.array(center)

                    layer_data.addPolygon(layer.id, polygon.type, points,
                                          polygon.line_width)

        if self._progress:
            self._progress.setProgress(50)

        # We are done processing all the layers we got from the engine, now create a mesh out of the data
        layer_data.build()

        if self._progress:
            self._progress.setProgress(100)

        #Add layerdata decorator to scene node to indicate that the node has layerdata
        decorator = LayerDataDecorator.LayerDataDecorator()
        decorator.setLayerData(layer_data)
        new_node.addDecorator(decorator)

        new_node.setMeshData(mesh)
        new_node.setParent(self._scene.getRoot())

        view = Application.getInstance().getController().getActiveView()
        if view.getPluginId() == "LayerView":
            view.resetLayerData()

        if self._progress:
            self._progress.hide()
Ejemplo n.º 58
0
    def event(self, event):
        modifiers = QApplication.keyboardModifiers()
        ctrl_is_active = modifiers & Qt.ControlModifier
        shift_is_active = modifiers & Qt.ShiftModifier
        if event.type == Event.KeyPressEvent and ctrl_is_active:
            amount = 10 if shift_is_active else 1
            if event.key == KeyEvent.UpKey:
                self.setLayer(self._current_layer_num + amount)
                return True
            if event.key == KeyEvent.DownKey:
                self.setLayer(self._current_layer_num - amount)
                return True
            if event.type == Event.MouseWheelEvent and ctrl_is_active:
                amount = 10 if shift_is_active else 1
                vertical_delta = str(event.vertical)
                if event.vertical > 0:
                    self.setLayer(self._current_layer_num + amount)
                    return True
                if event.vertical < 0:
                    self.setLayer(self._current_layer_num - amount)
                    return True

        if event.type == Event.ViewActivateEvent:
            # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching.
            # This can happen when you do the following steps:
            #   1. Start Cura
            #   2. Load a model
            #   3. Switch to Custom mode
            #   4. Select the model and click on the per-object tool icon
            #   5. Switch view to Layer view or X-Ray
            #   6. Cura will very likely crash
            # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why.
            # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL
            # context is None.
            if Platform.isOSX():
                if QOpenGLContext.currentContext() is None:
                    Logger.log(
                        "d",
                        "current context of OpenGL is empty on Mac OS X, will try to create shaders later"
                    )
                    CuraApplication.getInstance().callLater(
                        lambda e=event: self.event(e))
                    return

            # Make sure the SimulationPass is created
            layer_pass = self.getSimulationPass()
            self.getRenderer().addRenderPass(layer_pass)

            # Make sure the NozzleNode is add to the root
            nozzle = self.getNozzleNode()
            nozzle.setParent(self.getController().getScene().getRoot())
            nozzle.setVisible(False)

            Application.getInstance().globalContainerStackChanged.connect(
                self._onGlobalStackChanged)
            self._onGlobalStackChanged()

            if not self._simulationview_composite_shader:
                self._simulationview_composite_shader = OpenGL.getInstance(
                ).createShaderProgram(
                    os.path.join(
                        PluginRegistry.getInstance().getPluginPath(
                            "SimulationView"),
                        "simulationview_composite.shader"))
                theme = Application.getInstance().getTheme()
                self._simulationview_composite_shader.setUniformValue(
                    "u_background_color",
                    Color(*theme.getColor("viewport_background").getRgb()))
                self._simulationview_composite_shader.setUniformValue(
                    "u_outline_color",
                    Color(*theme.getColor("model_selection_outline").getRgb()))

            if not self._composite_pass:
                self._composite_pass = self.getRenderer().getRenderPass(
                    "composite")

            self._old_layer_bindings = self._composite_pass.getLayerBindings(
            )[:]  # make a copy so we can restore to it later
            self._composite_pass.getLayerBindings().append("simulationview")
            self._old_composite_shader = self._composite_pass.getCompositeShader(
            )
            self._composite_pass.setCompositeShader(
                self._simulationview_composite_shader)

        elif event.type == Event.ViewDeactivateEvent:
            self._wireprint_warning_message.hide()
            Application.getInstance().globalContainerStackChanged.disconnect(
                self._onGlobalStackChanged)
            if self._global_container_stack:
                self._global_container_stack.propertyChanged.disconnect(
                    self._onPropertyChanged)

            self._nozzle_node.setParent(None)
            self.getRenderer().removeRenderPass(self._layer_pass)
            self._composite_pass.setLayerBindings(self._old_layer_bindings)
            self._composite_pass.setCompositeShader(self._old_composite_shader)
Ejemplo n.º 59
0
 def __init__(self, message):
     super().__init__()
     self._message = message
     self._scene = Application.getInstance().getController().getScene()
     self._progress = None
Ejemplo n.º 60
0
 def closeBackend(self):
     Application.getInstance().getBackend().close()