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
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()
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())
def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") node.setSelectable(True) mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") new_instance = SettingInstance(definition, settings) new_instance.setProperty("value", True) new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) op = GroupedOperation() # First add node to the scene at the correct position/scale, before parenting, so the eraser mesh does not get scaled with the parent op.addOperation(AddSceneNodeOperation(node, self._controller.getScene().getRoot())) op.addOperation(SetParentOperation(node, parent)) op.push() node.setPosition(position, CuraSceneNode.TransformSpace.World) Application.getInstance().getController().getScene().sceneChanged.emit(node)
def _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)
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)
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
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)
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)
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
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)
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)
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())
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()
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())
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())
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
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()
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(",")
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))
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))
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.")
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)
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)
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)
def __init__(self, parent = None): super().__init__(parent = parent) self._additional_component = None self._additional_components_view = None Application.getInstance().engineCreatedSignal.connect(self._createAdditionalComponentsView)
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()
def __init__(self, filename): super().__init__(filename) from UM.Application import Application self._application = Application.getInstance() self._handler = Application.getInstance().getMeshFileHandler()
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()
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)]
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 = []
def _onMaterialMetaDataChanged(self, *args, **kwargs): for build_plate_number in range( Application.getInstance().getBuildPlateModel().maxBuildPlate + 1): self._calculateInformation(build_plate_number)
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()
def setSendSliceInfo(self, enabled: bool): Application.getInstance().getPreferences().setValue( "info/send_slice_info", enabled)
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.
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)
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())
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()
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)
def __init__(self, file_name): super().__init__() self._file_name = file_name self._mesh_handler = Application.getInstance().getMeshFileHandler()
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()
def __init__(self): super().__init__() self._shortcut_key = Qt.Key_G self._controller = Application.getInstance().getController()
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()
def startPrint(self): self.writeStarted.emit(self) gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list") self._updateJobState("printing") self.printGCode(gcode_list)
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
def _onDontAskMeAgain(self, checked: bool) -> None: Application.getInstance().getPreferences().setValue( self._show_xray_warning_preference, not checked)
def requestWrite(self, node, file_name=None, filter_by_machine=False): Application.getInstance().showPrintMonitor.emit(True) self.startPrint()
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)
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
def _createViewFromQML(self): path = os.path.join( PluginRegistry.getInstance().getPluginPath("3MFReader"), self._qml_url) self._view = Application.getInstance().createQmlComponent( path, {"manager": self})
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)
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()
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)
def __init__(self, message): super().__init__() self._message = message self._scene = Application.getInstance().getController().getScene() self._progress = None
def closeBackend(self): Application.getInstance().getBackend().close()