def createOutputModel(self) -> MaterialOutputModel:
        material_manager = CuraApplication.getInstance().getMaterialManager()
        material_group_list = material_manager.getMaterialGroupListByGUID(self.guid) or []

        # Sort the material groups by "is_read_only = True" first, and then the name alphabetically.
        read_only_material_group_list = list(filter(lambda x: x.is_read_only, material_group_list))
        non_read_only_material_group_list = list(filter(lambda x: not x.is_read_only, material_group_list))
        material_group = None
        if read_only_material_group_list:
            read_only_material_group_list = sorted(read_only_material_group_list, key = lambda x: x.name)
            material_group = read_only_material_group_list[0]
        elif non_read_only_material_group_list:
            non_read_only_material_group_list = sorted(non_read_only_material_group_list, key = lambda x: x.name)
            material_group = non_read_only_material_group_list[0]

        if material_group:
            container = material_group.root_material_node.getContainer()
            color = container.getMetaDataEntry("color_code")
            brand = container.getMetaDataEntry("brand")
            material_type = container.getMetaDataEntry("material")
            name = container.getName()
        else:
            Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster"
                       .format(guid = self.guid))
            color = self.color
            brand = self.brand
            material_type = self.material
            name = "Empty" if self.material == "empty" else "Unknown"

        return MaterialOutputModel(guid = self.guid, type = material_type, brand = brand, color = color, name = name)
Example #2
0
    def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1):
        new_node = copy.deepcopy(node)
        best_spot = self.bestSpot(
            offset_shape_arr, start_prio = self._last_priority, step = step)
        x, y = best_spot.x, best_spot.y

        # Save the last priority.
        self._last_priority = best_spot.priority

        # Ensure that the object is above the build platform
        new_node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
        if new_node.getBoundingBox():
            center_y = new_node.getWorldPosition().y - new_node.getBoundingBox().bottom
        else:
            center_y = 0

        if x is not None:  # We could find a place
            new_node.setPosition(Vector(x, center_y, y))
            found_spot = True
            self.place(x, y, hull_shape_arr)  # place the object in arranger
        else:
            Logger.log("d", "Could not find spot!"),
            found_spot = False
            new_node.setPosition(Vector(200, center_y, 100))
        return new_node, found_spot
Example #3
0
 def _materialWarningMessageAction(self, message, button):
     if button == "Undo":
         container_manager = ContainerManager.getInstance()
         container_manager.setContainerMetaDataEntry(self._material_diameter_warning_message.material_id, "properties/diameter", self._material_diameter_warning_message.previous_diameter)
         message.hide()
     else:
         Logger.log("w", "Unknown button action for material diameter warning message: {action}".format(action = button))
Example #4
0
    def fixSingleExtrusionMachineExtruderDefinition(self, global_stack: "GlobalStack") -> None:
        container_registry = ContainerRegistry.getInstance()
        expected_extruder_definition_0_id = global_stack.getMetaDataEntry("machine_extruder_trains")["0"]
        extruder_stack_0 = global_stack.extruders.get("0")
        # At this point, extruder stacks for this machine may not have been loaded yet. In this case, need to look in
        # the container registry as well.
        if not global_stack.extruders:
            extruder_trains = container_registry.findContainerStacks(type = "extruder_train",
                                                                     machine = global_stack.getId())
            if extruder_trains:
                for extruder in extruder_trains:
                    if extruder.getMetaDataEntry("position") == "0":
                        extruder_stack_0 = extruder
                        break

        if extruder_stack_0 is None:
            Logger.log("i", "No extruder stack for global stack [%s], create one", global_stack.getId())
            # Single extrusion machine without an ExtruderStack, create it
            from cura.Settings.CuraStackBuilder import CuraStackBuilder
            CuraStackBuilder.createExtruderStackWithDefaultSetup(global_stack, 0)

        elif extruder_stack_0.definition.getId() != expected_extruder_definition_0_id:
            Logger.log("e", "Single extruder printer [{printer}] expected extruder [{expected}], but got [{got}]. I'm making it [{expected}].".format(
                printer = global_stack.getId(), expected = expected_extruder_definition_0_id, got = extruder_stack_0.definition.getId()))
            extruder_definition = container_registry.findDefinitionContainers(id = expected_extruder_definition_0_id)[0]
            extruder_stack_0.definition = extruder_definition
Example #5
0
    def read(self, file_name):
        if file_name.split(".")[-1] != "gcode":
            return None

        prefix = ";SETTING_" + str(GCodeProfileReader.version) + " "
        prefix_length = len(prefix)

        # Loading all settings from the file.
        # They are all at the end, but Python has no reverse seek any more since Python3.
        # TODO: Consider moving settings to the start?
        serialized = ""  # Will be filled with the serialized profile.
        try:
            with open(file_name) as f:
                for line in f:
                    if line.startswith(prefix):
                        # Remove the prefix and the newline from the line and add it to the rest.
                        serialized += line[prefix_length : -1]
        except IOError as e:
            Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
            return None

        serialized = unescapeGcodeComment(serialized)
        Logger.log("i", "Serialized the following from %s: %s" %(file_name, repr(serialized)))

        json_data = json.loads(serialized)

        profile_strings = [json_data["global_quality"]]
        profile_strings.extend(json_data.get("extruder_quality", []))

        return [readQualityProfileFromString(profile_string) for profile_string in profile_strings]
Example #6
0
 def addInputDevice(self, device):
     name = device.getPluginId()
     if(name not in self._input_devices):
         self._input_devices[name] = device
         device.event.connect(self.event)
     else:
         Logger.log("w", "%s was already added to input device list. Unable to add it again." % name)
Example #7
0
    def read(self, file_name, **kwargs):
        try:
            for id, reader in self._mesh_readers.items():
                result = reader.read(file_name)
                if result is not None:
                    if kwargs.get("center", True):
                        # If the result has a mesh and no children it needs to be centered
                        if result.getMeshData() and len(result.getChildren()) == 0:
                            extents = result.getMeshData().getExtents()
                            move_vector = Vector()
                            move_vector.setX(extents.center.x)
                            move_vector.setY(extents.center.y) # Ensure that bottom is on 0 (above plate)
                            move_vector.setZ(extents.center.z)
                            result.setCenterPosition(move_vector)

                            if result.getMeshData().getExtents().bottom != 0:
                               result.translate(Vector(0,-result.getMeshData().getExtents().bottom ,0))

                        # Move all the meshes of children so that toolhandles are shown in the correct place.
                        for node in result.getChildren():
                            if node.getMeshData():
                                extents = node.getMeshData().getExtents()
                                m = Matrix()
                                m.translate(-extents.center)
                                node.setMeshData(node.getMeshData().getTransformed(m))
                                node.translate(extents.center)
                    return result

        except OSError as e:
            Logger.log("e", str(e))

        Logger.log("w", "Unable to read file %s", file_name)
        return None #unable to read
Example #8
0
    def _sendNextGcodeLine(self):
        if self._gcode_position >= len(self._gcode):
            return
        if self._gcode_position == 100:
            self._print_start_time_100 = time.time()
        line = self._gcode[self._gcode_position]

        if ";" in line:
            line = line[:line.find(";")]
        line = line.strip()

        # Don't send empty lines. But we do have to send something, so send
        # m105 instead.
        # Don't send the M0 or M1 to the machine, as M0 and M1 are handled as
        # an LCD menu pause.
        if line == "" or line == "M0" or line == "M1":
            line = "M105"
        try:
            if ("G0" in line or "G1" in line) and "Z" in line:
                z = float(re.search("Z([0-9\.]*)", line).group(1))
                if self._current_z != z:
                    self._current_z = z
        except Exception as e:
            Logger.log("e", "Unexpected error with printer connection, could not parse current Z: %s: %s" % (e, line))
            self._setErrorState("Unexpected error: %s" %e)
        checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))

        self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
        self._gcode_position += 1
        self.setProgress((self._gcode_position / len(self._gcode)) * 100)
        self.progressChanged.emit()
Example #9
0
 def addTool(self, tool):
     name = tool.getPluginId()
     if(name not in self._tools):
         self._tools[name] = tool
         self.toolsChanged.emit()
     else: 
         Logger.log("w", "%s was already added to tool list. Unable to add it again.", name)
Example #10
0
    def findDefaultVariant(self) -> Optional[ContainerInterface]:
        definition = self._getMachineDefinition()
        # has_variants can be overridden in other containers and stacks.
        # In the case of UM2, it is overridden in the GlobalStack
        if not self.getMetaDataEntry("has_variants"):
            # If the machine does not use variants, we should never set a variant.
            return None

        # First add any variant. Later, overwrite with preference if the preference is valid.
        variant = None
        definition_id = self._findInstanceContainerDefinitionId(definition)
        variants = ContainerRegistry.getInstance().findInstanceContainers(definition = definition_id, type = "variant")
        if variants:
            variant = variants[0]

        preferred_variant_id = definition.getMetaDataEntry("preferred_variant")
        if preferred_variant_id:
            preferred_variants = ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id, definition = definition_id, type = "variant")
            if preferred_variants:
                variant = preferred_variants[0]
            else:
                Logger.log("w", "The preferred variant \"{variant}\" of stack {stack} does not exist or is not a variant.", variant = preferred_variant_id, stack = self.id)
                # And leave it at the default variant.

        if variant:
            return variant

        Logger.log("w", "Could not find a valid default variant for stack {stack}", stack = self.id)
        return None
Example #11
0
    def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
        if not self.definition.findDefinitions(key = key):
            return None

        # Handle the "resolve" property.
        if self._shouldResolve(key, property_name):
            self._resolving_settings.add(key)
            resolve = super().getProperty(key, "resolve", context)
            self._resolving_settings.remove(key)
            if resolve is not None:
                return resolve

        if context is None:
            context = PropertyEvaluationContext()
        context.pushContainer(self)

        # Handle the "limit_to_extruder" property.
        limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
        if limit_to_extruder is not None:
            limit_to_extruder = str(limit_to_extruder)
        if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders:
            if super().getProperty(key, "settable_per_extruder", context):
                result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
                if result is not None:
                    context.popContainer()
                    return result
            else:
                Logger.log("e", "Setting {setting} has limit_to_extruder but is not settable per extruder!", setting = key)

        result = super().getProperty(key, property_name, context)
        context.popContainer()
        return result
Example #12
0
 def _onSocketStateChanged(self, state):
     if state == SignalSocket.ListeningState:
         if not Application.getInstance().getCommandLineOption("external-backend", False):
             self.startEngine()
     elif state == SignalSocket.ConnectedState:
         Logger.log("d", "Backend connected on port %s", self._port)
         self.backendConnected.emit()
Example #13
0
    def importProfile(self, file_name):
        if not file_name:
            return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")}

        plugin_registry = PluginRegistry.getInstance()
        for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
            profile_reader = plugin_registry.getPluginObject(plugin_id)
            try:
                profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader.
            except Exception as e:
                #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e))
                return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
            if profile_or_list: # Success!
                name_seed = os.path.splitext(os.path.basename(file_name))[0]
                if type(profile_or_list) is not list:
                    profile = profile_or_list
                    self._configureProfile(profile, name_seed)
                    return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
                else:
                    for profile in profile_or_list:
                        self._configureProfile(profile, name_seed)

                    if len(profile_or_list) == 1:
                        return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
                    else:
                        profile_names = ", ".join([profile.getName() for profile in profile_or_list])
                        return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) }

        #If it hasn't returned by now, none of the plugins loaded the profile successfully.
        return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
    def serialize(self):
        parser = configparser.ConfigParser(interpolation = None, empty_lines_in_values = False)

        if not self._definition:
            Logger.log("e", "Tried to serialize an instance container without definition, this is not supported")
            return ""

        parser["general"] = {}
        parser["general"]["version"] = str(self.Version)
        parser["general"]["name"] = str(self._name)
        parser["general"]["definition"] = str(self._definition.getId())

        parser["metadata"] = {}
        for key, value in self._metadata.items():
            parser["metadata"][key] = str(value)

        parser["values"] = {}
        for key, instance in self._instances.items():
            try:
                parser["values"][key] = str(instance.value)
            except AttributeError:
                pass

        stream = io.StringIO()
        parser.write(stream)
        return stream.getvalue()
Example #15
0
    def __init__(self, extruder: int, line_types: numpy.ndarray, data: numpy.ndarray, line_widths: numpy.ndarray, line_thicknesses: numpy.ndarray, line_feedrates: numpy.ndarray) -> None:
        self._extruder = extruder
        self._types = line_types
        for i in range(len(self._types)):
            if self._types[i] >= self.__number_of_types: # Got faulty line data from the engine.
                Logger.log("w", "Found an unknown line type: %s", i)
                self._types[i] = self.NoneType
        self._data = data
        self._line_widths = line_widths
        self._line_thicknesses = line_thicknesses
        self._line_feedrates = line_feedrates

        self._vertex_begin = 0
        self._vertex_end = 0
        self._index_begin = 0
        self._index_end = 0

        self._jump_mask = self.__jump_map[self._types]
        self._jump_count = numpy.sum(self._jump_mask)
        self._mesh_line_count = len(self._types) - self._jump_count
        self._vertex_count = self._mesh_line_count + numpy.sum(self._types[1:] == self._types[:-1])

        # Buffering the colors shouldn't be necessary as it is not 
        # re-used and can save alot of memory usage.
        self._color_map = LayerPolygon.getColorMap()
        self._colors = self._color_map[self._types]  # type: numpy.ndarray
        
        # When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
        # Should be generated in better way, not hardcoded.
        self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1], dtype=numpy.bool)
        
        self._build_cache_line_mesh_mask = None  # type: Optional[numpy.ndarray]
        self._build_cache_needed_points = None  # type: Optional[numpy.ndarray]
Example #16
0
    def addMachineExtruders(self, machine_definition: DefinitionContainerInterface, machine_id: str) -> None:
        changed = False
        machine_definition_id = machine_definition.getId()
        if machine_id not in self._extruder_trains:
            self._extruder_trains[machine_id] = { }
            changed = True
        container_registry = ContainerRegistry.getInstance()
        if container_registry:
            # Add the extruder trains that don't exist yet.
            for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition_id):
                position = extruder_definition.getMetaDataEntry("position", None)
                if not position:
                    Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
                if not container_registry.findContainerStacks(machine = machine_id, position = position): # Doesn't exist yet.
                    self.createExtruderTrain(extruder_definition, machine_definition, position, machine_id)
                    changed = True

            # Gets the extruder trains that we just created as well as any that still existed.
            extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_id)
            for extruder_train in extruder_trains:
                self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train

                # regardless of what the next stack is, we have to set it again, because of signal routing.
                extruder_train.setNextStack(Application.getInstance().getGlobalContainerStack())
                changed = True
        if changed:
            self.extrudersChanged.emit(machine_id)
Example #17
0
    def deleteAll(self, only_selectable = True) -> None:
        Logger.log("i", "Clearing scene")
        if not self.getController().getToolsEnabled():
            return

        nodes = []
        for node in DepthFirstIterator(self.getController().getScene().getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
            if not isinstance(node, SceneNode):
                continue
            if (not node.getMeshData() and not node.callDecoration("getLayerData")) and not node.callDecoration("isGroup"):
                continue  # Node that doesnt have a mesh and is not a group.
            if only_selectable and not node.isSelectable():
                continue
            if not node.callDecoration("isSliceable") and not node.callDecoration("getLayerData") and not node.callDecoration("isGroup"):
                continue  # Only remove nodes that are selectable.
            if node.getParent() and cast(SceneNode, node.getParent()).callDecoration("isGroup"):
                continue  # Grouped nodes don't need resetting as their parent (the group) is resetted)
            nodes.append(node)
        if nodes:
            op = GroupedOperation()

            for node in nodes:
                op.addOperation(RemoveSceneNodeOperation(node))

                # Reset the print information
                self.getController().getScene().sceneChanged.emit(node)

            op.push()
            Selection.clear()
Example #18
0
    def _updateMaterialContainer(self, definition, variant_container = None, preferred_material_name = None):
        if not definition.getMetaDataEntry("has_materials"):
            return self._empty_material_container

        search_criteria = { "type": "material" }

        if definition.getMetaDataEntry("has_machine_materials"):
            search_criteria["definition"] = self.getQualityDefinitionId(definition)

            if definition.getMetaDataEntry("has_variants") and variant_container:
                search_criteria["variant"] = self.getQualityVariantId(definition, variant_container)
        else:
            search_criteria["definition"] = "fdmprinter"

        if preferred_material_name:
            search_criteria["name"] = preferred_material_name
        else:
            preferred_material = definition.getMetaDataEntry("preferred_material")
            if preferred_material:
                search_criteria["id"] = preferred_material

        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
        if containers:
            return containers[0]

        containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
        if "variant" in search_criteria or "id" in search_criteria:
            # If a material by this name can not be found, try a wider set of search criteria
            search_criteria.pop("variant", None)
            search_criteria.pop("id", None)
            containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
            if containers:
                return containers[0]
        Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.")
        return self._empty_material_container
Example #19
0
    def _onSocketError(self, error):
        super()._onSocketError(error)

        self._terminate()

        if error.getErrorCode() not in [Arcus.ErrorCode.BindFailedError, Arcus.ErrorCode.ConnectionResetError, Arcus.ErrorCode.Debug]:
            Logger.log("e", "A socket error caused the connection to be reset")
Example #20
0
    def createMaterial(self) -> str:
        from UM.i18n import i18nCatalog
        catalog = i18nCatalog("cura")
        # Ensure all settings are saved.
        self._application.saveSettings()

        machine_manager = self._application.getMachineManager()
        extruder_stack = machine_manager.activeStack

        machine_definition = self._application.getGlobalContainerStack().definition
        preferred_material = machine_definition.getMetaDataEntry("preferred_material")

        approximate_diameter = str(extruder_stack.approximateMaterialDiameter)
        root_material_id = preferred_material if preferred_material else "generic_pla"
        root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
        material_group = self.getMaterialGroup(root_material_id)

        if not material_group:  # This should never happen
            Logger.log("w", "Cannot get the material group of %s.", root_material_id)
            return ""

        # Create a new ID & container to hold the data.
        new_id = self._container_registry.uniqueName("custom_material")
        new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
                        "brand": catalog.i18nc("@label", "Custom"),
                        "GUID": str(uuid.uuid4()),
                        }

        self.duplicateMaterial(material_group.root_material_node,
                               new_base_id = new_id,
                               new_metadata = new_metadata)
        return new_id
    def setActivePreset(self, preset_id: str):
        if preset_id == self._active_preset_item["id"]:
            Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id)
            return

        preset_item = None
        for item in self.items:
            if item["id"] == preset_id:
                preset_item = item
                break
        if preset_item is None:
            Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id)
            return

        need_to_save_to_custom = self._active_preset_item["id"] == "custom" and preset_id != "custom"
        if need_to_save_to_custom:
            # Save the current visibility settings to custom
            current_visibility_string = self._preferences.getValue("general/visible_settings")
            if current_visibility_string:
                self._preferences.setValue("cura/custom_visible_settings", current_visibility_string)

        new_visibility_string = ";".join(preset_item["settings"])
        if preset_id == "custom":
            # Get settings from the stored custom data
            new_visibility_string = self._preferences.getValue("cura/custom_visible_settings")
            if new_visibility_string is None:
                new_visibility_string = self._preferences.getValue("general/visible_settings")
        self._preferences.setValue("general/visible_settings", new_visibility_string)

        self._preferences.setValue("cura/active_setting_visibility_preset", preset_id)
        self._active_preset_item = preset_item
        self.activePresetChanged.emit()
Example #22
0
def checkValidGetReply(reply):
    status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)

    if status_code != 200:
        Logger.log("w", "Got status code {status_code} while trying to get data".format(status_code=status_code))
        return False
    return True
Example #23
0
    def _sendPrintJob(self, writer: FileWriter, preferred_format: Dict, nodes: List[SceneNode]):
        Logger.log("i", "Sending print job to printer.")
        if self._sending_gcode:
            self._error_message = Message(
                i18n_catalog.i18nc("@info:status",
                                   "Sending new jobs (temporarily) blocked, still sending the previous print job."))
            self._error_message.show()
            yield #Wait on the user to select a target printer.
            yield #Wait for the write job to be finished.
            yield False #Return whether this was a success or not.
            yield #Prevent StopIteration.

        self._sending_gcode = True

        target_printer = yield #Potentially wait on the user to select a target printer.

        # Using buffering greatly reduces the write time for many lines of gcode
        if preferred_format["mode"] == FileWriter.OutputMode.TextMode:
            stream = io.StringIO()
        else: #Binary mode.
            stream = io.BytesIO()

        job = WriteFileJob(writer, stream, nodes, preferred_format["mode"])

        self._write_job_progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1,
                                                   title = i18n_catalog.i18nc("@info:title", "Sending Data"), use_inactivity_timer = False)
        self._write_job_progress_message.show()

        self._dummy_lambdas = (target_printer, preferred_format, stream)
        job.finished.connect(self._sendPrintJobWaitOnWriteJobFinished)

        job.start()

        yield True #Return that we had success!
        yield #To prevent having to catch the StopIteration exception.
Example #24
0
    def _onTimeout(self):
        self._saving = True # To prevent the save process from triggering another autosave.
        Logger.log("d", "Autosaving preferences, instances and profiles")

        self._application.saveSettings()

        self._saving = False
Example #25
0
def loadJsonFromReply(reply: QNetworkReply) -> Optional[List[Dict[str, Any]]]:
    try:
        result = json.loads(bytes(reply.readAll()).decode("utf-8"))
    except json.decoder.JSONDecodeError:
        Logger.logException("w", "Unable to decode JSON from reply.")
        return None
    return result
    def _handleOnServiceChangedRequests(self):
        while True:
            # wait for the event to be set
            self._service_changed_request_event.wait(timeout = 5.0)
            # stop if the application is shutting down
            if Application.getInstance().isShuttingDown():
                return

            self._service_changed_request_event.clear()

            # handle all pending requests
            reschedule_requests = []  # a list of requests that have failed so later they will get re-scheduled
            while not self._service_changed_request_queue.empty():
                request = self._service_changed_request_queue.get()
                zeroconf, service_type, name, state_change = request
                try:
                    result = self._onServiceChanged(zeroconf, service_type, name, state_change)
                    if not result:
                        reschedule_requests.append(request)
                except Exception:
                    Logger.logException("e", "Failed to get service info for [%s] [%s], the request will be rescheduled",
                                        service_type, name)
                    reschedule_requests.append(request)

            # re-schedule the failed requests if any
            if reschedule_requests:
                for request in reschedule_requests:
                    self._service_changed_request_queue.put(request)
Example #27
0
    def importProfile(self, url):
        path = url.toLocalFile()
        if not path:
            return

        for profile_reader_id, profile_reader in self._manager.getProfileReaders():
            try:
                profile = profile_reader.read(path) #Try to open the file with the profile reader.
            except Exception as e:
                #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
                Logger.log("e", "Failed to import profile from %s: %s", path, str(e))
                return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", path, str(e)) }
            if profile: #Success!
                profile.setReadOnly(False)
                try:
                    self._manager.addProfile(profile) #Add the new profile to the list of profiles.
                except SettingsError.DuplicateProfileError as e:
                    count = 2
                    name = "{0} {1}".format(profile.getName(), count) #Try alternative profile names with a number appended to them.
                    while self._manager.findProfile(name) != None:
                        count += 1
                        name = "{0} {1}".format(profile.getName(), count)
                    profile.setName(name)
                    self._manager.addProfile(profile)
                    return { "status": "duplicate", "message": catalog.i18nc("@info:status", "Profile was imported as {0}", name) }
                else:
                    return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }

        #If it hasn't returned by now, none of the plugins loaded the profile successfully.
        return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", path) }
Example #28
0
def loadJsonFromReply(reply):
    try:
        result = json.loads(bytes(reply.readAll()).decode("utf-8"))
    except json.decoder.JSONDecodeError:
        Logger.logException("w", "Unable to decode JSON from reply.")
        return
    return result
Example #29
0
 def qmlPath(self) -> "QUrl":
     plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
     if plugin_path is None:
         Logger.log("e", "Cannot create QML view: cannot find plugin path for plugin [%s]", self.getPluginId())
         return QUrl("")
     path = os.path.join(plugin_path, self._qml_url)
     return QUrl.fromLocalFile(path)
Example #30
0
 def _onEngineCreated(self) -> None:
     plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
     if plugin_path:
         self.addDisplayComponent("main", os.path.join(plugin_path, "SimulationViewMainComponent.qml"))
         self.addDisplayComponent("menu", os.path.join(plugin_path, "SimulationViewMenuComponent.qml"))
     else:
         Logger.log("e", "Unable to find the path for %s", self.getPluginId())
Example #31
0
 def _onDataRequestError(self, request_type: str, reply: "QNetworkReply",
                         error: "QNetworkReply.NetworkError") -> None:
     Logger.log("e", "Request [%s] failed due to error [%s]: %s",
                request_type, error, reply.errorString())
     self.setViewPage("errored")
Example #32
0
    def stop(self):
        """Stops uploading the mesh, marking it as finished."""

        Logger.log("i", "Finished uploading")
        self._finished = True  # Signal to any ongoing retries that we should stop retrying.
        self._on_finished()
Example #33
0
 def _onInactivityTriggered(self):
     Logger.log("d", "Hiding message because of inactivity")
     self.hide()
Example #34
0
    def deserialize(self, serialized):
        # update the serialized data first
        from UM.Settings.Interfaces import ContainerInterface
        serialized = ContainerInterface.deserialize(self, serialized)

        try:
            data = ET.fromstring(serialized)
        except:
            Logger.logException("e", "An exception occured while parsing the material profile")
            return

        # Reset previous metadata
        self.clearData() # Ensure any previous data is gone.
        meta_data = {}
        meta_data["type"] = "material"
        meta_data["base_file"] = self.id
        meta_data["status"] = "unknown"  # TODO: Add material verfication

        common_setting_values = {}

        inherits = data.find("./um:inherits", self.__namespaces)
        if inherits is not None:
            inherited = self._resolveInheritance(inherits.text)
            data = self._mergeXML(inherited, data)

        if "version" in data.attrib:
            meta_data["setting_version"] = self.xmlVersionToSettingVersion(data.attrib["version"])
        else:
            meta_data["setting_version"] = self.xmlVersionToSettingVersion("1.2") #1.2 and lower didn't have that version number there yet.
        metadata = data.iterfind("./um:metadata/*", self.__namespaces)
        for entry in metadata:
            tag_name = _tag_without_namespace(entry)

            if tag_name == "name":
                brand = entry.find("./um:brand", self.__namespaces)
                material = entry.find("./um:material", self.__namespaces)
                color = entry.find("./um:color", self.__namespaces)
                label = entry.find("./um:label", self.__namespaces)

                if label is not None:
                    self._name = label.text
                else:
                    self._name = self._profile_name(material.text, color.text)
                meta_data["brand"] = brand.text
                meta_data["material"] = material.text
                meta_data["color_name"] = color.text
                continue
            meta_data[tag_name] = entry.text

            if tag_name in self.__material_metadata_setting_map:
                common_setting_values[self.__material_metadata_setting_map[tag_name]] = entry.text

        if "description" not in meta_data:
            meta_data["description"] = ""

        if "adhesion_info" not in meta_data:
            meta_data["adhesion_info"] = ""

        property_values = {}
        properties = data.iterfind("./um:properties/*", self.__namespaces)
        for entry in properties:
            tag_name = _tag_without_namespace(entry)
            property_values[tag_name] = entry.text

            if tag_name in self.__material_properties_setting_map:
                common_setting_values[self.__material_properties_setting_map[tag_name]] = entry.text

        meta_data["approximate_diameter"] = str(round(float(property_values.get("diameter", 2.85)))) # In mm
        meta_data["properties"] = property_values

        self.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0])

        common_compatibility = True
        settings = data.iterfind("./um:settings/um:setting", self.__namespaces)
        for entry in settings:
            key = entry.get("key")
            if key in self.__material_settings_setting_map:
                common_setting_values[self.__material_settings_setting_map[key]] = entry.text
            elif key in self.__unmapped_settings:
                if key == "hardware compatible":
                    common_compatibility = parseBool(entry.text)
            else:
                Logger.log("d", "Unsupported material setting %s", key)
        self._cached_values = common_setting_values # from InstanceContainer ancestor

        meta_data["compatible"] = common_compatibility
        self.setMetaData(meta_data)
        self._dirty = False

        machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
        for machine in machines:
            machine_compatibility = common_compatibility
            machine_setting_values = {}
            settings = machine.iterfind("./um:setting", self.__namespaces)
            for entry in settings:
                key = entry.get("key")
                if key in self.__material_settings_setting_map:
                    machine_setting_values[self.__material_settings_setting_map[key]] = entry.text
                elif key in self.__unmapped_settings:
                    if key == "hardware compatible":
                        machine_compatibility = parseBool(entry.text)
                else:
                    Logger.log("d", "Unsupported material setting %s", key)

            cached_machine_setting_properties = common_setting_values.copy()
            cached_machine_setting_properties.update(machine_setting_values)

            identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
            for identifier in identifiers:
                machine_id = self.__product_id_map.get(identifier.get("product"), None)
                if machine_id is None:
                    # Lets try again with some naive heuristics.
                    machine_id = identifier.get("product").replace(" ", "").lower()

                definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = machine_id)
                if not definitions:
                    Logger.log("w", "No definition found for machine ID %s", machine_id)
                    continue

                definition = definitions[0]

                if machine_compatibility:
                    new_material_id = self.id + "_" + machine_id

                    new_material = XmlMaterialProfile(new_material_id)

                    # Update the private directly, as we want to prevent the lookup that is done when using setName
                    new_material._name = self.getName()
                    new_material.setMetaData(copy.deepcopy(self.getMetaData()))
                    new_material.setDefinition(definition)
                    # Don't use setMetadata, as that overrides it for all materials with same base file
                    new_material.getMetaData()["compatible"] = machine_compatibility

                    new_material.setCachedValues(cached_machine_setting_properties)

                    new_material._dirty = False

                    ContainerRegistry.getInstance().addContainer(new_material)

                hotends = machine.iterfind("./um:hotend", self.__namespaces)
                for hotend in hotends:
                    hotend_id = hotend.get("id")
                    if hotend_id is None:
                        continue

                    variant_containers = ContainerRegistry.getInstance().findInstanceContainers(id = hotend_id)
                    if not variant_containers:
                        # It is not really properly defined what "ID" is so also search for variants by name.
                        variant_containers = ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id)

                    if not variant_containers:
                        #Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id)
                        continue

                    hotend_compatibility = machine_compatibility
                    hotend_setting_values = {}
                    settings = hotend.iterfind("./um:setting", self.__namespaces)
                    for entry in settings:
                        key = entry.get("key")
                        if key in self.__material_settings_setting_map:
                            hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text
                        elif key in self.__unmapped_settings:
                            if key == "hardware compatible":
                                hotend_compatibility = parseBool(entry.text)
                        else:
                            Logger.log("d", "Unsupported material setting %s", key)

                    new_hotend_id = self.id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")

                    new_hotend_material = XmlMaterialProfile(new_hotend_id)

                    # Update the private directly, as we want to prevent the lookup that is done when using setName
                    new_hotend_material._name = self.getName()
                    new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
                    new_hotend_material.setDefinition(definition)
                    new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id)
                    # Don't use setMetadata, as that overrides it for all materials with same base file
                    new_hotend_material.getMetaData()["compatible"] = hotend_compatibility

                    cached_hotend_setting_properties = cached_machine_setting_properties.copy()
                    cached_hotend_setting_properties.update(hotend_setting_values)

                    new_hotend_material.setCachedValues(cached_hotend_setting_properties)

                    new_hotend_material._dirty = False

                    ContainerRegistry.getInstance().addContainer(new_hotend_material)
Example #35
0
 def savePreferences(self) -> None:
     if self._preferences_filename:
         self._preferences.writeToFile(self._preferences_filename)
     else:
         Logger.log("i",
                    "Preferences filename not set. Unable to save file.")
Example #36
0
 def _onDownloadProgress(self, bytes_sent: int, bytes_total: int) -> None:
     if bytes_total > 0:
         new_progress = bytes_sent / bytes_total * 100
         self.setDownloadProgress(new_progress)
         Logger.log("d", "new download progress %s / %s : %s%%", bytes_sent,
                    bytes_total, new_progress)
Example #37
0
    def _onDataRequestFinished(self, request_type: str,
                               reply: "QNetworkReply") -> None:
        if reply.operation() != QNetworkAccessManager.GetOperation:
            Logger.log(
                "e",
                "_onDataRequestFinished() only handles GET requests but got [%s] instead",
                reply.operation())
            return

        http_status_code = reply.attribute(
            QNetworkRequest.HttpStatusCodeAttribute)
        if http_status_code != 200:
            Logger.log("e",
                       "Request type [%s] got non-200 HTTP response: [%s]",
                       http_status_code)
            self.setViewPage("errored")
            return

        data = bytes(reply.readAll())
        try:
            json_data = json.loads(data.decode("utf-8"))
        except json.decoder.JSONDecodeError:
            Logger.log(
                "e",
                "Failed to decode response data as JSON for request type [%s], response data [%s]",
                request_type, data)
            self.setViewPage("errored")
            return

        # Check for errors:
        if "errors" in json_data:
            for error in json_data["errors"]:
                Logger.log("e",
                           "Request type [%s] got response showing error: %s",
                           error["title"])
            self.setViewPage("errored")
            return

        # Create model and apply metadata:
        if not self._models[request_type]:
            Logger.log("e", "Could not find the model for request type [%s].",
                       request_type)
            self.setViewPage("errored")
            return

        self._server_response_data[request_type] = json_data["data"]
        self._models[request_type].setMetadata(
            self._server_response_data[request_type])

        if request_type == "packages":
            self._models[request_type].setFilter({"type": "plugin"})
            self.reBuildMaterialsModels()
            self.reBuildPluginsModels()
            self._notifyPackageManager()
        elif request_type == "authors":
            self._models[request_type].setFilter({"package_types": "material"})
            self._models[request_type].setFilter({"tags": "generic"})
        elif request_type == "updates":
            # Tell the package manager that there's a new set of updates available.
            packages = set([
                pkg["package_id"]
                for pkg in self._server_response_data[request_type]
            ])
            self._package_manager.setPackagesWithUpdate(packages)

        self.metadataChanged.emit()

        if self.isLoadingComplete():
            self.setViewPage("overview")
Example #38
0
    def __init__(self) -> None:
        if OpenGL.__instance is not None:
            raise RuntimeError("Try to create singleton '%s' more than once" %
                               self.__class__.__name__)
        OpenGL.__instance = self

        super().__init__()

        profile = QOpenGLVersionProfile()
        profile.setVersion(OpenGLContext.major_version,
                           OpenGLContext.minor_version)
        profile.setProfile(OpenGLContext.profile)

        context = QOpenGLContext.currentContext()
        if not context:
            Logger.log(
                "e", "Startup failed due to OpenGL context creation failing")
            QMessageBox.critical(
                None,
                i18n_catalog.i18nc(
                    "@message", "Failed to Initialize OpenGL",
                    "Could not initialize an OpenGL context. This program requires OpenGL 2.0 or higher. Please check your video card drivers."
                ))
            sys.exit(1)
        self._gl = context.versionFunctions(
            profile
        )  # type: Any #It's actually a protected class in PyQt that depends on the implementation of your graphics card.
        if not self._gl:
            Logger.log("e",
                       "Startup failed due to OpenGL initialization failing")
            QMessageBox.critical(
                None,
                i18n_catalog.i18nc(
                    "@message", "Failed to Initialize OpenGL",
                    "Could not initialize OpenGL. This program requires OpenGL 2.0 or higher. Please check your video card drivers."
                ))
            sys.exit(1)

        # It would be nice to be able to not necessarily need OpenGL FrameBuffer Object support, but
        # due to a limitation in PyQt, currently glReadPixels or similar methods are not available.
        # This means we can only get frame buffer contents through methods that indirectly call
        # those methods, in this case primarily QOpenGLFrameBufferObject::toImage(), making us
        # hard-depend on FrameBuffer Objects.
        if not self.hasFrameBufferObjects():
            Logger.log(
                "e",
                "Startup failed, OpenGL does not support Frame Buffer Objects")
            QMessageBox.critical(
                None,
                i18n_catalog.i18nc(
                    "Critical OpenGL Extensions Missing",
                    "Critical OpenGL extensions are missing. This program requires support for Framebuffer Objects. Please check your video card drivers."
                ))
            sys.exit(1)

        self._gl.initializeOpenGLFunctions()

        self._gpu_vendor = OpenGL.Vendor.Other  #type: int
        vendor_string = self._gl.glGetString(self._gl.GL_VENDOR)
        if vendor_string is None:
            vendor_string = "Unknown"
        vendor_string = vendor_string.lower()

        if "nvidia" in vendor_string:
            self._gpu_vendor = OpenGL.Vendor.NVidia
        elif "amd" in vendor_string or "ati" in vendor_string:
            self._gpu_vendor = OpenGL.Vendor.AMD
        elif "intel" in vendor_string:
            self._gpu_vendor = OpenGL.Vendor.Intel

        self._gpu_type = "Unknown"  # type: str
        # WORKAROUND: Cura/#1117 Cura-packaging/12
        # Some Intel GPU chipsets return a string, which is not undecodable via PyQt5.
        # This workaround makes the code fall back to a "Unknown" renderer in these cases.
        try:
            self._gpu_type = self._gl.glGetString(self._gl.GL_RENDERER)
        except UnicodeDecodeError:
            Logger.log(
                "e", "DecodeError while getting GL_RENDERER via glGetString!")

        self._opengl_version = self._gl.glGetString(
            self._gl.GL_VERSION)  #type: str

        self._opengl_shading_language_version = Version("0.0")  # type: Version
        try:
            self._opengl_shading_language_version = Version(
                self._gl.glGetString(self._gl.GL_SHADING_LANGUAGE_VERSION))
        except:
            self._opengl_shading_language_version = Version("1.0")

        if not self.hasFrameBufferObjects():
            Logger.log(
                "w",
                "No frame buffer support, falling back to texture copies.")

        Logger.log("d", "Initialized OpenGL subsystems.")
        Logger.log("d", "OpenGL Version:  %s", self._opengl_version)
        Logger.log("d", "OpenGL Vendor:   %s",
                   self._gl.glGetString(self._gl.GL_VENDOR))
        Logger.log("d", "OpenGL Renderer: %s", self._gpu_type)
        Logger.log("d", "GLSL Version:    %s",
                   self._opengl_shading_language_version)
Example #39
0
    def _upgradeFile(self, storage_path_absolute: str, configuration_file: str,
                     old_configuration_type: str) -> bool:
        configuration_file_absolute = os.path.join(storage_path_absolute,
                                                   configuration_file)

        # Read the old file.
        try:
            with open(configuration_file_absolute,
                      encoding="utf-8",
                      errors="ignore") as file_handle:
                files_data = [file_handle.read()]
        except MemoryError:  # File is too big. It might be the log.
            return False
        except FileNotFoundError:  # File was already moved to an /old directory.
            return False
        except IOError:
            Logger.log("w", "Can't open configuration file %s for reading.",
                       configuration_file_absolute)
            return False

        # Get the version number of the old file.
        try:
            old_version = self._get_version_functions[old_configuration_type](
                files_data[0])
        except:  # Version getter gives an exception. Not a valid file. Can't upgrade it then.
            return False

        version = old_version
        configuration_type = old_configuration_type

        # Get the actual MIME type object, from the name.
        try:
            mime_type = UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile(
                configuration_file)
        except UM.MimeTypeDatabase.MimeTypeNotFoundError:
            return False

        filenames_without_extension = [
            self._stripMimeTypeExtension(mime_type, configuration_file)
        ]
        result_data = self.updateFilesData(configuration_type, version,
                                           files_data,
                                           filenames_without_extension)
        if not result_data:
            return False
        configuration_type, version, files_data, filenames_without_extension = result_data

        # If the version changed, save the new files.
        if version != old_version or configuration_type != old_configuration_type:

            # Finding out where to store these files.
            resource_type, mime_type_name = self._current_versions[(
                configuration_type, version)]
            storage_path = Resources.getStoragePathForType(resource_type)
            mime_type = UM.MimeTypeDatabase.MimeTypeDatabase.getMimeType(
                mime_type_name
            )  # Get the actual MIME type object, from the name.
            if mime_type.preferredSuffix:
                extension = "." + mime_type.preferredSuffix
            elif mime_type.suffixes:
                extension = "." + mime_type.suffixes[0]
            else:
                extension = ""  # No known suffix. Put no extension behind it.
            new_filenames = [
                filename + extension
                for filename in filenames_without_extension
            ]
            configuration_files_absolute = [
                os.path.join(storage_path, filename)
                for filename in new_filenames
            ]

            for file_idx, configuration_file_absolute in enumerate(
                    configuration_files_absolute):
                try:
                    with open(os.path.join(configuration_file_absolute),
                              "w",
                              encoding="utf-8") as file_handle:
                        file_handle.write(
                            files_data[file_idx])  # Save the new file.
                except IOError:
                    Logger.log("w",
                               "Couldn't write new configuration file to %s.",
                               configuration_file_absolute)
                    return False
            Logger.log("i", "Upgraded %s to version %s.", configuration_file,
                       str(version))
            return True
        return False  # Version didn't change. Was already current.
Example #40
0
 def disable(self, plugin_id: str) -> None:
     self._plugin_registry.disablePlugin(plugin_id)
     self.enabledChanged.emit()
     Logger.log("i", "%s was set as 'deactive'.", plugin_id)
     self._restart_required = True
     self.restartRequiredChanged.emit()
Example #41
0
    def run(self):
        if not self._url:
            Logger.log("e", "Can not check for a new release. URL not set!")
        no_new_version = True

        application_name = Application.getInstance().getApplicationName()
        Logger.log("i", "Checking for new version of %s" % application_name)
        try:
            headers = {"User-Agent": "%s - %s" % (application_name, Application.getInstance().getVersion())}
            request = urllib.request.Request(self._url, headers = headers)
            latest_version_file = urllib.request.urlopen(request)
        except Exception as e:
            Logger.log("w", "Failed to check for new version: %s" % e)
            if not self.silent:
                Message(i18n_catalog.i18nc("@info", "Could not access update information."),
                    title = i18n_catalog.i18nc("@info:title", "Version Upgrade")
                ).show()
            return

        try:
            reader = codecs.getreader("utf-8")
            data = json.load(reader(latest_version_file))
            try:
                if Application.getInstance().getVersion() is not "master":
                    local_version = Version(Application.getInstance().getVersion())
                else:
                    if not self.silent:
                        Message(i18n_catalog.i18nc("@info", "The version you are using does not support checking for updates."), title = i18n_catalog.i18nc("@info:title", "Warning")).show()
                    return
            except ValueError:
                Logger.log("w", "Could not determine application version from string %s, not checking for updates", Application.getInstance().getVersion())
                if not self.silent:
                    Message(i18n_catalog.i18nc("@info", "The version you are using does not support checking for updates."), title = i18n_catalog.i18nc("@info:title", "Version Upgrade")).show()
                return

            if application_name in data:
                for key, value in data[application_name].items():
                    if "major" in value and "minor" in value and "revision" in value and "url" in value:
                        os = key
                        if platform.system() == os: #TODO: add architecture check
                            newest_version = Version([int(value["major"]), int(value["minor"]), int(value["revision"])])
                            if local_version < newest_version:
                                Logger.log("i", "Found a new version of the software. Spawning message")
                                message = Message(i18n_catalog.i18nc("@info", "A new version is available!"), title = i18n_catalog.i18nc("@info:title", "Version Upgrade"))
                                message.addAction("download", i18n_catalog.i18nc("@action:button", "Download"), "[no_icon]", "[no_description]")
                                if self._set_download_url_callback:
                                    self._set_download_url_callback(value["url"])
                                message.actionTriggered.connect(self._callback)
                                message.show()
                                no_new_version = False
                                break
                    else:
                        Logger.log("w", "Could not find version information or download url for update.")
            else:
                Logger.log("w", "Did not find any version information for %s." % application_name)
        except Exception:
            Logger.logException("e", "Exception in update checker while parsing the JSON file.")
            Message(i18n_catalog.i18nc("@info", "An exception occurred while checking for updates."), title = i18n_catalog.i18nc("@info:title", "Error")).show()
            no_new_version = False  # Just to suppress the message below.

        if no_new_version and not self.silent:
            Message(i18n_catalog.i18nc("@info", "No new version was found."), title = i18n_catalog.i18nc("@info:title", "Version Upgrade")).show()
Example #42
0
    def createVertexBuffer(self, mesh: "MeshData",
                           **kwargs: Any) -> QOpenGLBuffer:
        if not kwargs.get("force_recreate", False) and hasattr(
                mesh, OpenGL.VertexBufferProperty):
            return getattr(mesh, OpenGL.VertexBufferProperty)

        buffer = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        buffer.create()
        buffer.bind()

        float_size = ctypes.sizeof(ctypes.c_float)
        int_size = ctypes.sizeof(ctypes.c_int)

        buffer_size = mesh.getVertexCount(
        ) * 3 * float_size  # Vertex count * number of components * sizeof(float32)
        if mesh.hasNormals():
            buffer_size += mesh.getVertexCount(
            ) * 3 * float_size  # Vertex count * number of components * sizeof(float32)
        if mesh.hasColors():
            buffer_size += mesh.getVertexCount(
            ) * 4 * float_size  # Vertex count * number of components * sizeof(float32)
        if mesh.hasUVCoordinates():
            buffer_size += mesh.getVertexCount(
            ) * 2 * float_size  # Vertex count * number of components * sizeof(float32)
        for attribute_name in mesh.attributeNames():
            attribute = mesh.getAttribute(attribute_name)
            if attribute["opengl_type"] == "vector2f":
                buffer_size += mesh.getVertexCount() * 2 * float_size
            elif attribute["opengl_type"] == "vector4f":
                buffer_size += mesh.getVertexCount() * 4 * float_size
            elif attribute["opengl_type"] == "int":
                buffer_size += mesh.getVertexCount() * int_size
            elif attribute["opengl_type"] == "float":
                buffer_size += mesh.getVertexCount() * float_size
            else:
                Logger.log(
                    "e",
                    "Could not determine buffer size for attribute [%s] with type [%s]"
                    % (attribute_name, attribute["opengl_type"]))
        buffer.allocate(buffer_size)

        offset = 0
        vertices = mesh.getVerticesAsByteArray()
        if vertices is not None:
            buffer.write(0, vertices, len(vertices))
            offset += len(vertices)

        if mesh.hasNormals():
            normals = cast(bytes, mesh.getNormalsAsByteArray())
            buffer.write(offset, normals, len(normals))
            offset += len(normals)

        if mesh.hasColors():
            colors = cast(bytes, mesh.getColorsAsByteArray())
            buffer.write(offset, colors, len(colors))
            offset += len(colors)

        if mesh.hasUVCoordinates():
            uvs = cast(bytes, mesh.getUVCoordinatesAsByteArray())
            buffer.write(offset, uvs, len(uvs))
            offset += len(uvs)

        for attribute_name in mesh.attributeNames():
            attribute = mesh.getAttribute(attribute_name)
            attribute_byte_array = attribute["value"].tostring()
            buffer.write(offset, attribute_byte_array,
                         len(attribute_byte_array))
            offset += len(attribute_byte_array)

        buffer.release()

        setattr(mesh, OpenGL.VertexBufferProperty, buffer)
        return buffer
Example #43
0
 def openPrinterControlPanel(self) -> None:
     Logger.log("d", "Opening printer control panel...")
     QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
Example #44
0
 def registerCurrentVersion(self, version_info: Tuple[str, int],
                            type_info: Any) -> None:
     if version_info in self._current_versions:
         Logger.log("d", "Overwriting current version info: %s",
                    repr(version_info))
     self._current_versions[version_info] = type_info
 def log(self, msg):
     Logger.log("d", msg)
Example #46
0
    def run(self):
        stack = Application.getInstance().getGlobalContainerStack()
        if not stack:
            self.setResult(StartJobResult.Error)
            return

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

        # Don't slice if there is a per object setting with an error value.
        for node in DepthFirstIterator(self._scene.getRoot()):
            if type(node) is not SceneNode or not node.isSelectable():
                continue

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

        with self._scene.getSceneLock():
            # Remove old layer data.
            for node in DepthFirstIterator(self._scene.getRoot()):
                if node.callDecoration("getLayerData"):
                    node.getParent().removeChild(node)
                    break

            # Get the objects in their groups to print.
            object_groups = []
            if stack.getProperty("print_sequence", "value") == "one_at_a_time":
                for node in OneAtATimeIterator(self._scene.getRoot()):
                    temp_list = []

                    # Node can't be printed, so don't bother sending it.
                    if getattr(node, "_outside_buildarea", False):
                        continue

                    children = node.getAllChildren()
                    children.append(node)
                    for child_node in children:
                        if type(child_node
                                ) is SceneNode and child_node.getMeshData(
                                ) and child_node.getMeshData().getVertices(
                                ) is not None:
                            temp_list.append(child_node)

                    if temp_list:
                        object_groups.append(temp_list)
                    Job.yieldThread()
                if len(object_groups) == 0:
                    Logger.log(
                        "w",
                        "No objects suitable for one at a time found, or no correct order found"
                    )
            else:
                temp_list = []
                for node in DepthFirstIterator(self._scene.getRoot()):
                    if type(node) is SceneNode and node.getMeshData(
                    ) and node.getMeshData().getVertices() is not None:
                        if not getattr(node, "_outside_buildarea", False):
                            temp_list.append(node)
                    Job.yieldThread()

                if temp_list:
                    object_groups.append(temp_list)

            # There are cases when there is nothing to slice. This can happen due to one at a time slicing not being
            # able to find a possible sequence or because there are no objects on the build plate (or they are outside
            # the build volume)
            if not object_groups:
                self.setResult(StartJobResult.NothingToSlice)
                return

            self._buildGlobalSettingsMessage(stack)
            self._buildGlobalInheritsStackMessage(stack)

            for extruder_stack in cura.Settings.ExtruderManager.getInstance(
            ).getMachineExtruders(stack.getId()):
                self._buildExtruderMessage(extruder_stack)

            for group in object_groups:
                group_message = self._slice_message.addRepeatedMessage(
                    "object_lists")
                if group[0].getParent().callDecoration("isGroup"):
                    self._handlePerObjectSettings(group[0].getParent(),
                                                  group_message)
                for object in group:
                    mesh_data = object.getMeshData().getTransformed(
                        object.getWorldTransformation())

                    obj = group_message.addRepeatedMessage("objects")
                    obj.id = id(object)
                    verts = numpy.array(mesh_data.getVertices())

                    # Convert from Y up axes to Z up axes. Equals a 90 degree rotation.
                    verts[:, [1, 2]] = verts[:, [2, 1]]
                    verts[:, 1] *= -1

                    obj.vertices = verts

                    self._handlePerObjectSettings(object, obj)

                    Job.yieldThread()

        self.setResult(StartJobResult.Finished)
Example #47
0
 def cancelPreheatBed(self):
     Logger.log("i", "Cancelling pre-heating of the bed.")
     self._setTargetBedTemperature(0)
     self.preheatBedRemainingTimeChanged.emit()
Example #48
0
    def requestWrite(self,
                     nodes: List[SceneNode],
                     file_name: Optional[str] = None,
                     limit_mimetypes: bool = False,
                     file_handler: Optional[FileHandler] = None,
                     **kwargs: str) -> None:
        self.writeStarted.emit(self)

        self.sendMaterialProfiles()

        # Formats supported by this application (file types that we can actually write).
        if file_handler:
            file_formats = file_handler.getSupportedFileTypesWrite()
        else:
            file_formats = CuraApplication.getInstance().getMeshFileHandler(
            ).getSupportedFileTypesWrite()

        global_stack = CuraApplication.getInstance().getGlobalContainerStack()
        # Create a list from the supported file formats string.
        if not global_stack:
            Logger.log("e", "Missing global stack!")
            return

        machine_file_formats = global_stack.getMetaDataEntry(
            "file_formats").split(";")
        machine_file_formats = [
            file_type.strip() for file_type in machine_file_formats
        ]
        # Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format.
        if "application/x-ufp" not in machine_file_formats and Version(
                self.firmwareVersion) >= Version("4.4"):
            machine_file_formats = ["application/x-ufp"] + machine_file_formats

        # Take the intersection between file_formats and machine_file_formats.
        format_by_mimetype = {
            format["mime_type"]: format
            for format in file_formats
        }
        file_formats = [
            format_by_mimetype[mimetype] for mimetype in machine_file_formats
        ]  #Keep them ordered according to the preference in machine_file_formats.

        if len(file_formats) == 0:
            Logger.log("e",
                       "There are no file formats available to write with!")
            raise OutputDeviceError.WriteRequestFailedError(
                i18n_catalog.i18nc(
                    "@info:status",
                    "There are no file formats available to write with!"))
        preferred_format = file_formats[0]

        # Just take the first file format available.
        if file_handler is not None:
            writer = file_handler.getWriterByMimeType(
                cast(str, preferred_format["mime_type"]))
        else:
            writer = CuraApplication.getInstance().getMeshFileHandler(
            ).getWriterByMimeType(cast(str, preferred_format["mime_type"]))

        if not writer:
            Logger.log("e",
                       "Unexpected error when trying to get the FileWriter")
            return

        # This function pauses with the yield, waiting on instructions on which printer it needs to print with.
        if not writer:
            Logger.log("e", "Missing file or mesh writer!")
            return
        self._sending_job = self._sendPrintJob(writer, preferred_format, nodes)
        if self._sending_job is not None:
            self._sending_job.send(None)  # Start the generator.

            if len(self._printers) > 1:  # We need to ask the user.
                self._spawnPrinterSelectionDialog()
                is_job_sent = True
            else:  # Just immediately continue.
                self._sending_job.send("")  # No specifically selected printer.
                is_job_sent = self._sending_job.send(None)
Example #49
0
    def _listen(self):
        Logger.log(
            "i", "Printer connection listen thread started for %s" %
            self._serial_port)
        temperature_request_timeout = time.time()
        ok_timeout = time.time()
        while self._connection_state == ConnectionState.connected:
            line = self._readline()
            if line is None:
                break  # None is only returned when something went wrong. Stop listening

            if time.time() > temperature_request_timeout:
                if self._num_extruders > 1:
                    self._temperature_requested_extruder_index = (
                        self._temperature_requested_extruder_index +
                        1) % self._num_extruders
                    self.sendCommand(
                        "M105 T%d" %
                        (self._temperature_requested_extruder_index))
                else:
                    self.sendCommand("M105")
                temperature_request_timeout = time.time() + 5

            if line.startswith(b"Error:"):
                # Oh YEAH, consistency.
                # Marlin reports a MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
                # But a bed temp error is reported as "Error: Temperature heated bed switched off. MAXTEMP triggered !!"
                # So we can have an extra newline in the most common case. Awesome work people.
                if re.match(b"Error:[0-9]\n", line):
                    line = line.rstrip() + self._readline()

                # Skip the communication errors, as those get corrected.
                if b"Extruder switched off" in line or b"Temperature heated bed switched off" in line or b"Something is wrong, please turn off the printer." in line:
                    if not self.hasError():
                        self._setErrorState(line[6:])

            elif b" T:" in line or line.startswith(
                    b"T:"):  # Temperature message
                try:
                    self._setHotendTemperature(
                        self._temperature_requested_extruder_index,
                        float(re.search(b"T: *([0-9\.]*)", line).group(1)))
                except:
                    pass
                if b"B:" in line:  # Check if it's a bed temperature
                    try:
                        self._setBedTemperature(
                            float(re.search(b"B: *([0-9\.]*)", line).group(1)))
                    except Exception as e:
                        pass
                #TODO: temperature changed callback
            elif b"_min" in line or b"_max" in line:
                tag, value = line.split(b":", 1)
                self._setEndstopState(tag,
                                      (b"H" in value or b"TRIGGERED" in value))

            if self._is_printing:
                if line == b"" and time.time() > ok_timeout:
                    line = b"ok"  # Force a timeout (basically, send next command)

                if b"ok" in line:
                    ok_timeout = time.time() + 5
                    if not self._command_queue.empty():
                        self._sendCommand(self._command_queue.get())
                    elif self._is_paused:
                        line = b""  # Force getting temperature as keep alive
                    else:
                        self._sendNextGcodeLine()
                elif b"resend" in line.lower(
                ) or b"rs" in line:  # Because a resend can be asked with "resend" and "rs"
                    try:
                        self._gcode_position = int(
                            line.replace(b"N:",
                                         b" ").replace(b"N", b" ").replace(
                                             b":", b" ").split()[-1])
                    except:
                        if b"rs" in line:
                            self._gcode_position = int(line.split()[1])

            # Request the temperature on comm timeout (every 2 seconds) when we are not printing.)
            if line == b"":
                if self._num_extruders > 1:
                    self._temperature_requested_extruder_index = (
                        self._temperature_requested_extruder_index +
                        1) % self._num_extruders
                    self.sendCommand(
                        "M105 T%d" %
                        self._temperature_requested_extruder_index)
                else:
                    self.sendCommand("M105")

        Logger.log(
            "i", "Printer connection listen thread stopped for %s" %
            self._serial_port)
Example #50
0
    def load(self, file_name: str, version: str = "") -> None:
        """Load a shader program file.

        This method loads shaders from a simple text file, using Python's configparser
        as parser.

        :note When writing shader program files, please note that configparser expects
        indented lines for multiline values. Since the shaders are provided as a single
        multiline string, make sure to indent them properly.

        :param file_name: The shader file to load.
        :param version: can be used for a special version of the shader. it will be appended
        to the keys [vertex, fragment, geometry] in the shader file

        :exception{InvalidShaderProgramError} Raised when the file provided does not contain any valid shaders.
        """
        Logger.log("d", "Loading [%s]...", file_name)

        vertex_key = "vertex" + version
        fragment_key = "fragment" + version
        geometry_key = "geometry" + version

        # Hashtags should not be ignored, they are part of GLSL.
        parser = configparser.ConfigParser(interpolation=None,
                                           comment_prefixes=(';', ))
        parser.optionxform = lambda option: option  # type: ignore
        try:
            parser.read(file_name, encoding="UTF-8")
        except EnvironmentError:
            raise InvalidShaderProgramError(
                "{0} can't be opened for reading.".format(file_name))
        except UnicodeDecodeError:
            raise InvalidShaderProgramError(
                "{0} contains invalid UTF-8 code. File corrupted?".format(
                    file_name))
        except configparser.Error as e:
            raise InvalidShaderProgramError(
                "{file_name} has broken config file syntax: {err}".format(
                    file_name=file_name, err=str(e)))

        if "shaders" not in parser:
            raise InvalidShaderProgramError(
                "{0} is missing section [shaders]".format(file_name))

        if vertex_key not in parser["shaders"] or fragment_key not in parser[
                "shaders"]:
            raise InvalidShaderProgramError(
                "{0} is missing a shader [{1}, {2}]".format(
                    file_name, vertex_key, fragment_key))

        vertex_code = parser["shaders"][vertex_key]
        if self._debug_shader:
            vertex_code_str = "\n".join([
                "%4i %s" % (i, s)
                for i, s in enumerate(vertex_code.split("\n"))
            ])
            Logger.log("d", "Vertex shader")
            Logger.log("d", vertex_code_str)

        fragment_code = parser["shaders"][fragment_key]
        if self._debug_shader:
            fragment_code_str = "\n".join([
                "%4i %s" % (i, s)
                for i, s in enumerate(fragment_code.split("\n"))
            ])
            Logger.log("d", "Fragment shader")
            Logger.log("d", fragment_code_str)

        if not self.setVertexShader(vertex_code):
            raise InvalidShaderProgramError(
                f"Could not set vertex shader from '{file_name}'.")
        if not self.setFragmentShader(fragment_code):
            raise InvalidShaderProgramError(
                f"Could not set fragment shader from '{file_name}'.")
        # Geometry shader is optional and only since version OpenGL 3.2 or with extension ARB_geometry_shader4
        if geometry_key in parser["shaders"]:
            code = parser["shaders"][geometry_key]
            if self._debug_shader:
                code_str = "\n".join([
                    "%4i %s" % (i, s) for i, s in enumerate(code.split("\n"))
                ])
                Logger.log("d", "Loading geometry shader... \n")
                Logger.log("d", code_str)
            if not self.setGeometryShader(code):
                raise InvalidShaderProgramError(
                    f"Could not set geometry shader from '{file_name}'.")

        self.build()

        if "defaults" in parser:
            for key, value in parser["defaults"].items():
                self.setUniformValue(key, ast.literal_eval(value), cache=True)

        if "bindings" in parser:
            for key, value in parser["bindings"].items():
                self.addBinding(key, value)

        if "attributes" in parser:
            for key, value in parser["attributes"].items():
                self.addAttributeBinding(key, value)
Example #51
0
 def updateFirmware(self, file_name):
     Logger.log("i", "Updating firmware of %s using %s", self._serial_port,
                file_name)
     self._firmware_file_name = file_name
     self._update_firmware_thread.start()
Example #52
0
 def preheatBed(self, temperature, duration):
     Logger.log("i", "Pre-heating the bed to %i degrees.", temperature)
     self._setTargetBedTemperature(temperature)
     self.preheatBedRemainingTimeChanged.emit()
Example #53
0
 def _setTargetBedTemperature(self, temperature):
     Logger.log("d", "Setting bed temperature to %s", temperature)
     self._sendCommand("M140 S%s" % temperature)
Example #54
0
    def _connect(self):
        Logger.log("d", "Attempting to connect to %s", self._serial_port)
        self.setConnectionState(ConnectionState.connecting)
        programmer = stk500v2.Stk500v2()
        try:
            programmer.connect(
                self._serial_port
            )  # Connect with the serial, if this succeeds, it's an arduino based usb device.
            self._serial = programmer.leaveISP()
        except ispBase.IspError as e:
            programmer.close()
            Logger.log(
                "i",
                "Could not establish connection on %s: %s. Device is not arduino based."
                % (self._serial_port, str(e)))
        except Exception as e:
            programmer.close()
            Logger.log(
                "i",
                "Could not establish connection on %s, unknown reasons.  Device is not arduino based."
                % self._serial_port)

        # If the programmer connected, we know its an atmega based version.
        # Not all that useful, but it does give some debugging information.
        for baud_rate in self._getBaudrateList(
        ):  # Cycle all baud rates (auto detect)
            Logger.log(
                "d",
                "Attempting to connect to printer with serial %s on baud rate %s",
                self._serial_port, baud_rate)
            if self._serial is None:
                try:
                    self._serial = serial.Serial(str(self._serial_port),
                                                 baud_rate,
                                                 timeout=3,
                                                 writeTimeout=10000)
                    time.sleep(10)
                except serial.SerialException:
                    Logger.log("d",
                               "Could not open port %s" % self._serial_port)
                    continue
            else:
                if not self.setBaudRate(baud_rate):
                    continue  # Could not set the baud rate, go to the next

            time.sleep(
                1.5
            )  # Ensure that we are not talking to the bootloader. 1.5 seconds seems to be the magic number
            sucesfull_responses = 0
            timeout_time = time.time() + 5
            self._serial.write(b"\n")
            self._sendCommand(
                "M105"
            )  # Request temperature, as this should (if baudrate is correct) result in a command with "T:" in it
            while timeout_time > time.time():
                line = self._readline()
                if line is None:
                    Logger.log("d",
                               "No response from serial connection received.")
                    # Something went wrong with reading, could be that close was called.
                    self.setConnectionState(ConnectionState.closed)
                    return

                if b"T:" in line:
                    Logger.log(
                        "d",
                        "Correct response for auto-baudrate detection received."
                    )
                    self._serial.timeout = 0.5
                    sucesfull_responses += 1
                    if sucesfull_responses >= self._required_responses_auto_baud:
                        self._serial.timeout = 2  # Reset serial timeout
                        self.setConnectionState(ConnectionState.connected)
                        self._listen_thread.start()  # Start listening
                        Logger.log(
                            "i", "Established printer connection on port %s" %
                            self._serial_port)
                        return

                self._sendCommand(
                    "M105"
                )  # Send M105 as long as we are listening, otherwise we end up in an undefined state

        Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
        self.close()  # Unable to connect, wrap up.
        self.setConnectionState(ConnectionState.closed)
Example #55
0
 def _setHeadPosition(self, x, y, z, speed):
     Logger.log(
         "w", "_setHeadPosition is not implemented by this output device")
Example #56
0
 def _setTargetHotendTemperature(self, index, temperature):
     Logger.log("d", "Setting hotend %s temperature to %s", index,
                temperature)
     self._sendCommand("M104 T%s S%s" % (index, temperature))
Example #57
0
 def materialHotendChangedMessage(self, callback):
     Logger.log(
         "w",
         "materialHotendChangedMessage needs to be implemented, returning 'Yes'"
     )
     callback(QMessageBox.Yes)
Example #58
0
 def _setHeadZ(self, z, speed):
     Logger.log("w", "_setHeadZ is not implemented by this output device")
Example #59
0
 def _setTargetHotendTemperature(self, index, temperature):
     Logger.log(
         "w",
         "_setTargetHotendTemperature is not implemented by this output device"
     )
Example #60
0
 def _moveHead(self, x, y, z, speed):
     Logger.log("w", "_moveHead is not implemented by this output device")