diff --git a/.gitignore b/.gitignore index 71e83433cf..a91d3f9377 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,6 @@ plugins/Doodle3D-cura-plugin plugins/FlatProfileExporter plugins/GodMode plugins/OctoPrintPlugin -plugins/PostProcessingPlugin plugins/ProfileFlattener plugins/X3GWriter diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 8aeeb9c1e8..30fd461868 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -319,7 +319,7 @@ class CuraApplication(QtApplication): preferences.addPreference("cura/asked_dialog_on_project_save", False) preferences.addPreference("cura/choice_on_profile_override", "always_ask") preferences.addPreference("cura/choice_on_open_project", "always_ask") - preferences.addPreference("cura/arrange_objects_on_load", True) + preferences.addPreference("cura/not_arrange_objects_on_load", False) preferences.addPreference("cura/use_multi_build_plate", False) preferences.addPreference("cura/currency", "€") @@ -1428,11 +1428,13 @@ class CuraApplication(QtApplication): self.fileLoaded.emit(filename) arrange_objects_on_load = ( not Preferences.getInstance().getValue("cura/use_multi_build_plate") or - Preferences.getInstance().getValue("cura/arrange_objects_on_load")) + not Preferences.getInstance().getValue("cura/not_arrange_objects_on_load")) target_build_plate = self.getBuildPlateModel().activeBuildPlate if arrange_objects_on_load else -1 for original_node in nodes: - node = CuraSceneNode() # We want our own CuraSceneNode + + # Create a CuraSceneNode just if the original node is not that type + node = original_node if isinstance(original_node, CuraSceneNode) else CuraSceneNode() node.setMeshData(original_node.getMeshData()) node.setSelectable(True) @@ -1477,7 +1479,14 @@ class CuraApplication(QtApplication): # Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher node, _ = arranger.findNodePlacement(node, offset_shape_arr, hull_shape_arr, step = 10) - node.addDecorator(BuildPlateDecorator(target_build_plate)) + # This node is deepcopied from some other node which already has a BuildPlateDecorator, but the deepcopy + # of BuildPlateDecorator produces one that's assoicated with build plate -1. So, here we need to check if + # the BuildPlateDecorator exists or not and always set the correct build plate number. + build_plate_decorator = node.getDecorator(BuildPlateDecorator) + if build_plate_decorator is None: + build_plate_decorator = BuildPlateDecorator(target_build_plate) + node.addDecorator(build_plate_decorator) + build_plate_decorator.setBuildPlateNumber(target_build_plate) op = AddSceneNodeOperation(node, scene.getRoot()) op.push() diff --git a/cura/OneAtATimeIterator.py b/cura/OneAtATimeIterator.py index 44f8d2766a..5653c8f1fb 100644 --- a/cura/OneAtATimeIterator.py +++ b/cura/OneAtATimeIterator.py @@ -18,7 +18,7 @@ class OneAtATimeIterator(Iterator.Iterator): def _fillStack(self): node_list = [] for node in self._scene_node.getChildren(): - if not type(node) is SceneNode: + if not isinstance(node, SceneNode): continue if node.callDecoration("getConvexHull"): diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 60d3c11a49..838628e37c 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -11,6 +11,7 @@ from UM.Preferences import Preferences from UM.Settings.ContainerRegistry import ContainerRegistry from cura.Settings.ExtruderManager import ExtruderManager +from typing import Dict import math import os.path @@ -177,7 +178,7 @@ class PrintInformation(QObject): self._material_amounts = material_amounts self._calculateInformation(build_plate_number) - def _updateTotalPrintTimePerFeature(self, build_plate_number, print_time): + def _updateTotalPrintTimePerFeature(self, build_plate_number, print_time: Dict[str, int]): total_estimated_time = 0 if build_plate_number not in self._print_time_message_values: diff --git a/cura/Scene/CuraSceneController.py b/cura/Scene/CuraSceneController.py index 65723db52c..c3e27ca3dd 100644 --- a/cura/Scene/CuraSceneController.py +++ b/cura/Scene/CuraSceneController.py @@ -41,6 +41,14 @@ class CuraSceneController(QObject): self._build_plate_model.setMaxBuildPlate(self._max_build_plate) build_plates = [{"name": "Build Plate %d" % (i + 1), "buildPlateNumber": i} for i in range(self._max_build_plate + 1)] self._build_plate_model.setItems(build_plates) + if self._active_build_plate > self._max_build_plate: + build_plate_number = 0 + if self._last_selected_index >= 0: # go to the buildplate of the item you last selected + item = self._objects_model.getItem(self._last_selected_index) + if "node" in item: + node = item["node"] + build_plate_number = node.callDecoration("getBuildPlateNumber") + self.setActiveBuildPlate(build_plate_number) # self.buildPlateItemsChanged.emit() # TODO: necessary after setItems? def _calcMaxBuildPlate(self): @@ -75,11 +83,11 @@ class CuraSceneController(QObject): # Single select item = self._objects_model.getItem(index) node = item["node"] - Selection.clear() - Selection.add(node) build_plate_number = node.callDecoration("getBuildPlateNumber") if build_plate_number is not None and build_plate_number != -1: - self._build_plate_model.setActiveBuildPlate(build_plate_number) + self.setActiveBuildPlate(build_plate_number) + Selection.clear() + Selection.add(node) self._last_selected_index = index diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 209e1ec8fd..eefc109cbc 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -816,6 +816,22 @@ class ContainerManager(QObject): ContainerRegistry.getInstance().addContainer(container_to_add) return self._getMaterialContainerIdForActiveMachine(clone_of_original) + ## Create a duplicate of a material or it's original entry + # + # \return \type{str} the id of the newly created container. + @pyqtSlot(str, result = str) + def duplicateOriginalMaterial(self, material_id): + + # check if the given material has a base file (i.e. was shipped by default) + base_file = self.getContainerMetaDataEntry(material_id, "base_file") + + if base_file == "": + # there is no base file, so duplicate by ID + return self.duplicateMaterial(material_id) + else: + # there is a base file, so duplicate the original material + return self.duplicateMaterial(base_file) + ## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue # # \return \type{str} the id of the newly created container. diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index a078240d80..9202e57285 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -202,7 +202,6 @@ class CuraContainerRegistry(ContainerRegistry): for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue - profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. @@ -269,6 +268,10 @@ class CuraContainerRegistry(ContainerRegistry): profile._id = new_id profile.setName(new_name) + # Set the unique Id to the profile, so it's generating a new one even if the user imports the same profile + # It also solves an issue with importing profiles from G-Codes + profile.setMetaDataEntry("id", new_id) + if "type" in profile.getMetaData(): profile.setMetaDataEntry("type", "quality_changes") else: @@ -515,6 +518,7 @@ class CuraContainerRegistry(ContainerRegistry): extruder_quality_changes_container = self.findInstanceContainers(name = machine.qualityChanges.getName(), extruder = extruder_id) if extruder_quality_changes_container: extruder_quality_changes_container = extruder_quality_changes_container[0] + quality_changes_id = extruder_quality_changes_container.getId() extruder_stack.setQualityChangesById(quality_changes_id) else: @@ -525,15 +529,92 @@ class CuraContainerRegistry(ContainerRegistry): if extruder_quality_changes_container: quality_changes_id = extruder_quality_changes_container.getId() extruder_stack.setQualityChangesById(quality_changes_id) + else: + # if we still cannot find a quality changes container for the extruder, create a new one + container_id = self.uniqueName(extruder_stack.getId() + "_user") + container_name = machine.qualityChanges.getName() + extruder_quality_changes_container = InstanceContainer(container_id) + extruder_quality_changes_container.setName(container_name) + extruder_quality_changes_container.addMetaDataEntry("type", "quality_changes") + extruder_quality_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) + extruder_quality_changes_container.addMetaDataEntry("extruder", extruder_stack.definition.getId()) + extruder_quality_changes_container.addMetaDataEntry("quality_type", machine.qualityChanges.getMetaDataEntry("quality_type")) + extruder_quality_changes_container.setDefinition(machine.qualityChanges.getDefinition().getId()) if not extruder_quality_changes_container: Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]", machine.qualityChanges.getName(), extruder_stack.getId()) + else: + # move all per-extruder settings to the extruder's quality changes + for qc_setting_key in machine.qualityChanges.getAllKeys(): + settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder") + if settable_per_extruder: + setting_value = machine.qualityChanges.getProperty(qc_setting_key, "value") + + setting_definition = machine.getSettingDefinition(qc_setting_key) + new_instance = SettingInstance(setting_definition, definition_changes) + new_instance.setProperty("value", setting_value) + new_instance.resetState() # Ensure that the state is not seen as a user state. + extruder_quality_changes_container.addInstance(new_instance) + extruder_quality_changes_container.setDirty(True) + + machine.qualityChanges.removeInstance(qc_setting_key, postpone_emit=True) else: extruder_stack.setQualityChangesById("empty_quality_changes") self.addContainer(extruder_stack) + # Also need to fix the other qualities that are suitable for this machine. Those quality changes may still have + # per-extruder settings in the container for the machine instead of the extruder. + if machine.qualityChanges.getId() not in ("empty", "empty_quality_changes"): + quality_changes_machine_definition_id = machine.qualityChanges.getDefinition().getId() + else: + whole_machine_definition = machine.definition + machine_entry = machine.definition.getMetaDataEntry("machine") + if machine_entry is not None: + container_registry = ContainerRegistry.getInstance() + whole_machine_definition = container_registry.findDefinitionContainers(id = machine_entry)[0] + + quality_changes_machine_definition_id = "fdmprinter" + if whole_machine_definition.getMetaDataEntry("has_machine_quality"): + quality_changes_machine_definition_id = machine.definition.getMetaDataEntry("quality_definition", + whole_machine_definition.getId()) + qcs = self.findInstanceContainers(type = "quality_changes", definition = quality_changes_machine_definition_id) + qc_groups = {} # map of qc names -> qc containers + for qc in qcs: + qc_name = qc.getName() + if qc_name not in qc_groups: + qc_groups[qc_name] = [] + qc_groups[qc_name].append(qc) + # try to find from the quality changes cura directory too + quality_changes_container = self._findQualityChangesContainerInCuraFolder(machine.qualityChanges.getName()) + if quality_changes_container: + qc_groups[qc_name].append(quality_changes_container) + + for qc_name, qc_list in qc_groups.items(): + qc_dict = {"global": None, "extruders": []} + for qc in qc_list: + extruder_def_id = qc.getMetaDataEntry("extruder") + if extruder_def_id is not None: + qc_dict["extruders"].append(qc) + else: + qc_dict["global"] = qc + if qc_dict["global"] is not None and len(qc_dict["extruders"]) == 1: + # move per-extruder settings + for qc_setting_key in qc_dict["global"].getAllKeys(): + settable_per_extruder = machine.getProperty(qc_setting_key, "settable_per_extruder") + if settable_per_extruder: + setting_value = qc_dict["global"].getProperty(qc_setting_key, "value") + + setting_definition = machine.getSettingDefinition(qc_setting_key) + new_instance = SettingInstance(setting_definition, definition_changes) + new_instance.setProperty("value", setting_value) + new_instance.resetState() # Ensure that the state is not seen as a user state. + qc_dict["extruders"][0].addInstance(new_instance) + qc_dict["extruders"][0].setDirty(True) + + qc_dict["global"].removeInstance(qc_setting_key, postpone_emit=True) + # Set next stack at the end extruder_stack.setNextStack(machine) @@ -562,6 +643,9 @@ class CuraContainerRegistry(ContainerRegistry): if parser["general"]["name"] == name: # load the container container_id = os.path.basename(file_path).replace(".inst.cfg", "") + if self.findInstanceContainers(id = container_id): + # this container is already in the registry, skip it + continue instance_container = InstanceContainer(container_id) with open(file_path, "r") as f: diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 0ca500ecec..e8c830b901 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -205,8 +205,8 @@ class CuraEngineBackend(QObject, Backend): Logger.log("d", " ## Process layers job still busy, trying later") return - if not hasattr(self._scene, "gcode_list"): - self._scene.gcode_list = {} + if not hasattr(self._scene, "gcode_dict"): + self._scene.gcode_dict = {} # see if we really have to slice active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate @@ -214,8 +214,10 @@ class CuraEngineBackend(QObject, Backend): Logger.log("d", "Going to slice build plate [%s]!" % build_plate_to_be_sliced) num_objects = self._numObjects() if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0: - self._scene.gcode_list[build_plate_to_be_sliced] = [] - Logger.log("d", "Build plate %s has 0 objects to be sliced, skipping", build_plate_to_be_sliced) + self._scene.gcode_dict[build_plate_to_be_sliced] = [] + Logger.log("d", "Build plate %s has no objects to be sliced, skipping", build_plate_to_be_sliced) + if self._build_plates_to_be_sliced: + self.slice() return self._stored_layer_data = [] @@ -232,10 +234,12 @@ class CuraEngineBackend(QObject, Backend): self.processingProgress.emit(0.0) self.backendStateChange.emit(BackendState.NotStarted) - self._scene.gcode_list[build_plate_to_be_sliced] = [] #[] indexed by build plate number + self._scene.gcode_dict[build_plate_to_be_sliced] = [] #[] indexed by build plate number self._slicing = True self.slicingStarted.emit() + self.determineAutoSlicing() # Switch timer on or off if appropriate + slice_message = self._socket.createMessage("cura.proto.Slice") self._start_slice_job = StartSliceJob.StartSliceJob(slice_message) self._start_slice_job_build_plate = build_plate_to_be_sliced @@ -391,7 +395,7 @@ class CuraEngineBackend(QObject, Backend): self.backendStateChange.emit(BackendState.Disabled) gcode_list = node.callDecoration("getGCodeList") if gcode_list is not None: - self._scene.gcode_list[node.callDecoration("getBuildPlateNumber")] = gcode_list + self._scene.gcode_dict[node.callDecoration("getBuildPlateNumber")] = gcode_list if self._use_timer == enable_timer: return self._use_timer @@ -456,6 +460,7 @@ class CuraEngineBackend(QObject, Backend): for build_plate_number in build_plate_changed: if build_plate_number not in self._build_plates_to_be_sliced: self._build_plates_to_be_sliced.append(build_plate_number) + self.printDurationMessage.emit(source_build_plate_number, {}, []) self.processingProgress.emit(0.0) self.backendStateChange.emit(BackendState.NotStarted) # if not self._use_timer: @@ -518,7 +523,7 @@ class CuraEngineBackend(QObject, Backend): def _onStackErrorCheckFinished(self): self._is_error_check_scheduled = False - if not self._slicing and self._build_plates_to_be_sliced: #self._need_slicing: + if not self._slicing and self._build_plates_to_be_sliced: self.needsSlicing() self._onChanged() @@ -558,7 +563,7 @@ class CuraEngineBackend(QObject, Backend): self.backendStateChange.emit(BackendState.Done) self.processingProgress.emit(1.0) - gcode_list = self._scene.gcode_list[self._start_slice_job_build_plate] + gcode_list = self._scene.gcode_dict[self._start_slice_job_build_plate] for index, line in enumerate(gcode_list): replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601))) replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths)) @@ -581,21 +586,23 @@ class CuraEngineBackend(QObject, Backend): Logger.log("d", "See if there is more to slice...") # Somehow this results in an Arcus Error # self.slice() - # Testing call slice again, allow backend to restart by using the timer - self._invokeSlice() + # Call slice again using the timer, allowing the backend to restart + if self._build_plates_to_be_sliced: + self.enableTimer() # manually enable timer to be able to invoke slice, also when in manual slice mode + self._invokeSlice() ## Called when a g-code message is received from the engine. # # \param message The protobuf message containing g-code, encoded as UTF-8. def _onGCodeLayerMessage(self, message): - self._scene.gcode_list[self._start_slice_job_build_plate].append(message.data.decode("utf-8", "replace")) + self._scene.gcode_dict[self._start_slice_job_build_plate].append(message.data.decode("utf-8", "replace")) ## Called when a g-code prefix message is received from the engine. # # \param message The protobuf message containing the g-code prefix, # encoded as UTF-8. def _onGCodePrefixMessage(self, message): - self._scene.gcode_list[self._start_slice_job_build_plate].insert(0, message.data.decode("utf-8", "replace")) + self._scene.gcode_dict[self._start_slice_job_build_plate].insert(0, message.data.decode("utf-8", "replace")) ## Creates a new socket connection. def _createSocket(self): diff --git a/plugins/CuraEngineBackend/ProcessGCodeJob.py b/plugins/CuraEngineBackend/ProcessGCodeJob.py index 4974907c30..ed430f8fa9 100644 --- a/plugins/CuraEngineBackend/ProcessGCodeJob.py +++ b/plugins/CuraEngineBackend/ProcessGCodeJob.py @@ -12,4 +12,6 @@ class ProcessGCodeLayerJob(Job): self._message = message def run(self): - self._scene.gcode_list.append(self._message.data.decode("utf-8", "replace")) + active_build_plate_id = Application.getInstance().getBuildPlateModel().activeBuildPlate + gcode_list = self._scene.gcode_dict[active_build_plate_id] + gcode_list.append(self._message.data.decode("utf-8", "replace")) diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index be9c3f73f0..c1fc597d80 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -4,7 +4,6 @@ import gc from UM.Job import Job -from UM.Scene.SceneNode import SceneNode from UM.Application import Application from UM.Mesh.MeshData import MeshData from UM.Preferences import Preferences @@ -17,6 +16,7 @@ from UM.Logger import Logger from UM.Math.Vector import Vector from cura.Scene.BuildPlateDecorator import BuildPlateDecorator +from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Settings.ExtruderManager import ExtruderManager from cura import LayerDataBuilder from cura import LayerDataDecorator @@ -81,7 +81,7 @@ class ProcessSlicedLayersJob(Job): Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) - new_node = SceneNode() + new_node = CuraSceneNode() new_node.addDecorator(BuildPlateDecorator(self._build_plate_number)) # Force garbage collection. diff --git a/plugins/GCodeReader/FlavorParser.py b/plugins/GCodeReader/FlavorParser.py index fa5d6da243..f63ba3ca69 100644 --- a/plugins/GCodeReader/FlavorParser.py +++ b/plugins/GCodeReader/FlavorParser.py @@ -8,14 +8,14 @@ from UM.Logger import Logger from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.Vector import Vector from UM.Message import Message -from UM.Scene.SceneNode import SceneNode +from cura.Scene.CuraSceneNode import CuraSceneNode from UM.i18n import i18nCatalog from UM.Preferences import Preferences catalog = i18nCatalog("cura") from cura import LayerDataBuilder -from cura import LayerDataDecorator +from cura.LayerDataDecorator import LayerDataDecorator from cura.LayerPolygon import LayerPolygon from cura.Scene.GCodeListDecorator import GCodeListDecorator from cura.Settings.ExtruderManager import ExtruderManager @@ -292,7 +292,7 @@ class FlavorParser: # We obtain the filament diameter from the selected printer to calculate line widths self._filament_diameter = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") - scene_node = SceneNode() + scene_node = CuraSceneNode() # Override getBoundingBox function of the sceneNode, as this node should return a bounding box, but there is no # real data to calculate it from. scene_node.getBoundingBox = self._getNullBoundingBox @@ -418,11 +418,17 @@ class FlavorParser: self._layer_number += 1 current_path.clear() - material_color_map = numpy.zeros((10, 4), dtype = numpy.float32) + material_color_map = numpy.zeros((8, 4), dtype = numpy.float32) material_color_map[0, :] = [0.0, 0.7, 0.9, 1.0] material_color_map[1, :] = [0.7, 0.9, 0.0, 1.0] + material_color_map[2, :] = [0.9, 0.0, 0.7, 1.0] + material_color_map[3, :] = [0.7, 0.0, 0.0, 1.0] + material_color_map[4, :] = [0.0, 0.7, 0.0, 1.0] + material_color_map[5, :] = [0.0, 0.0, 0.7, 1.0] + material_color_map[6, :] = [0.3, 0.3, 0.3, 1.0] + material_color_map[7, :] = [0.7, 0.7, 0.7, 1.0] layer_mesh = self._layer_data_builder.build(material_color_map) - decorator = LayerDataDecorator.LayerDataDecorator() + decorator = LayerDataDecorator() decorator.setLayerData(layer_mesh) scene_node.addDecorator(decorator) @@ -430,7 +436,10 @@ class FlavorParser: gcode_list_decorator.setGCodeList(gcode_list) scene_node.addDecorator(gcode_list_decorator) - Application.getInstance().getController().getScene().gcode_list = gcode_list + # gcode_dict stores gcode_lists for a number of build plates. + active_build_plate_id = Application.getInstance().getBuildPlateModel().activeBuildPlate + gcode_dict = {active_build_plate_id: gcode_list} + Application.getInstance().getController().getScene().gcode_dict = gcode_dict Logger.log("d", "Finished parsing %s" % file_name) self._message.hide() diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index ad23f2c8ee..95c48c4d9e 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -61,8 +61,11 @@ class GCodeWriter(MeshWriter): active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate scene = Application.getInstance().getController().getScene() - gcode_list = getattr(scene, "gcode_list")[active_build_plate] - if gcode_list: + gcode_dict = getattr(scene, "gcode_dict") + if not gcode_dict: + return False + gcode_list = gcode_dict.get(active_build_plate, None) + if gcode_list is not None: for gcode in gcode_list: stream.write(gcode) # Serialise the current container stack and put it at the end of the file. diff --git a/plugins/MonitorStage/MonitorMainView.qml b/plugins/MonitorStage/MonitorMainView.qml index 15b05bed0a..c48f6d0aab 100644 --- a/plugins/MonitorStage/MonitorMainView.qml +++ b/plugins/MonitorStage/MonitorMainView.qml @@ -8,8 +8,9 @@ import Cura 1.0 as Cura Item { - width: parent.width - height: parent.height + // parent could be undefined as this component is not visible at all times + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 // We show a nice overlay on the 3D viewer when the current output device has no monitor view Rectangle diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py index badca13468..3e1df1c7b8 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal +from UM.FlameProfiler import pyqtSlot from UM.Application import Application from UM.Settings.ContainerRegistry import ContainerRegistry @@ -22,6 +23,9 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand self._node = None self._stack = None + # this is a set of settings that will be skipped if the user chooses to reset. + self._skip_reset_setting_set = set() + def setSelectedObjectId(self, id): if id != self._selected_object_id: self._selected_object_id = id @@ -36,6 +40,10 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand def selectedObjectId(self): return self._selected_object_id + @pyqtSlot(str) + def addSkipResetSetting(self, setting_name): + self._skip_reset_setting_set.add(setting_name) + def setVisible(self, visible): if not self._node: return @@ -50,6 +58,9 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand # Remove all instances that are not in visibility list for instance in all_instances: + # exceptionally skip setting + if instance.definition.key in self._skip_reset_setting_set: + continue if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 5bdb6d4cb0..eb492d8de2 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -18,6 +18,9 @@ Item { width: childrenRect.width; height: childrenRect.height; + property var all_categories_except_support: [ "machine_settings", "resolution", "shell", "infill", "material", "speed", + "travel", "cooling", "platform_adhesion", "dual", "meshfix", "blackmagic", "experimental"] + Column { id: items @@ -39,6 +42,13 @@ Item { verticalAlignment: Text.AlignVCenter } + UM.SettingPropertyProvider + { + id: meshTypePropertyProvider + containerStackId: Cura.MachineManager.activeMachineId + watchedProperties: [ "enabled" ] + } + ComboBox { id: meshTypeSelection @@ -49,36 +59,55 @@ Item { model: ListModel { id: meshTypeModel - Component.onCompleted: + Component.onCompleted: meshTypeSelection.populateModel() + } + + function populateModel() + { + meshTypeModel.append({ + type: "", + text: catalog.i18nc("@label", "Normal model") + }); + meshTypePropertyProvider.key = "support_mesh"; + if(meshTypePropertyProvider.properties.enabled == "True") { - meshTypeModel.append({ - type: "", - text: catalog.i18nc("@label", "Normal model") - }); meshTypeModel.append({ type: "support_mesh", text: catalog.i18nc("@label", "Print as support") }); + } + meshTypePropertyProvider.key = "anti_overhang_mesh"; + if(meshTypePropertyProvider.properties.enabled == "True") + { meshTypeModel.append({ type: "anti_overhang_mesh", text: catalog.i18nc("@label", "Don't support overlap with other models") }); + } + meshTypePropertyProvider.key = "cutting_mesh"; + if(meshTypePropertyProvider.properties.enabled == "True") + { meshTypeModel.append({ type: "cutting_mesh", text: catalog.i18nc("@label", "Modify settings for overlap with other models") }); + } + meshTypePropertyProvider.key = "infill_mesh"; + if(meshTypePropertyProvider.properties.enabled == "True") + { meshTypeModel.append({ type: "infill_mesh", text: catalog.i18nc("@label", "Modify settings for infill of other models") }); - - meshTypeSelection.updateCurrentIndex(); } + + meshTypeSelection.updateCurrentIndex(); } function updateCurrentIndex() { var mesh_type = UM.ActiveTool.properties.getValue("MeshType"); + meshTypeSelection.currentIndex = -1; for(var index=0; index < meshTypeSelection.model.count; index++) { if(meshTypeSelection.model.get(index).type == mesh_type) @@ -91,6 +120,16 @@ Item { } } + Connections + { + target: Cura.MachineManager + onGlobalContainerChanged: + { + meshTypeSelection.model.clear(); + meshTypeSelection.populateModel(); + } + } + Connections { target: UM.Selection @@ -106,7 +145,7 @@ Item { id: currentSettings property int maximumHeight: 200 * screenScaleFactor height: Math.min(contents.count * (UM.Theme.getSize("section").height + UM.Theme.getSize("default_lining").height), maximumHeight) - visible: ["support_mesh", "anti_overhang_mesh"].indexOf(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type) == -1 + visible: meshTypeSelection.model.get(meshTypeSelection.currentIndex).type != "anti_overhang_mesh" ScrollView { @@ -124,7 +163,15 @@ Item { id: addedSettingsModel; containerId: Cura.MachineManager.activeDefinitionId expanded: [ "*" ] - exclude: [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ] + exclude: { + var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; + + if(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh") + { + excluded_settings = excluded_settings.concat(base.all_categories_except_support); + } + return excluded_settings; + } visibilityHandler: Cura.PerObjectSettingVisibilityHandler { @@ -306,7 +353,18 @@ Item { } } - onClicked: settingPickDialog.visible = true; + onClicked: + { + settingPickDialog.visible = true; + if (meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh") + { + settingPickDialog.additional_excluded_settings = base.all_categories_except_support; + } + else + { + settingPickDialog.additional_excluded_settings = [] + } + } } } @@ -315,15 +373,18 @@ Item { id: settingPickDialog title: catalog.i18nc("@title:window", "Select Settings to Customize for this model") - width: screenScaleFactor * 360; + width: screenScaleFactor * 360 property string labelFilter: "" + property var additional_excluded_settings onVisibilityChanged: { // force updating the model to sync it with addedSettingsModel if(visible) { + // Set skip setting, it will prevent from resetting selected mesh_type + contents.model.visibilityHandler.addSkipResetSetting(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type) listview.model.forceUpdate() } } @@ -394,7 +455,12 @@ Item { } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] - exclude: [ "machine_settings", "command_line_settings", "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ] + exclude: + { + var excluded_settings = [ "machine_settings", "command_line_settings", "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; + excluded_settings = excluded_settings.concat(settingPickDialog.additional_excluded_settings); + return excluded_settings; + } } delegate:Loader { diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py new file mode 100644 index 0000000000..657e5c5387 --- /dev/null +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -0,0 +1,206 @@ +# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. +from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot + +from UM.PluginRegistry import PluginRegistry +from UM.Resources import Resources +from UM.Application import Application +from UM.Extension import Extension +from UM.Logger import Logger + +import os.path +import pkgutil +import sys +import importlib.util + +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("cura") + + +## The post processing plugin is an Extension type plugin that enables pre-written scripts to post process generated +# g-code files. +class PostProcessingPlugin(QObject, Extension): + def __init__(self, parent = None): + super().__init__(parent) + self.addMenuItem(i18n_catalog.i18n("Modify G-Code"), self.showPopup) + self._view = None + + # Loaded scripts are all scripts that can be used + self._loaded_scripts = {} + self._script_labels = {} + + # Script list contains instances of scripts in loaded_scripts. + # There can be duplicates, which will be executed in sequence. + self._script_list = [] + self._selected_script_index = -1 + + Application.getInstance().getOutputDeviceManager().writeStarted.connect(self.execute) + + selectedIndexChanged = pyqtSignal() + @pyqtProperty("QVariant", notify = selectedIndexChanged) + def selectedScriptDefinitionId(self): + try: + return self._script_list[self._selected_script_index].getDefinitionId() + except: + return "" + + @pyqtProperty("QVariant", notify=selectedIndexChanged) + def selectedScriptStackId(self): + try: + return self._script_list[self._selected_script_index].getStackId() + except: + return "" + + ## Execute all post-processing scripts on the gcode. + def execute(self, output_device): + scene = Application.getInstance().getController().getScene() + gcode_dict = getattr(scene, "gcode_dict") + if not gcode_dict: + return + + # get gcode list for the active build plate + active_build_plate_id = Application.getInstance().getBuildPlateModel().activeBuildPlate + gcode_list = gcode_dict[active_build_plate_id] + if not gcode_list: + return + + if ";POSTPROCESSED" not in gcode_list[0]: + for script in self._script_list: + try: + gcode_list = script.execute(gcode_list) + except Exception: + Logger.logException("e", "Exception in post-processing script.") + if len(self._script_list): # Add comment to g-code if any changes were made. + gcode_list[0] += ";POSTPROCESSED\n" + gcode_dict[active_build_plate_id] = gcode_list + setattr(scene, "gcode_dict", gcode_dict) + else: + Logger.log("e", "Already post processed") + + @pyqtSlot(int) + def setSelectedScriptIndex(self, index): + self._selected_script_index = index + self.selectedIndexChanged.emit() + + @pyqtProperty(int, notify = selectedIndexChanged) + def selectedScriptIndex(self): + return self._selected_script_index + + @pyqtSlot(int, int) + def moveScript(self, index, new_index): + if new_index < 0 or new_index > len(self._script_list) - 1: + return # nothing needs to be done + else: + # Magical switch code. + self._script_list[new_index], self._script_list[index] = self._script_list[index], self._script_list[new_index] + self.scriptListChanged.emit() + self.selectedIndexChanged.emit() #Ensure that settings are updated + self._propertyChanged() + + ## Remove a script from the active script list by index. + @pyqtSlot(int) + def removeScriptByIndex(self, index): + self._script_list.pop(index) + if len(self._script_list) - 1 < self._selected_script_index: + self._selected_script_index = len(self._script_list) - 1 + self.scriptListChanged.emit() + self.selectedIndexChanged.emit() # Ensure that settings are updated + self._propertyChanged() + + ## Load all scripts from provided path. + # This should probably only be done on init. + # \param path Path to check for scripts. + def loadAllScripts(self, path): + scripts = pkgutil.iter_modules(path = [path]) + for loader, script_name, ispkg in scripts: + # Iterate over all scripts. + if script_name not in sys.modules: + spec = importlib.util.spec_from_file_location(__name__ + "." + script_name, os.path.join(path, script_name + ".py")) + loaded_script = importlib.util.module_from_spec(spec) + spec.loader.exec_module(loaded_script) + sys.modules[script_name] = loaded_script + + loaded_class = getattr(loaded_script, script_name) + temp_object = loaded_class() + Logger.log("d", "Begin loading of script: %s", script_name) + try: + setting_data = temp_object.getSettingData() + if "name" in setting_data and "key" in setting_data: + self._script_labels[setting_data["key"]] = setting_data["name"] + self._loaded_scripts[setting_data["key"]] = loaded_class + else: + Logger.log("w", "Script %s.py has no name or key", script_name) + self._script_labels[script_name] = script_name + self._loaded_scripts[script_name] = loaded_class + except AttributeError: + Logger.log("e", "Script %s.py is not a recognised script type. Ensure it inherits Script", script_name) + except NotImplementedError: + Logger.log("e", "Script %s.py has no implemented settings", script_name) + self.loadedScriptListChanged.emit() + + loadedScriptListChanged = pyqtSignal() + @pyqtProperty("QVariantList", notify = loadedScriptListChanged) + def loadedScriptList(self): + return sorted(list(self._loaded_scripts.keys())) + + @pyqtSlot(str, result = str) + def getScriptLabelByKey(self, key): + return self._script_labels[key] + + scriptListChanged = pyqtSignal() + @pyqtProperty("QVariantList", notify = scriptListChanged) + def scriptList(self): + script_list = [script.getSettingData()["key"] for script in self._script_list] + return script_list + + @pyqtSlot(str) + def addScriptToList(self, key): + Logger.log("d", "Adding script %s to list.", key) + new_script = self._loaded_scripts[key]() + self._script_list.append(new_script) + self.setSelectedScriptIndex(len(self._script_list) - 1) + self.scriptListChanged.emit() + self._propertyChanged() + + ## Creates the view used by show popup. The view is saved because of the fairly aggressive garbage collection. + def _createView(self): + Logger.log("d", "Creating post processing plugin view.") + + ## Load all scripts in the scripts folders + for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]: + try: + path = os.path.join(root, "scripts") + if not os.path.isdir(path): + try: + os.makedirs(path) + except OSError: + Logger.log("w", "Unable to create a folder for scripts: " + path) + continue + + self.loadAllScripts(path) + except Exception as e: + Logger.logException("e", "Exception occurred while loading post processing plugin: {error_msg}".format(error_msg = str(e))) + + # Create the plugin dialog component + path = os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "PostProcessingPlugin.qml") + self._view = Application.getInstance().createQmlComponent(path, {"manager": self}) + Logger.log("d", "Post processing view created.") + + # Create the save button component + Application.getInstance().addAdditionalComponent("saveButton", self._view.findChild(QObject, "postProcessingSaveAreaButton")) + + ## Show the (GUI) popup of the post processing plugin. + def showPopup(self): + if self._view is None: + self._createView() + self._view.show() + + ## Property changed: trigger re-slice + # To do this we use the global container stack propertyChanged. + # Re-slicing is necessary for setting changes in this plugin, because the changes + # are applied only once per "fresh" gcode + def _propertyChanged(self): + global_container_stack = Application.getInstance().getGlobalContainerStack() + global_container_stack.propertyChanged.emit("post_processing_plugin", "value") + + diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml new file mode 100644 index 0000000000..d64d60a04a --- /dev/null +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml @@ -0,0 +1,501 @@ +// Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. +// The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Window 2.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +UM.Dialog +{ + id: dialog + + title: catalog.i18nc("@title:window", "Post Processing Plugin") + width: 700 * screenScaleFactor; + height: 500 * screenScaleFactor; + minimumWidth: 400 * screenScaleFactor; + minimumHeight: 250 * screenScaleFactor; + + Item + { + UM.I18nCatalog{id: catalog; name:"cura"} + id: base + property int columnWidth: Math.floor((base.width / 2) - UM.Theme.getSize("default_margin").width) + property int textMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) + property string activeScriptName + SystemPalette{ id: palette } + SystemPalette{ id: disabledPalette; colorGroup: SystemPalette.Disabled } + anchors.fill: parent + + ExclusiveGroup + { + id: selectedScriptGroup + } + Item + { + id: activeScripts + anchors.left: parent.left + width: base.columnWidth + height: parent.height + + Label + { + id: activeScriptsHeader + text: catalog.i18nc("@label", "Post Processing Scripts") + anchors.top: parent.top + anchors.topMargin: base.textMargin + anchors.left: parent.left + anchors.leftMargin: base.textMargin + anchors.right: parent.right + anchors.rightMargin: base.textMargin + font: UM.Theme.getFont("large") + } + ListView + { + id: activeScriptsList + anchors.top: activeScriptsHeader.bottom + anchors.topMargin: base.textMargin + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: parent.right + anchors.rightMargin: base.textMargin + height: childrenRect.height + model: manager.scriptList + delegate: Item + { + width: parent.width + height: activeScriptButton.height + Button + { + id: activeScriptButton + text: manager.getScriptLabelByKey(modelData.toString()) + exclusiveGroup: selectedScriptGroup + checkable: true + checked: { + if (manager.selectedScriptIndex == index) + { + base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) + return true + } + else + { + return false + } + } + onClicked: + { + forceActiveFocus() + manager.setSelectedScriptIndex(index) + base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) + } + width: parent.width + height: UM.Theme.getSize("setting").height + style: ButtonStyle + { + background: Rectangle + { + color: activeScriptButton.checked ? palette.highlight : "transparent" + width: parent.width + height: parent.height + } + label: Label + { + wrapMode: Text.Wrap + text: control.text + color: activeScriptButton.checked ? palette.highlightedText : palette.text + } + } + } + Button + { + id: removeButton + text: "x" + width: 20 * screenScaleFactor + height: 20 * screenScaleFactor + anchors.right:parent.right + anchors.rightMargin: base.textMargin + anchors.verticalCenter: parent.verticalCenter + onClicked: manager.removeScriptByIndex(index) + style: ButtonStyle + { + label: Item + { + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.floor(control.width / 2.7) + height: Math.floor(control.height / 2.7) + sourceSize.width: width + sourceSize.height: width + color: palette.text + source: UM.Theme.getIcon("cross1") + } + } + } + } + Button + { + id: downButton + text: "" + anchors.right: removeButton.left + anchors.verticalCenter: parent.verticalCenter + enabled: index != manager.scriptList.length - 1 + width: 20 * screenScaleFactor + height: 20 * screenScaleFactor + onClicked: + { + if (manager.selectedScriptIndex == index) + { + manager.setSelectedScriptIndex(index + 1) + } + return manager.moveScript(index, index + 1) + } + style: ButtonStyle + { + label: Item + { + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.floor(control.width / 2.5) + height: Math.floor(control.height / 2.5) + sourceSize.width: width + sourceSize.height: width + color: control.enabled ? palette.text : disabledPalette.text + source: UM.Theme.getIcon("arrow_bottom") + } + } + } + } + Button + { + id: upButton + text: "" + enabled: index != 0 + width: 20 * screenScaleFactor + height: 20 * screenScaleFactor + anchors.right: downButton.left + anchors.verticalCenter: parent.verticalCenter + onClicked: + { + if (manager.selectedScriptIndex == index) + { + manager.setSelectedScriptIndex(index - 1) + } + return manager.moveScript(index, index - 1) + } + style: ButtonStyle + { + label: Item + { + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.floor(control.width / 2.5) + height: Math.floor(control.height / 2.5) + sourceSize.width: width + sourceSize.height: width + color: control.enabled ? palette.text : disabledPalette.text + source: UM.Theme.getIcon("arrow_top") + } + } + } + } + } + } + Button + { + id: addButton + text: catalog.i18nc("@action", "Add a script") + anchors.left: parent.left + anchors.leftMargin: base.textMargin + anchors.top: activeScriptsList.bottom + anchors.topMargin: base.textMargin + menu: scriptsMenu + style: ButtonStyle + { + label: Label + { + text: control.text + } + } + } + Menu + { + id: scriptsMenu + + Instantiator + { + model: manager.loadedScriptList + + MenuItem + { + text: manager.getScriptLabelByKey(modelData.toString()) + onTriggered: manager.addScriptToList(modelData.toString()) + } + + onObjectAdded: scriptsMenu.insertItem(index, object); + onObjectRemoved: scriptsMenu.removeItem(object); + } + } + } + + Rectangle + { + color: UM.Theme.getColor("sidebar") + anchors.left: activeScripts.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: parent.right + height: parent.height + id: settingsPanel + + Label + { + id: scriptSpecsHeader + text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName + anchors.top: parent.top + anchors.topMargin: base.textMargin + anchors.left: parent.left + anchors.leftMargin: base.textMargin + anchors.right: parent.right + anchors.rightMargin: base.textMargin + height: 20 * screenScaleFactor + font: UM.Theme.getFont("large") + color: UM.Theme.getColor("text") + } + + ScrollView + { + id: scrollView + anchors.top: scriptSpecsHeader.bottom + anchors.topMargin: settingsPanel.textMargin + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + visible: manager.selectedScriptDefinitionId != "" + style: UM.Theme.styles.scrollview; + + ListView + { + id: listview + spacing: UM.Theme.getSize("default_lining").height + model: UM.SettingDefinitionsModel + { + id: definitionsModel; + containerId: manager.selectedScriptDefinitionId + showAll: true + } + delegate:Loader + { + id: settingLoader + + width: parent.width + height: + { + if(provider.properties.enabled == "True") + { + if(model.type != undefined) + { + return UM.Theme.getSize("section").height; + } + else + { + return 0; + } + } + else + { + return 0; + } + + } + Behavior on height { NumberAnimation { duration: 100 } } + opacity: provider.properties.enabled == "True" ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + enabled: opacity > 0 + property var definition: model + property var settingDefinitionsModel: definitionsModel + property var propertyProvider: provider + property var globalPropertyProvider: inheritStackProvider + + //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 + //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, + //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. + asynchronous: model.type != "enum" && model.type != "extruder" + + onLoaded: { + settingLoader.item.showRevertButton = false + settingLoader.item.showInheritButton = false + settingLoader.item.showLinkedSettingIcon = false + settingLoader.item.doDepthIndentation = true + settingLoader.item.doQualityUserSettingEmphasis = false + } + + sourceComponent: + { + switch(model.type) + { + case "int": + return settingTextField + case "float": + return settingTextField + case "enum": + return settingComboBox + case "extruder": + return settingExtruder + case "bool": + return settingCheckBox + case "str": + return settingTextField + case "category": + return settingCategory + default: + return settingUnknown + } + } + + UM.SettingPropertyProvider + { + id: provider + containerStackId: manager.selectedScriptStackId + key: model.key ? model.key : "None" + watchedProperties: [ "value", "enabled", "state", "validationState" ] + storeIndex: 0 + } + + // Specialty provider that only watches global_inherits (we cant filter on what property changed we get events + // so we bypass that to make a dedicated provider). + UM.SettingPropertyProvider + { + id: inheritStackProvider + containerStackId: Cura.MachineManager.activeMachineId + key: model.key ? model.key : "None" + watchedProperties: [ "limit_to_extruder" ] + } + + Connections + { + target: item + + onShowTooltip: + { + tooltip.text = text; + var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0); + tooltip.show(position); + tooltip.target.x = position.x + 1 + } + + onHideTooltip: + { + tooltip.hide(); + } + } + + } + } + } + } + + Cura.SidebarTooltip + { + id: tooltip + } + + Component + { + id: settingTextField; + + Cura.SettingTextField { } + } + + Component + { + id: settingComboBox; + + Cura.SettingComboBox { } + } + + Component + { + id: settingExtruder; + + Cura.SettingExtruder { } + } + + Component + { + id: settingCheckBox; + + Cura.SettingCheckBox { } + } + + Component + { + id: settingCategory; + + Cura.SettingCategory { } + } + + Component + { + id: settingUnknown; + + Cura.SettingUnknown { } + } + } + rightButtons: Button + { + text: catalog.i18nc("@action:button", "Close") + iconName: "dialog-close" + onClicked: dialog.accept() + } + + Button { + objectName: "postProcessingSaveAreaButton" + visible: activeScriptsList.count > 0 + height: UM.Theme.getSize("save_button_save_to_button").height + width: height + tooltip: catalog.i18nc("@info:tooltip", "Change active post-processing scripts") + onClicked: dialog.show() + + style: ButtonStyle { + background: Rectangle { + id: deviceSelectionIcon + border.width: UM.Theme.getSize("default_lining").width + border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : + control.pressed ? UM.Theme.getColor("action_button_active_border") : + control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") + color: !control.enabled ? UM.Theme.getColor("action_button_disabled") : + control.pressed ? UM.Theme.getColor("action_button_active") : + control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") + Behavior on color { ColorAnimation { duration: 50; } } + anchors.left: parent.left + anchors.leftMargin: Math.floor(UM.Theme.getSize("save_button_text_margin").width / 2); + width: parent.height + height: parent.height + + UM.RecolorImage { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.floor(parent.width / 2) + height: Math.floor(parent.height / 2) + sourceSize.width: width + sourceSize.height: height + color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : + control.pressed ? UM.Theme.getColor("action_button_active_text") : + control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); + source: "postprocessing.svg" + } + } + label: Label{ } + } + } +} \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/README.md b/plugins/PostProcessingPlugin/README.md new file mode 100644 index 0000000000..988f40007d --- /dev/null +++ b/plugins/PostProcessingPlugin/README.md @@ -0,0 +1,2 @@ +# PostProcessingPlugin +A post processing plugin for Cura diff --git a/plugins/PostProcessingPlugin/Script.py b/plugins/PostProcessingPlugin/Script.py new file mode 100644 index 0000000000..7d603ba11f --- /dev/null +++ b/plugins/PostProcessingPlugin/Script.py @@ -0,0 +1,111 @@ +# Copyright (c) 2015 Jaime van Kessel +# Copyright (c) 2017 Ultimaker B.V. +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. +from UM.Logger import Logger +from UM.Signal import Signal, signalemitter +from UM.i18n import i18nCatalog + +# Setting stuff import +from UM.Application import Application +from UM.Settings.ContainerStack import ContainerStack +from UM.Settings.InstanceContainer import InstanceContainer +from UM.Settings.DefinitionContainer import DefinitionContainer +from UM.Settings.ContainerRegistry import ContainerRegistry + +import re +import json +import collections +i18n_catalog = i18nCatalog("cura") + + +## Base class for scripts. All scripts should inherit the script class. +@signalemitter +class Script: + def __init__(self): + super().__init__() + self._settings = None + self._stack = None + + setting_data = self.getSettingData() + self._stack = ContainerStack(stack_id = str(id(self))) + self._stack.setDirty(False) # This stack does not need to be saved. + + + ## Check if the definition of this script already exists. If not, add it to the registry. + if "key" in setting_data: + definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = setting_data["key"]) + if definitions: + # Definition was found + self._definition = definitions[0] + else: + self._definition = DefinitionContainer(setting_data["key"]) + self._definition.deserialize(json.dumps(setting_data)) + ContainerRegistry.getInstance().addContainer(self._definition) + self._stack.addContainer(self._definition) + self._instance = InstanceContainer(container_id="ScriptInstanceContainer") + self._instance.setDefinition(self._definition.getId()) + self._instance.addMetaDataEntry("setting_version", self._definition.getMetaDataEntry("setting_version", default = 0)) + self._stack.addContainer(self._instance) + self._stack.propertyChanged.connect(self._onPropertyChanged) + + ContainerRegistry.getInstance().addContainer(self._stack) + + settingsLoaded = Signal() + valueChanged = Signal() # Signal emitted whenever a value of a setting is changed + + def _onPropertyChanged(self, key, property_name): + if property_name == "value": + self.valueChanged.emit() + + # Property changed: trigger reslice + # To do this we use the global container stack propertyChanged. + # Reslicing is necessary for setting changes in this plugin, because the changes + # are applied only once per "fresh" gcode + global_container_stack = Application.getInstance().getGlobalContainerStack() + global_container_stack.propertyChanged.emit(key, property_name) + + ## Needs to return a dict that can be used to construct a settingcategory file. + # See the example script for an example. + # It follows the same style / guides as the Uranium settings. + # Scripts can either override getSettingData directly, or use getSettingDataString + # to return a string that will be parsed as json. The latter has the benefit over + # returning a dict in that the order of settings is maintained. + def getSettingData(self): + setting_data = self.getSettingDataString() + if type(setting_data) == str: + setting_data = json.loads(setting_data, object_pairs_hook = collections.OrderedDict) + return setting_data + + def getSettingDataString(self): + raise NotImplementedError() + + def getDefinitionId(self): + if self._stack: + return self._stack.getBottom().getId() + + def getStackId(self): + if self._stack: + return self._stack.getId() + + ## Convenience function that retrieves value of a setting from the stack. + def getSettingValueByKey(self, key): + return self._stack.getProperty(key, "value") + + ## Convenience function that finds the value in a line of g-code. + # When requesting key = x from line "G1 X100" the value 100 is returned. + def getValue(self, line, key, default = None): + if not key in line or (';' in line and line.find(key) > line.find(';')): + return default + sub_part = line[line.find(key) + 1:] + m = re.search('^-?[0-9]+\.?[0-9]*', sub_part) + if m is None: + return default + try: + return float(m.group(0)) + except: + return default + + ## This is called when the script is executed. + # It gets a list of g-code strings and needs to return a (modified) list. + def execute(self, data): + raise NotImplementedError() diff --git a/plugins/PostProcessingPlugin/__init__.py b/plugins/PostProcessingPlugin/__init__.py new file mode 100644 index 0000000000..85f1126136 --- /dev/null +++ b/plugins/PostProcessingPlugin/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. + +from . import PostProcessingPlugin +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") +def getMetaData(): + return {} + +def register(app): + return {"extension": PostProcessingPlugin.PostProcessingPlugin()} \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/plugin.json b/plugins/PostProcessingPlugin/plugin.json new file mode 100644 index 0000000000..ebfef8145a --- /dev/null +++ b/plugins/PostProcessingPlugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Post Processing", + "author": "Ultimaker", + "version": "2.2", + "api": 4, + "description": "Extension that allows for user created scripts for post processing", + "catalog": "cura" +} \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/postprocessing.svg b/plugins/PostProcessingPlugin/postprocessing.svg new file mode 100644 index 0000000000..f55face4a9 --- /dev/null +++ b/plugins/PostProcessingPlugin/postprocessing.svg @@ -0,0 +1,47 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/BQ_PauseAtHeight.py b/plugins/PostProcessingPlugin/scripts/BQ_PauseAtHeight.py new file mode 100644 index 0000000000..fb59378206 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/BQ_PauseAtHeight.py @@ -0,0 +1,48 @@ +from ..Script import Script +class BQ_PauseAtHeight(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Pause at height (BQ Printers)", + "key": "BQ_PauseAtHeight", + "metadata":{}, + "version": 2, + "settings": + { + "pause_height": + { + "label": "Pause height", + "description": "At what height should the pause occur", + "unit": "mm", + "type": "float", + "default_value": 5.0 + } + } + }""" + + def execute(self, data): + x = 0. + y = 0. + current_z = 0. + pause_z = self.getSettingValueByKey("pause_height") + for layer in data: + lines = layer.split("\n") + for line in lines: + if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0: + current_z = self.getValue(line, 'Z') + if current_z != None: + if current_z >= pause_z: + prepend_gcode = ";TYPE:CUSTOM\n" + prepend_gcode += "; -- Pause at height (%.2f mm) --\n" % pause_z + + # Insert Pause gcode + prepend_gcode += "M25 ; Pauses the print and waits for the user to resume it\n" + + index = data.index(layer) + layer = prepend_gcode + layer + data[index] = layer # Override the data of this layer with the modified data + return data + break + return data diff --git a/plugins/PostProcessingPlugin/scripts/ColorChange.py b/plugins/PostProcessingPlugin/scripts/ColorChange.py new file mode 100644 index 0000000000..8db45f4033 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/ColorChange.py @@ -0,0 +1,76 @@ +# This PostProcessing Plugin script is released +# under the terms of the AGPLv3 or higher + +from ..Script import Script +#from UM.Logger import Logger +# from cura.Settings.ExtruderManager import ExtruderManager + +class ColorChange(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Color Change", + "key": "ColorChange", + "metadata": {}, + "version": 2, + "settings": + { + "layer_number": + { + "label": "Layer", + "description": "At what layer should color change occur. This will be before the layer starts printing. Specify multiple color changes with a comma.", + "unit": "", + "type": "str", + "default_value": "1" + }, + + "initial_retract": + { + "label": "Initial Retraction", + "description": "Initial filament retraction distance", + "unit": "mm", + "type": "float", + "default_value": 300.0 + }, + "later_retract": + { + "label": "Later Retraction Distance", + "description": "Later filament retraction distance for removal", + "unit": "mm", + "type": "float", + "default_value": 30.0 + } + } + }""" + + def execute(self, data: list): + + """data is a list. Each index contains a layer""" + layer_nums = self.getSettingValueByKey("layer_number") + initial_retract = self.getSettingValueByKey("initial_retract") + later_retract = self.getSettingValueByKey("later_retract") + + color_change = "M600" + + if initial_retract is not None and initial_retract > 0.: + color_change = color_change + (" E%.2f" % initial_retract) + + if later_retract is not None and later_retract > 0.: + color_change = color_change + (" L%.2f" % later_retract) + + color_change = color_change + " ; Generated by ColorChange plugin" + + layer_targets = layer_nums.split(',') + if len(layer_targets) > 0: + for layer_num in layer_targets: + layer_num = int( layer_num.strip() ) + if layer_num < len(data): + layer = data[ layer_num - 1 ] + lines = layer.split("\n") + lines.insert(2, color_change ) + final_line = "\n".join( lines ) + data[ layer_num - 1 ] = final_line + + return data diff --git a/plugins/PostProcessingPlugin/scripts/ExampleScript.py b/plugins/PostProcessingPlugin/scripts/ExampleScript.py new file mode 100644 index 0000000000..416a5f5404 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/ExampleScript.py @@ -0,0 +1,43 @@ +# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. +from ..Script import Script + +class ExampleScript(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Example script", + "key": "ExampleScript", + "metadata": {}, + "version": 2, + "settings": + { + "test": + { + "label": "Test", + "description": "None", + "unit": "mm", + "type": "float", + "default_value": 0.5, + "minimum_value": "0", + "minimum_value_warning": "0.1", + "maximum_value_warning": "1" + }, + "derp": + { + "label": "zomg", + "description": "afgasgfgasfgasf", + "unit": "mm", + "type": "float", + "default_value": 0.5, + "minimum_value": "0", + "minimum_value_warning": "0.1", + "maximum_value_warning": "1" + } + } + }""" + + def execute(self, data): + return data \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py b/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py new file mode 100644 index 0000000000..925a5a7ac5 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py @@ -0,0 +1,221 @@ +from ..Script import Script +# from cura.Settings.ExtruderManager import ExtruderManager + +class PauseAtHeight(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Pause at height", + "key": "PauseAtHeight", + "metadata": {}, + "version": 2, + "settings": + { + "pause_height": + { + "label": "Pause Height", + "description": "At what height should the pause occur", + "unit": "mm", + "type": "float", + "default_value": 5.0 + }, + "head_park_x": + { + "label": "Park Print Head X", + "description": "What X location does the head move to when pausing.", + "unit": "mm", + "type": "float", + "default_value": 190 + }, + "head_park_y": + { + "label": "Park Print Head Y", + "description": "What Y location does the head move to when pausing.", + "unit": "mm", + "type": "float", + "default_value": 190 + }, + "retraction_amount": + { + "label": "Retraction", + "description": "How much filament must be retracted at pause.", + "unit": "mm", + "type": "float", + "default_value": 0 + }, + "retraction_speed": + { + "label": "Retraction Speed", + "description": "How fast to retract the filament.", + "unit": "mm/s", + "type": "float", + "default_value": 25 + }, + "extrude_amount": + { + "label": "Extrude Amount", + "description": "How much filament should be extruded after pause. This is needed when doing a material change on Ultimaker2's to compensate for the retraction after the change. In that case 128+ is recommended.", + "unit": "mm", + "type": "float", + "default_value": 0 + }, + "extrude_speed": + { + "label": "Extrude Speed", + "description": "How fast to extrude the material after pause.", + "unit": "mm/s", + "type": "float", + "default_value": 3.3333 + }, + "redo_layers": + { + "label": "Redo Layers", + "description": "Redo a number of previous layers after a pause to increases adhesion.", + "unit": "layers", + "type": "int", + "default_value": 0 + }, + "standby_temperature": + { + "label": "Standby Temperature", + "description": "Change the temperature during the pause", + "unit": "°C", + "type": "int", + "default_value": 0 + }, + "resume_temperature": + { + "label": "Resume Temperature", + "description": "Change the temperature after the pause", + "unit": "°C", + "type": "int", + "default_value": 0 + } + } + }""" + + def execute(self, data: list): + + """data is a list. Each index contains a layer""" + + x = 0. + y = 0. + current_z = 0. + pause_height = self.getSettingValueByKey("pause_height") + retraction_amount = self.getSettingValueByKey("retraction_amount") + retraction_speed = self.getSettingValueByKey("retraction_speed") + extrude_amount = self.getSettingValueByKey("extrude_amount") + extrude_speed = self.getSettingValueByKey("extrude_speed") + park_x = self.getSettingValueByKey("head_park_x") + park_y = self.getSettingValueByKey("head_park_y") + layers_started = False + redo_layers = self.getSettingValueByKey("redo_layers") + standby_temperature = self.getSettingValueByKey("standby_temperature") + resume_temperature = self.getSettingValueByKey("resume_temperature") + + # T = ExtruderManager.getInstance().getActiveExtruderStack().getProperty("material_print_temperature", "value") + # with open("out.txt", "w") as f: + # f.write(T) + + # use offset to calculate the current height: = - + layer_0_z = 0. + got_first_g_cmd_on_layer_0 = False + for layer in data: + lines = layer.split("\n") + for line in lines: + if ";LAYER:0" in line: + layers_started = True + continue + + if not layers_started: + continue + + if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0: + current_z = self.getValue(line, 'Z') + if not got_first_g_cmd_on_layer_0: + layer_0_z = current_z + got_first_g_cmd_on_layer_0 = True + + x = self.getValue(line, 'X', x) + y = self.getValue(line, 'Y', y) + if current_z is not None: + current_height = current_z - layer_0_z + if current_height >= pause_height: + index = data.index(layer) + prevLayer = data[index - 1] + prevLines = prevLayer.split("\n") + current_e = 0. + for prevLine in reversed(prevLines): + current_e = self.getValue(prevLine, 'E', -1) + if current_e >= 0: + break + + # include a number of previous layers + for i in range(1, redo_layers + 1): + prevLayer = data[index - i] + layer = prevLayer + layer + + prepend_gcode = ";TYPE:CUSTOM\n" + prepend_gcode += ";added code by post processing\n" + prepend_gcode += ";script: PauseAtHeight.py\n" + prepend_gcode += ";current z: %f \n" % current_z + prepend_gcode += ";current height: %f \n" % current_height + + # Retraction + prepend_gcode += "M83\n" + if retraction_amount != 0: + prepend_gcode += "G1 E-%f F%f\n" % (retraction_amount, retraction_speed * 60) + + # Move the head away + prepend_gcode += "G1 Z%f F300\n" % (current_z + 1) + prepend_gcode += "G1 X%f Y%f F9000\n" % (park_x, park_y) + if current_z < 15: + prepend_gcode += "G1 Z15 F300\n" + + # Disable the E steppers + prepend_gcode += "M84 E0\n" + + # Set extruder standby temperature + prepend_gcode += "M104 S%i; standby temperature\n" % (standby_temperature) + + # Wait till the user continues printing + prepend_gcode += "M0 ;Do the actual pause\n" + + # Set extruder resume temperature + prepend_gcode += "M109 S%i; resume temperature\n" % (resume_temperature) + + # Push the filament back, + if retraction_amount != 0: + prepend_gcode += "G1 E%f F%f\n" % (retraction_amount, retraction_speed * 60) + + # Optionally extrude material + if extrude_amount != 0: + prepend_gcode += "G1 E%f F%f\n" % (extrude_amount, extrude_speed * 60) + + # and retract again, the properly primes the nozzle + # when changing filament. + if retraction_amount != 0: + prepend_gcode += "G1 E-%f F%f\n" % (retraction_amount, retraction_speed * 60) + + # Move the head back + prepend_gcode += "G1 Z%f F300\n" % (current_z + 1) + prepend_gcode += "G1 X%f Y%f F9000\n" % (x, y) + if retraction_amount != 0: + prepend_gcode += "G1 E%f F%f\n" % (retraction_amount, retraction_speed * 60) + prepend_gcode += "G1 F9000\n" + prepend_gcode += "M82\n" + + # reset extrude value to pre pause value + prepend_gcode += "G92 E%f\n" % (current_e) + + layer = prepend_gcode + layer + + + # Override the data of this layer with the + # modified data + data[index] = layer + return data + break + return data diff --git a/plugins/PostProcessingPlugin/scripts/PauseAtHeightforRepetier.py b/plugins/PostProcessingPlugin/scripts/PauseAtHeightforRepetier.py new file mode 100644 index 0000000000..710baab26a --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/PauseAtHeightforRepetier.py @@ -0,0 +1,169 @@ +from ..Script import Script +class PauseAtHeightforRepetier(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Pause at height for repetier", + "key": "PauseAtHeightforRepetier", + "metadata": {}, + "version": 2, + "settings": + { + "pause_height": + { + "label": "Pause height", + "description": "At what height should the pause occur", + "unit": "mm", + "type": "float", + "default_value": 5.0 + }, + "head_park_x": + { + "label": "Park print head X", + "description": "What x location does the head move to when pausing.", + "unit": "mm", + "type": "float", + "default_value": 5.0 + }, + "head_park_y": + { + "label": "Park print head Y", + "description": "What y location does the head move to when pausing.", + "unit": "mm", + "type": "float", + "default_value": 5.0 + }, + "head_move_Z": + { + "label": "Head move Z", + "description": "The Hieght of Z-axis retraction before parking.", + "unit": "mm", + "type": "float", + "default_value": 15.0 + }, + "retraction_amount": + { + "label": "Retraction", + "description": "How much fillament must be retracted at pause.", + "unit": "mm", + "type": "float", + "default_value": 5.0 + }, + "extrude_amount": + { + "label": "Extrude amount", + "description": "How much filament should be extruded after pause. This is needed when doing a material change on Ultimaker2's to compensate for the retraction after the change. In that case 128+ is recommended.", + "unit": "mm", + "type": "float", + "default_value": 90.0 + }, + "redo_layers": + { + "label": "Redo layers", + "description": "Redo a number of previous layers after a pause to increases adhesion.", + "unit": "layers", + "type": "int", + "default_value": 0 + } + } + }""" + + def execute(self, data): + x = 0. + y = 0. + current_z = 0. + pause_z = self.getSettingValueByKey("pause_height") + retraction_amount = self.getSettingValueByKey("retraction_amount") + extrude_amount = self.getSettingValueByKey("extrude_amount") + park_x = self.getSettingValueByKey("head_park_x") + park_y = self.getSettingValueByKey("head_park_y") + move_Z = self.getSettingValueByKey("head_move_Z") + layers_started = False + redo_layers = self.getSettingValueByKey("redo_layers") + for layer in data: + lines = layer.split("\n") + for line in lines: + if ";LAYER:0" in line: + layers_started = True + continue + + if not layers_started: + continue + + if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0: + current_z = self.getValue(line, 'Z') + x = self.getValue(line, 'X', x) + y = self.getValue(line, 'Y', y) + if current_z != None: + if current_z >= pause_z: + + index = data.index(layer) + prevLayer = data[index-1] + prevLines = prevLayer.split("\n") + current_e = 0. + for prevLine in reversed(prevLines): + current_e = self.getValue(prevLine, 'E', -1) + if current_e >= 0: + break + + prepend_gcode = ";TYPE:CUSTOM\n" + prepend_gcode += ";added code by post processing\n" + prepend_gcode += ";script: PauseAtHeightforRepetier.py\n" + prepend_gcode += ";current z: %f \n" % (current_z) + prepend_gcode += ";current X: %f \n" % (x) + prepend_gcode += ";current Y: %f \n" % (y) + + #Retraction + prepend_gcode += "M83\n" + if retraction_amount != 0: + prepend_gcode += "G1 E-%f F6000\n" % (retraction_amount) + + #Move the head away + prepend_gcode += "G1 Z%f F300\n" % (1 + current_z) + prepend_gcode += "G1 X%f Y%f F9000\n" % (park_x, park_y) + if current_z < move_Z: + prepend_gcode += "G1 Z%f F300\n" % (current_z + move_Z) + + #Disable the E steppers + prepend_gcode += "M84 E0\n" + #Wait till the user continues printing + prepend_gcode += "@pause now change filament and press continue printing ;Do the actual pause\n" + + #Push the filament back, + if retraction_amount != 0: + prepend_gcode += "G1 E%f F6000\n" % (retraction_amount) + + # Optionally extrude material + if extrude_amount != 0: + prepend_gcode += "G1 E%f F200\n" % (extrude_amount) + prepend_gcode += "@info wait for cleaning nozzle from previous filament\n" + prepend_gcode += "@pause remove the waste filament from parking area and press continue printing\n" + + # and retract again, the properly primes the nozzle when changing filament. + if retraction_amount != 0: + prepend_gcode += "G1 E-%f F6000\n" % (retraction_amount) + + #Move the head back + prepend_gcode += "G1 Z%f F300\n" % (1 + current_z) + prepend_gcode +="G1 X%f Y%f F9000\n" % (x, y) + if retraction_amount != 0: + prepend_gcode +="G1 E%f F6000\n" % (retraction_amount) + prepend_gcode +="G1 F9000\n" + prepend_gcode +="M82\n" + + # reset extrude value to pre pause value + prepend_gcode +="G92 E%f\n" % (current_e) + + layer = prepend_gcode + layer + + # include a number of previous layers + for i in range(1, redo_layers + 1): + prevLayer = data[index-i] + layer = prevLayer + layer + + data[index] = layer #Override the data of this layer with the modified data + return data + break + return data diff --git a/plugins/PostProcessingPlugin/scripts/SearchAndReplace.py b/plugins/PostProcessingPlugin/scripts/SearchAndReplace.py new file mode 100644 index 0000000000..68d697e470 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/SearchAndReplace.py @@ -0,0 +1,56 @@ +# Copyright (c) 2017 Ruben Dulek +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. + +import re #To perform the search and replace. + +from ..Script import Script + +## Performs a search-and-replace on all g-code. +# +# Due to technical limitations, the search can't cross the border between +# layers. +class SearchAndReplace(Script): + def getSettingDataString(self): + return """{ + "name": "Search and Replace", + "key": "SearchAndReplace", + "metadata": {}, + "version": 2, + "settings": + { + "search": + { + "label": "Search", + "description": "All occurrences of this text will get replaced by the replacement text.", + "type": "str", + "default_value": "" + }, + "replace": + { + "label": "Replace", + "description": "The search text will get replaced by this text.", + "type": "str", + "default_value": "" + }, + "is_regex": + { + "label": "Use Regular Expressions", + "description": "When enabled, the search text will be interpreted as a regular expression.", + "type": "bool", + "default_value": false + } + } + }""" + + def execute(self, data): + search_string = self.getSettingValueByKey("search") + if not self.getSettingValueByKey("is_regex"): + search_string = re.escape(search_string) #Need to search for the actual string, not as a regex. + search_regex = re.compile(search_string) + + replace_string = self.getSettingValueByKey("replace") + + for layer_number, layer in enumerate(data): + data[layer_number] = re.sub(search_regex, replace_string, layer) #Replace all. + + return data \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/Stretch.py b/plugins/PostProcessingPlugin/scripts/Stretch.py new file mode 100644 index 0000000000..bcb923d3ff --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/Stretch.py @@ -0,0 +1,469 @@ +# This PostProcessingPlugin script is released under the terms of the AGPLv3 or higher. +""" +Copyright (c) 2017 Christophe Baribaud 2017 +Python implementation of https://github.com/electrocbd/post_stretch +Correction of hole sizes, cylinder diameters and curves +See the original description in https://github.com/electrocbd/post_stretch + +WARNING This script has never been tested with several extruders +""" +from ..Script import Script +import numpy as np +from UM.Logger import Logger +from UM.Application import Application +import re + +def _getValue(line, key, default=None): + """ + Convenience function that finds the value in a line of g-code. + When requesting key = x from line "G1 X100" the value 100 is returned. + It is a copy of Stript's method, so it is no DontRepeatYourself, but + I split the class into setup part (Stretch) and execution part (Strecher) + and only the setup part inherits from Script + """ + if not key in line or (";" in line and line.find(key) > line.find(";")): + return default + sub_part = line[line.find(key) + 1:] + number = re.search(r"^-?[0-9]+\.?[0-9]*", sub_part) + if number is None: + return default + return float(number.group(0)) + +class GCodeStep(): + """ + Class to store the current value of each G_Code parameter + for any G-Code step + """ + def __init__(self, step): + self.step = step + self.step_x = 0 + self.step_y = 0 + self.step_z = 0 + self.step_e = 0 + self.step_f = 0 + self.comment = "" + + def readStep(self, line): + """ + Reads gcode from line into self + """ + self.step_x = _getValue(line, "X", self.step_x) + self.step_y = _getValue(line, "Y", self.step_y) + self.step_z = _getValue(line, "Z", self.step_z) + self.step_e = _getValue(line, "E", self.step_e) + self.step_f = _getValue(line, "F", self.step_f) + return + + def copyPosFrom(self, step): + """ + Copies positions of step into self + """ + self.step_x = step.step_x + self.step_y = step.step_y + self.step_z = step.step_z + self.step_e = step.step_e + self.step_f = step.step_f + self.comment = step.comment + return + + +# Execution part of the stretch plugin +class Stretcher(): + """ + Execution part of the stretch algorithm + """ + def __init__(self, line_width, wc_stretch, pw_stretch): + self.line_width = line_width + self.wc_stretch = wc_stretch + self.pw_stretch = pw_stretch + if self.pw_stretch > line_width / 4: + self.pw_stretch = line_width / 4 # Limit value of pushwall stretch distance + self.outpos = GCodeStep(0) + self.vd1 = np.empty((0, 2)) # Start points of segments + # of already deposited material for current layer + self.vd2 = np.empty((0, 2)) # End points of segments + # of already deposited material for current layer + self.layer_z = 0 # Z position of the extrusion moves of the current layer + self.layergcode = "" + + def execute(self, data): + """ + Computes the new X and Y coordinates of all g-code steps + """ + Logger.log("d", "Post stretch with line width = " + str(self.line_width) + + "mm wide circle stretch = " + str(self.wc_stretch)+ "mm" + + "and push wall stretch = " + str(self.pw_stretch) + "mm") + retdata = [] + layer_steps = [] + current = GCodeStep(0) + self.layer_z = 0. + current_e = 0. + for layer in data: + lines = layer.rstrip("\n").split("\n") + for line in lines: + current.comment = "" + if line.find(";") >= 0: + current.comment = line[line.find(";"):] + if _getValue(line, "G") == 0: + current.readStep(line) + onestep = GCodeStep(0) + onestep.copyPosFrom(current) + elif _getValue(line, "G") == 1: + current.readStep(line) + onestep = GCodeStep(1) + onestep.copyPosFrom(current) + elif _getValue(line, "G") == 92: + current.readStep(line) + onestep = GCodeStep(-1) + onestep.copyPosFrom(current) + else: + onestep = GCodeStep(-1) + onestep.copyPosFrom(current) + onestep.comment = line + if line.find(";LAYER:") >= 0 and len(layer_steps): + # Previous plugin "forgot" to separate two layers... + Logger.log("d", "Layer Z " + "{:.3f}".format(self.layer_z) + + " " + str(len(layer_steps)) + " steps") + retdata.append(self.processLayer(layer_steps)) + layer_steps = [] + layer_steps.append(onestep) + # self.layer_z is the z position of the last extrusion move (not travel move) + if current.step_z != self.layer_z and current.step_e != current_e: + self.layer_z = current.step_z + current_e = current.step_e + if len(layer_steps): # Force a new item in the array + Logger.log("d", "Layer Z " + "{:.3f}".format(self.layer_z) + + " " + str(len(layer_steps)) + " steps") + retdata.append(self.processLayer(layer_steps)) + layer_steps = [] + retdata.append(";Wide circle stretch distance " + str(self.wc_stretch) + "\n") + retdata.append(";Push wall stretch distance " + str(self.pw_stretch) + "\n") + return retdata + + def extrusionBreak(self, layer_steps, i_pos): + """ + Returns true if the command layer_steps[i_pos] breaks the extruded filament + i.e. it is a travel move + """ + if i_pos == 0: + return True # Begining a layer always breaks filament (for simplicity) + step = layer_steps[i_pos] + prev_step = layer_steps[i_pos - 1] + if step.step_e != prev_step.step_e: + return False + delta_x = step.step_x - prev_step.step_x + delta_y = step.step_y - prev_step.step_y + if delta_x * delta_x + delta_y * delta_y < self.line_width * self.line_width / 4: + # This is a very short movement, less than 0.5 * line_width + # It does not break filament, we should stay in the same extrusion sequence + return False + return True # New sequence + + + def processLayer(self, layer_steps): + """ + Computes the new coordinates of g-code steps + for one layer (all the steps at the same Z coordinate) + """ + self.outpos.step_x = -1000 # Force output of X and Y coordinates + self.outpos.step_y = -1000 # at each start of layer + self.layergcode = "" + self.vd1 = np.empty((0, 2)) + self.vd2 = np.empty((0, 2)) + orig_seq = np.empty((0, 2)) + modif_seq = np.empty((0, 2)) + iflush = 0 + for i, step in enumerate(layer_steps): + if step.step == 0 or step.step == 1: + if self.extrusionBreak(layer_steps, i): + # No extrusion since the previous step, so it is a travel move + # Let process steps accumulated into orig_seq, + # which are a sequence of continuous extrusion + modif_seq = np.copy(orig_seq) + if len(orig_seq) >= 2: + self.workOnSequence(orig_seq, modif_seq) + self.generate(layer_steps, iflush, i, modif_seq) + iflush = i + orig_seq = np.empty((0, 2)) + orig_seq = np.concatenate([orig_seq, np.array([[step.step_x, step.step_y]])]) + if len(orig_seq): + modif_seq = np.copy(orig_seq) + if len(orig_seq) >= 2: + self.workOnSequence(orig_seq, modif_seq) + self.generate(layer_steps, iflush, len(layer_steps), modif_seq) + return self.layergcode + + def stepToGcode(self, onestep): + """ + Converts a step into G-Code + For each of the X, Y, Z, E and F parameter, + the parameter is written only if its value changed since the + previous g-code step. + """ + sout = "" + if onestep.step_f != self.outpos.step_f: + self.outpos.step_f = onestep.step_f + sout += " F{:.0f}".format(self.outpos.step_f).rstrip(".") + if onestep.step_x != self.outpos.step_x or onestep.step_y != self.outpos.step_y: + assert onestep.step_x >= -1000 and onestep.step_x < 1000 # If this assertion fails, + # something went really wrong ! + self.outpos.step_x = onestep.step_x + sout += " X{:.3f}".format(self.outpos.step_x).rstrip("0").rstrip(".") + assert onestep.step_y >= -1000 and onestep.step_y < 1000 # If this assertion fails, + # something went really wrong ! + self.outpos.step_y = onestep.step_y + sout += " Y{:.3f}".format(self.outpos.step_y).rstrip("0").rstrip(".") + if onestep.step_z != self.outpos.step_z or onestep.step_z != self.layer_z: + self.outpos.step_z = onestep.step_z + sout += " Z{:.3f}".format(self.outpos.step_z).rstrip("0").rstrip(".") + if onestep.step_e != self.outpos.step_e: + self.outpos.step_e = onestep.step_e + sout += " E{:.5f}".format(self.outpos.step_e).rstrip("0").rstrip(".") + return sout + + def generate(self, layer_steps, ibeg, iend, orig_seq): + """ + Appends g-code lines to the plugin's returned string + starting from step ibeg included and until step iend excluded + """ + ipos = 0 + for i in range(ibeg, iend): + if layer_steps[i].step == 0: + layer_steps[i].step_x = orig_seq[ipos][0] + layer_steps[i].step_y = orig_seq[ipos][1] + sout = "G0" + self.stepToGcode(layer_steps[i]) + self.layergcode = self.layergcode + sout + "\n" + ipos = ipos + 1 + elif layer_steps[i].step == 1: + layer_steps[i].step_x = orig_seq[ipos][0] + layer_steps[i].step_y = orig_seq[ipos][1] + sout = "G1" + self.stepToGcode(layer_steps[i]) + self.layergcode = self.layergcode + sout + "\n" + ipos = ipos + 1 + else: + self.layergcode = self.layergcode + layer_steps[i].comment + "\n" + + + def workOnSequence(self, orig_seq, modif_seq): + """ + Computes new coordinates for a sequence + A sequence is a list of consecutive g-code steps + of continuous material extrusion + """ + d_contact = self.line_width / 2.0 + if (len(orig_seq) > 2 and + ((orig_seq[len(orig_seq) - 1] - orig_seq[0]) ** 2).sum(0) < d_contact * d_contact): + # Starting and ending point of the sequence are nearby + # It is a closed loop + #self.layergcode = self.layergcode + ";wideCircle\n" + self.wideCircle(orig_seq, modif_seq) + else: + #self.layergcode = self.layergcode + ";wideTurn\n" + self.wideTurn(orig_seq, modif_seq) # It is an open curve + if len(orig_seq) > 6: # Don't try push wall on a short sequence + self.pushWall(orig_seq, modif_seq) + if len(orig_seq): + self.vd1 = np.concatenate([self.vd1, np.array(orig_seq[:-1])]) + self.vd2 = np.concatenate([self.vd2, np.array(orig_seq[1:])]) + + def wideCircle(self, orig_seq, modif_seq): + """ + Similar to wideTurn + The first and last point of the sequence are the same, + so it is possible to extend the end of the sequence + with its beginning when seeking for triangles + + It is necessary to find the direction of the curve, knowing three points (a triangle) + If the triangle is not wide enough, there is a huge risk of finding + an incorrect orientation, due to insufficient accuracy. + So, when the consecutive points are too close, the method + use following and preceding points to form a wider triangle around + the current point + dmin_tri is the minimum distance between two consecutive points + of an acceptable triangle + """ + dmin_tri = self.line_width / 2.0 + iextra_base = np.floor_divide(len(orig_seq), 3) # Nb of extra points + ibeg = 0 # Index of first point of the triangle + iend = 0 # Index of the third point of the triangle + for i, step in enumerate(orig_seq): + if i == 0 or i == len(orig_seq) - 1: + # First and last point of the sequence are the same, + # so it is necessary to skip one of these two points + # when creating a triangle containing the first or the last point + iextra = iextra_base + 1 + else: + iextra = iextra_base + # i is the index of the second point of the triangle + # pos_after is the array of positions of the original sequence + # after the current point + pos_after = np.resize(np.roll(orig_seq, -i-1, 0), (iextra, 2)) + # Vector of distances between the current point and each following point + dist_from_point = ((step - pos_after) ** 2).sum(1) + if np.amax(dist_from_point) < dmin_tri * dmin_tri: + continue + iend = np.argmax(dist_from_point >= dmin_tri * dmin_tri) + # pos_before is the array of positions of the original sequence + # before the current point + pos_before = np.resize(np.roll(orig_seq, -i, 0)[::-1], (iextra, 2)) + # This time, vector of distances between the current point and each preceding point + dist_from_point = ((step - pos_before) ** 2).sum(1) + if np.amax(dist_from_point) < dmin_tri * dmin_tri: + continue + ibeg = np.argmax(dist_from_point >= dmin_tri * dmin_tri) + # See https://github.com/electrocbd/post_stretch for explanations + # relpos is the relative position of the projection of the second point + # of the triangle on the segment from the first to the third point + # 0 means the position of the first point, 1 means the position of the third, + # intermediate values are positions between + length_base = ((pos_after[iend] - pos_before[ibeg]) ** 2).sum(0) + relpos = ((step - pos_before[ibeg]) + * (pos_after[iend] - pos_before[ibeg])).sum(0) + if np.fabs(relpos) < 1000.0 * np.fabs(length_base): + relpos /= length_base + else: + relpos = 0.5 # To avoid division by zero or precision loss + projection = (pos_before[ibeg] + relpos * (pos_after[iend] - pos_before[ibeg])) + dist_from_proj = np.sqrt(((projection - step) ** 2).sum(0)) + if dist_from_proj > 0.001: # Move central point only if points are not aligned + modif_seq[i] = (step - (self.wc_stretch / dist_from_proj) + * (projection - step)) + return + + def wideTurn(self, orig_seq, modif_seq): + ''' + We have to select three points in order to form a triangle + These three points should be far enough from each other to have + a reliable estimation of the orientation of the current turn + ''' + dmin_tri = self.line_width / 2.0 + ibeg = 0 + iend = 2 + for i in range(1, len(orig_seq) - 1): + dist_from_point = ((orig_seq[i] - orig_seq[i+1:]) ** 2).sum(1) + if np.amax(dist_from_point) < dmin_tri * dmin_tri: + continue + iend = i + 1 + np.argmax(dist_from_point >= dmin_tri * dmin_tri) + dist_from_point = ((orig_seq[i] - orig_seq[i-1::-1]) ** 2).sum(1) + if np.amax(dist_from_point) < dmin_tri * dmin_tri: + continue + ibeg = i - 1 - np.argmax(dist_from_point >= dmin_tri * dmin_tri) + length_base = ((orig_seq[iend] - orig_seq[ibeg]) ** 2).sum(0) + relpos = ((orig_seq[i] - orig_seq[ibeg]) * (orig_seq[iend] - orig_seq[ibeg])).sum(0) + if np.fabs(relpos) < 1000.0 * np.fabs(length_base): + relpos /= length_base + else: + relpos = 0.5 + projection = orig_seq[ibeg] + relpos * (orig_seq[iend] - orig_seq[ibeg]) + dist_from_proj = np.sqrt(((projection - orig_seq[i]) ** 2).sum(0)) + if dist_from_proj > 0.001: + modif_seq[i] = (orig_seq[i] - (self.wc_stretch / dist_from_proj) + * (projection - orig_seq[i])) + return + + def pushWall(self, orig_seq, modif_seq): + """ + The algorithm tests for each segment if material was + already deposited at one or the other side of this segment. + If material was deposited at one side but not both, + the segment is moved into the direction of the deposited material, + to "push the wall" + + Already deposited material is stored as segments. + vd1 is the array of the starting points of the segments + vd2 is the array of the ending points of the segments + For example, segment nr 8 starts at position self.vd1[8] + and ends at position self.vd2[8] + """ + dist_palp = self.line_width # Palpation distance to seek for a wall + mrot = np.array([[0, -1], [1, 0]]) # Rotation matrix for a quarter turn + for i in range(len(orig_seq)): + ibeg = i # Index of the first point of the segment + iend = i + 1 # Index of the last point of the segment + if iend == len(orig_seq): + iend = i - 1 + xperp = np.dot(mrot, orig_seq[iend] - orig_seq[ibeg]) + xperp = xperp / np.sqrt((xperp ** 2).sum(-1)) + testleft = orig_seq[ibeg] + xperp * dist_palp + materialleft = False # Is there already extruded material at the left of the segment + testright = orig_seq[ibeg] - xperp * dist_palp + materialright = False # Is there already extruded material at the right of the segment + if self.vd1.shape[0]: + relpos = np.clip(((testleft - self.vd1) * (self.vd2 - self.vd1)).sum(1) + / ((self.vd2 - self.vd1) * (self.vd2 - self.vd1)).sum(1), 0., 1.) + nearpoints = self.vd1 + relpos[:, np.newaxis] * (self.vd2 - self.vd1) + # nearpoints is the array of the nearest points of each segment + # from the point testleft + dist = ((testleft - nearpoints) * (testleft - nearpoints)).sum(1) + # dist is the array of the squares of the distances between testleft + # and each segment + if np.amin(dist) <= dist_palp * dist_palp: + materialleft = True + # Now the same computation with the point testright at the other side of the + # current segment + relpos = np.clip(((testright - self.vd1) * (self.vd2 - self.vd1)).sum(1) + / ((self.vd2 - self.vd1) * (self.vd2 - self.vd1)).sum(1), 0., 1.) + nearpoints = self.vd1 + relpos[:, np.newaxis] * (self.vd2 - self.vd1) + dist = ((testright - nearpoints) * (testright - nearpoints)).sum(1) + if np.amin(dist) <= dist_palp * dist_palp: + materialright = True + if materialleft and not materialright: + modif_seq[ibeg] = modif_seq[ibeg] + xperp * self.pw_stretch + elif not materialleft and materialright: + modif_seq[ibeg] = modif_seq[ibeg] - xperp * self.pw_stretch + if materialleft and materialright: + modif_seq[ibeg] = orig_seq[ibeg] # Surrounded by walls, don't move + +# Setup part of the stretch plugin +class Stretch(Script): + """ + Setup part of the stretch algorithm + The only parameter is the stretch distance + """ + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Post stretch script", + "key": "Stretch", + "metadata": {}, + "version": 2, + "settings": + { + "wc_stretch": + { + "label": "Wide circle stretch distance", + "description": "Distance by which the points are moved by the correction effect in corners. The higher this value, the higher the effect", + "unit": "mm", + "type": "float", + "default_value": 0.08, + "minimum_value": 0, + "minimum_value_warning": 0, + "maximum_value_warning": 0.2 + }, + "pw_stretch": + { + "label": "Push Wall stretch distance", + "description": "Distance by which the points are moved by the correction effect when two lines are nearby. The higher this value, the higher the effect", + "unit": "mm", + "type": "float", + "default_value": 0.08, + "minimum_value": 0, + "minimum_value_warning": 0, + "maximum_value_warning": 0.2 + } + } + }""" + + def execute(self, data): + """ + Entry point of the plugin. + data is the list of original g-code instructions, + the returned string is the list of modified g-code instructions + """ + stretcher = Stretcher( + Application.getInstance().getGlobalContainerStack().getProperty("line_width", "value") + , self.getSettingValueByKey("wc_stretch"), self.getSettingValueByKey("pw_stretch")) + return stretcher.execute(data) + diff --git a/plugins/PostProcessingPlugin/scripts/TweakAtZ.py b/plugins/PostProcessingPlugin/scripts/TweakAtZ.py new file mode 100644 index 0000000000..7b714f6ee0 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/TweakAtZ.py @@ -0,0 +1,495 @@ +# TweakAtZ script - Change printing parameters at a given height +# This script is the successor of the TweakAtZ plugin for legacy Cura. +# It contains code from the TweakAtZ plugin V1.0-V4.x and from the ExampleScript by Jaime van Kessel, Ultimaker B.V. +# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher. +# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms + +#Authors of the TweakAtZ plugin / script: +# Written by Steven Morlock, smorloc@gmail.com +# Modified by Ricardo Gomez, ricardoga@otulook.com, to add Bed Temperature and make it work with Cura_13.06.04+ +# Modified by Stefan Heule, Dim3nsioneer@gmx.ch since V3.0 (see changelog below) +# Modified by Jaime van Kessel (Ultimaker), j.vankessel@ultimaker.com to make it work for 15.10 / 2.x +# Modified by Ruben Dulek (Ultimaker), r.dulek@ultimaker.com, to debug. + +##history / changelog: +##V3.0.1: TweakAtZ-state default 1 (i.e. the plugin works without any TweakAtZ comment) +##V3.1: Recognizes UltiGCode and deactivates value reset, fan speed added, alternatively layer no. to tweak at, +## extruder three temperature disabled by "#Ex3" +##V3.1.1: Bugfix reset flow rate +##V3.1.2: Bugfix disable TweakAtZ on Cool Head Lift +##V3.2: Flow rate for specific extruder added (only for 2 extruders), bugfix parser, +## added speed reset at the end of the print +##V4.0: Progress bar, tweaking over multiple layers, M605&M606 implemented, reset after one layer option, +## extruder three code removed, tweaking print speed, save call of Publisher class, +## uses previous value from other plugins also on UltiGCode +##V4.0.1: Bugfix for doubled G1 commands +##V4.0.2: uses Cura progress bar instead of its own +##V4.0.3: Bugfix for cool head lift (contributed by luisonoff) +##V4.9.91: First version for Cura 15.06.x and PostProcessingPlugin +##V4.9.92: Modifications for Cura 15.10 +##V4.9.93: Minor bugfixes (input settings) / documentation +##V4.9.94: Bugfix Combobox-selection; remove logger +##V5.0: Bugfix for fall back after one layer and doubled G0 commands when using print speed tweak, Initial version for Cura 2.x +##V5.0.1: Bugfix for calling unknown property 'bedTemp' of previous settings storage and unkown variable 'speed' +##V5.1: API Changes included for use with Cura 2.2 + +## Uses - +## M220 S - set speed factor override percentage +## M221 S - set flow factor override percentage +## M221 S T<0-#toolheads> - set flow factor override percentage for single extruder +## M104 S T<0-#toolheads> - set extruder to target temperature +## M140 S - set bed target temperature +## M106 S - set fan speed to target speed +## M605/606 to save and recall material settings on the UM2 + +from ..Script import Script +#from UM.Logger import Logger +import re + +class TweakAtZ(Script): + version = "5.1.1" + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"TweakAtZ """ + self.version + """ (Experimental)", + "key":"TweakAtZ", + "metadata": {}, + "version": 2, + "settings": + { + "a_trigger": + { + "label": "Trigger", + "description": "Trigger at height or at layer no.", + "type": "enum", + "options": {"height":"Height","layer_no":"Layer No."}, + "default_value": "height" + }, + "b_targetZ": + { + "label": "Tweak Height", + "description": "Z height to tweak at", + "unit": "mm", + "type": "float", + "default_value": 5.0, + "minimum_value": "0", + "minimum_value_warning": "0.1", + "maximum_value_warning": "230", + "enabled": "a_trigger == 'height'" + }, + "b_targetL": + { + "label": "Tweak Layer", + "description": "Layer no. to tweak at", + "unit": "", + "type": "int", + "default_value": 1, + "minimum_value": "-100", + "minimum_value_warning": "-1", + "enabled": "a_trigger == 'layer_no'" + }, + "c_behavior": + { + "label": "Behavior", + "description": "Select behavior: Tweak value and keep it for the rest, Tweak value for single layer only", + "type": "enum", + "options": {"keep_value":"Keep value","single_layer":"Single Layer"}, + "default_value": "keep_value" + }, + "d_twLayers": + { + "label": "No. Layers", + "description": "No. of layers used to tweak", + "unit": "", + "type": "int", + "default_value": 1, + "minimum_value": "1", + "maximum_value_warning": "50", + "enabled": "c_behavior == 'keep_value'" + }, + "e1_Tweak_speed": + { + "label": "Tweak Speed", + "description": "Select if total speed (print and travel) has to be tweaked", + "type": "bool", + "default_value": false + }, + "e2_speed": + { + "label": "Speed", + "description": "New total speed (print and travel)", + "unit": "%", + "type": "int", + "default_value": 100, + "minimum_value": "1", + "minimum_value_warning": "10", + "maximum_value_warning": "200", + "enabled": "e1_Tweak_speed" + }, + "f1_Tweak_printspeed": + { + "label": "Tweak Print Speed", + "description": "Select if print speed has to be tweaked", + "type": "bool", + "default_value": false + }, + "f2_printspeed": + { + "label": "Print Speed", + "description": "New print speed", + "unit": "%", + "type": "int", + "default_value": 100, + "minimum_value": "1", + "minimum_value_warning": "10", + "maximum_value_warning": "200", + "enabled": "f1_Tweak_printspeed" + }, + "g1_Tweak_flowrate": + { + "label": "Tweak Flow Rate", + "description": "Select if flow rate has to be tweaked", + "type": "bool", + "default_value": false + }, + "g2_flowrate": + { + "label": "Flow Rate", + "description": "New Flow rate", + "unit": "%", + "type": "int", + "default_value": 100, + "minimum_value": "1", + "minimum_value_warning": "10", + "maximum_value_warning": "200", + "enabled": "g1_Tweak_flowrate" + }, + "g3_Tweak_flowrateOne": + { + "label": "Tweak Flow Rate 1", + "description": "Select if first extruder flow rate has to be tweaked", + "type": "bool", + "default_value": false + }, + "g4_flowrateOne": + { + "label": "Flow Rate One", + "description": "New Flow rate Extruder 1", + "unit": "%", + "type": "int", + "default_value": 100, + "minimum_value": "1", + "minimum_value_warning": "10", + "maximum_value_warning": "200", + "enabled": "g3_Tweak_flowrateOne" + }, + "g5_Tweak_flowrateTwo": + { + "label": "Tweak Flow Rate 2", + "description": "Select if second extruder flow rate has to be tweaked", + "type": "bool", + "default_value": false + }, + "g6_flowrateTwo": + { + "label": "Flow Rate two", + "description": "New Flow rate Extruder 2", + "unit": "%", + "type": "int", + "default_value": 100, + "minimum_value": "1", + "minimum_value_warning": "10", + "maximum_value_warning": "200", + "enabled": "g5_Tweak_flowrateTwo" + }, + "h1_Tweak_bedTemp": + { + "label": "Tweak Bed Temp", + "description": "Select if Bed Temperature has to be tweaked", + "type": "bool", + "default_value": false + }, + "h2_bedTemp": + { + "label": "Bed Temp", + "description": "New Bed Temperature", + "unit": "C", + "type": "float", + "default_value": 60, + "minimum_value": "0", + "minimum_value_warning": "30", + "maximum_value_warning": "120", + "enabled": "h1_Tweak_bedTemp" + }, + "i1_Tweak_extruderOne": + { + "label": "Tweak Extruder 1 Temp", + "description": "Select if First Extruder Temperature has to be tweaked", + "type": "bool", + "default_value": false + }, + "i2_extruderOne": + { + "label": "Extruder 1 Temp", + "description": "New First Extruder Temperature", + "unit": "C", + "type": "float", + "default_value": 190, + "minimum_value": "0", + "minimum_value_warning": "160", + "maximum_value_warning": "250", + "enabled": "i1_Tweak_extruderOne" + }, + "i3_Tweak_extruderTwo": + { + "label": "Tweak Extruder 2 Temp", + "description": "Select if Second Extruder Temperature has to be tweaked", + "type": "bool", + "default_value": false + }, + "i4_extruderTwo": + { + "label": "Extruder 2 Temp", + "description": "New Second Extruder Temperature", + "unit": "C", + "type": "float", + "default_value": 190, + "minimum_value": "0", + "minimum_value_warning": "160", + "maximum_value_warning": "250", + "enabled": "i3_Tweak_extruderTwo" + }, + "j1_Tweak_fanSpeed": + { + "label": "Tweak Fan Speed", + "description": "Select if Fan Speed has to be tweaked", + "type": "bool", + "default_value": false + }, + "j2_fanSpeed": + { + "label": "Fan Speed", + "description": "New Fan Speed (0-255)", + "unit": "PWM", + "type": "int", + "default_value": 255, + "minimum_value": "0", + "minimum_value_warning": "15", + "maximum_value_warning": "255", + "enabled": "j1_Tweak_fanSpeed" + } + } + }""" + + def getValue(self, line, key, default = None): #replace default getvalue due to comment-reading feature + if not key in line or (";" in line and line.find(key) > line.find(";") and + not ";TweakAtZ" in key and not ";LAYER:" in key): + return default + subPart = line[line.find(key) + len(key):] #allows for string lengths larger than 1 + if ";TweakAtZ" in key: + m = re.search("^[0-4]", subPart) + elif ";LAYER:" in key: + m = re.search("^[+-]?[0-9]*", subPart) + else: + #the minus at the beginning allows for negative values, e.g. for delta printers + m = re.search("^[-]?[0-9]*\.?[0-9]*", subPart) + if m == None: + return default + try: + return float(m.group(0)) + except: + return default + + def execute(self, data): + #Check which tweaks should apply + TweakProp = {"speed": self.getSettingValueByKey("e1_Tweak_speed"), + "flowrate": self.getSettingValueByKey("g1_Tweak_flowrate"), + "flowrateOne": self.getSettingValueByKey("g3_Tweak_flowrateOne"), + "flowrateTwo": self.getSettingValueByKey("g5_Tweak_flowrateTwo"), + "bedTemp": self.getSettingValueByKey("h1_Tweak_bedTemp"), + "extruderOne": self.getSettingValueByKey("i1_Tweak_extruderOne"), + "extruderTwo": self.getSettingValueByKey("i3_Tweak_extruderTwo"), + "fanSpeed": self.getSettingValueByKey("j1_Tweak_fanSpeed")} + TweakPrintSpeed = self.getSettingValueByKey("f1_Tweak_printspeed") + TweakStrings = {"speed": "M220 S%f\n", + "flowrate": "M221 S%f\n", + "flowrateOne": "M221 T0 S%f\n", + "flowrateTwo": "M221 T1 S%f\n", + "bedTemp": "M140 S%f\n", + "extruderOne": "M104 S%f T0\n", + "extruderTwo": "M104 S%f T1\n", + "fanSpeed": "M106 S%d\n"} + target_values = {"speed": self.getSettingValueByKey("e2_speed"), + "printspeed": self.getSettingValueByKey("f2_printspeed"), + "flowrate": self.getSettingValueByKey("g2_flowrate"), + "flowrateOne": self.getSettingValueByKey("g4_flowrateOne"), + "flowrateTwo": self.getSettingValueByKey("g6_flowrateTwo"), + "bedTemp": self.getSettingValueByKey("h2_bedTemp"), + "extruderOne": self.getSettingValueByKey("i2_extruderOne"), + "extruderTwo": self.getSettingValueByKey("i4_extruderTwo"), + "fanSpeed": self.getSettingValueByKey("j2_fanSpeed")} + old = {"speed": -1, "flowrate": -1, "flowrateOne": -1, "flowrateTwo": -1, "platformTemp": -1, "extruderOne": -1, + "extruderTwo": -1, "bedTemp": -1, "fanSpeed": -1, "state": -1} + twLayers = self.getSettingValueByKey("d_twLayers") + if self.getSettingValueByKey("c_behavior") == "single_layer": + behavior = 1 + else: + behavior = 0 + try: + twLayers = max(int(twLayers),1) #for the case someone entered something as "funny" as -1 + except: + twLayers = 1 + pres_ext = 0 + done_layers = 0 + z = 0 + x = None + y = None + layer = -100000 #layer no. may be negative (raft) but never that low + # state 0: deactivated, state 1: activated, state 2: active, but below z, + # state 3: active and partially executed (multi layer), state 4: active and passed z + state = 1 + # IsUM2: Used for reset of values (ok for Marlin/Sprinter), + # has to be set to 1 for UltiGCode (work-around for missing default values) + IsUM2 = False + oldValueUnknown = False + TWinstances = 0 + + if self.getSettingValueByKey("a_trigger") == "layer_no": + targetL_i = int(self.getSettingValueByKey("b_targetL")) + targetZ = 100000 + else: + targetL_i = -100000 + targetZ = self.getSettingValueByKey("b_targetZ") + index = 0 + for active_layer in data: + modified_gcode = "" + lines = active_layer.split("\n") + for line in lines: + if ";Generated with Cura_SteamEngine" in line: + TWinstances += 1 + modified_gcode += ";TweakAtZ instances: %d\n" % TWinstances + if not ("M84" in line or "M25" in line or ("G1" in line and TweakPrintSpeed and (state==3 or state==4)) or + ";TweakAtZ instances:" in line): + modified_gcode += line + "\n" + IsUM2 = ("FLAVOR:UltiGCode" in line) or IsUM2 #Flavor is UltiGCode! + if ";TweakAtZ-state" in line: #checks for state change comment + state = self.getValue(line, ";TweakAtZ-state", state) + if ";TweakAtZ instances:" in line: + try: + tempTWi = int(line[20:]) + except: + tempTWi = TWinstances + TWinstances = tempTWi + if ";Small layer" in line: #checks for begin of Cool Head Lift + old["state"] = state + state = 0 + if ";LAYER:" in line: #new layer no. found + if state == 0: + state = old["state"] + layer = self.getValue(line, ";LAYER:", layer) + if targetL_i > -100000: #target selected by layer no. + if (state == 2 or targetL_i == 0) and layer == targetL_i: #determine targetZ from layer no.; checks for tweak on layer 0 + state = 2 + targetZ = z + 0.001 + if (self.getValue(line, "T", None) is not None) and (self.getValue(line, "M", None) is None): #looking for single T-cmd + pres_ext = self.getValue(line, "T", pres_ext) + if "M190" in line or "M140" in line and state < 3: #looking for bed temp, stops after target z is passed + old["bedTemp"] = self.getValue(line, "S", old["bedTemp"]) + if "M109" in line or "M104" in line and state < 3: #looking for extruder temp, stops after target z is passed + if self.getValue(line, "T", pres_ext) == 0: + old["extruderOne"] = self.getValue(line, "S", old["extruderOne"]) + elif self.getValue(line, "T", pres_ext) == 1: + old["extruderTwo"] = self.getValue(line, "S", old["extruderTwo"]) + if "M107" in line: #fan is stopped; is always updated in order not to miss switch off for next object + old["fanSpeed"] = 0 + if "M106" in line and state < 3: #looking for fan speed + old["fanSpeed"] = self.getValue(line, "S", old["fanSpeed"]) + if "M221" in line and state < 3: #looking for flow rate + tmp_extruder = self.getValue(line,"T",None) + if tmp_extruder == None: #check if extruder is specified + old["flowrate"] = self.getValue(line, "S", old["flowrate"]) + elif tmp_extruder == 0: #first extruder + old["flowrateOne"] = self.getValue(line, "S", old["flowrateOne"]) + elif tmp_extruder == 1: #second extruder + old["flowrateOne"] = self.getValue(line, "S", old["flowrateOne"]) + if ("M84" in line or "M25" in line): + if state>0 and TweakProp["speed"]: #"finish" commands for UM Original and UM2 + modified_gcode += "M220 S100 ; speed reset to 100% at the end of print\n" + modified_gcode += "M117 \n" + modified_gcode += line + "\n" + if "G1" in line or "G0" in line: + newZ = self.getValue(line, "Z", z) + x = self.getValue(line, "X", None) + y = self.getValue(line, "Y", None) + e = self.getValue(line, "E", None) + f = self.getValue(line, "F", None) + if 'G1' in line and TweakPrintSpeed and (state==3 or state==4): + # check for pure print movement in target range: + if x != None and y != None and f != None and e != None and newZ==z: + modified_gcode += "G1 F%d X%1.3f Y%1.3f E%1.5f\n" % (int(f / 100.0 * float(target_values["printspeed"])), self.getValue(line, "X"), + self.getValue(line, "Y"), self.getValue(line, "E")) + else: #G1 command but not a print movement + modified_gcode += line + "\n" + # no tweaking on retraction hops which have no x and y coordinate: + if (newZ != z) and (x is not None) and (y is not None): + z = newZ + if z < targetZ and state == 1: + state = 2 + if z >= targetZ and state == 2: + state = 3 + done_layers = 0 + for key in TweakProp: + if TweakProp[key] and old[key]==-1: #old value is not known + oldValueUnknown = True + if oldValueUnknown: #the tweaking has to happen within one layer + twLayers = 1 + if IsUM2: #Parameters have to be stored in the printer (UltiGCode=UM2) + modified_gcode += "M605 S%d;stores parameters before tweaking\n" % (TWinstances-1) + if behavior == 1: #single layer tweak only and then reset + twLayers = 1 + if TweakPrintSpeed and behavior == 0: + twLayers = done_layers + 1 + if state==3: + if twLayers-done_layers>0: #still layers to go? + if targetL_i > -100000: + modified_gcode += ";TweakAtZ V%s: executed at Layer %d\n" % (self.version,layer) + modified_gcode += "M117 Printing... tw@L%4d\n" % layer + else: + modified_gcode += (";TweakAtZ V%s: executed at %1.2f mm\n" % (self.version,z)) + modified_gcode += "M117 Printing... tw@%5.1f\n" % z + for key in TweakProp: + if TweakProp[key]: + modified_gcode += TweakStrings[key] % float(old[key]+(float(target_values[key])-float(old[key]))/float(twLayers)*float(done_layers+1)) + done_layers += 1 + else: + state = 4 + if behavior == 1: #reset values after one layer + if targetL_i > -100000: + modified_gcode += ";TweakAtZ V%s: reset on Layer %d\n" % (self.version,layer) + else: + modified_gcode += ";TweakAtZ V%s: reset at %1.2f mm\n" % (self.version,z) + if IsUM2 and oldValueUnknown: #executes on UM2 with Ultigcode and machine setting + modified_gcode += "M606 S%d;recalls saved settings\n" % (TWinstances-1) + else: #executes on RepRap, UM2 with Ultigcode and Cura setting + for key in TweakProp: + if TweakProp[key]: + modified_gcode += TweakStrings[key] % float(old[key]) + # re-activates the plugin if executed by pre-print G-command, resets settings: + if (z < targetZ or layer == 0) and state >= 3: #resets if below tweak level or at level 0 + state = 2 + done_layers = 0 + if targetL_i > -100000: + modified_gcode += ";TweakAtZ V%s: reset below Layer %d\n" % (self.version,targetL_i) + else: + modified_gcode += ";TweakAtZ V%s: reset below %1.2f mm\n" % (self.version,targetZ) + if IsUM2 and oldValueUnknown: #executes on UM2 with Ultigcode and machine setting + modified_gcode += "M606 S%d;recalls saved settings\n" % (TWinstances-1) + else: #executes on RepRap, UM2 with Ultigcode and Cura setting + for key in TweakProp: + if TweakProp[key]: + modified_gcode += TweakStrings[key] % float(old[key]) + data[index] = modified_gcode + index += 1 + return data diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index b453020ffa..c9c1443bfe 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -106,7 +106,7 @@ class SimulationPass(RenderPass): nozzle_node = node nozzle_node.setVisible(False) - elif issubclass(type(node), SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible() and node.callDecoration("getBuildPlateNumber") == active_build_plate: + elif issubclass(type(node), SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible(): layer_data = node.callDecoration("getLayerData") if not layer_data: continue diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 7a716d3b2b..f667aff998 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -104,7 +104,7 @@ class SimulationView(View): title = catalog.i18nc("@info:title", "Simulation View")) def _resetSettings(self): - self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed + self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed, 3 is layer thickness self._extruder_count = 0 self._extruder_opacity = [1.0, 1.0, 1.0, 1.0] self._show_travel_moves = 0 diff --git a/plugins/SimulationView/SimulationView.qml b/plugins/SimulationView/SimulationView.qml index 19ae81a6e3..11b985f77c 100644 --- a/plugins/SimulationView/SimulationView.qml +++ b/plugins/SimulationView/SimulationView.qml @@ -176,7 +176,6 @@ Item viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2); viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3); } - } Label diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index e156e655ce..50ff2864b7 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -28,6 +28,7 @@ class SolidView(View): self._enabled_shader = None self._disabled_shader = None self._non_printing_shader = None + self._support_mesh_shader = None self._extruders_model = ExtrudersModel() self._theme = None @@ -54,6 +55,11 @@ class SolidView(View): 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) + global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: support_extruder_nr = global_container_stack.getProperty("support_extruder_nr", "value") @@ -117,6 +123,16 @@ class SolidView(View): renderer.queueNode(node, shader = self._non_printing_shader, transparent = True) elif getattr(node, "_outside_buildarea", False): renderer.queueNode(node, shader = self._disabled_shader) + elif per_mesh_stack and per_mesh_stack.getProperty("support_mesh", "value"): + # 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: renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms) if node.callDecoration("isGroup") and Selection.isSelected(node): diff --git a/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py b/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py index 126dbbbde3..786b97d034 100644 --- a/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py @@ -115,7 +115,6 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): self._not_authenticated_message.hide() self._requestAuthentication() - pass # Cura Connect doesn't do any authorization def connect(self): super().connect() diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index c43d9a826b..6c03450a88 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -96,9 +96,12 @@ class USBPrinterOutputDevice(PrinterOutputDevice): Application.getInstance().getController().setActiveStage("MonitorStage") - gcode_list = getattr(Application.getInstance().getController().getScene(), "gcode_list") - self._printGCode(gcode_list) + # find the G-code for the active build plate to print + active_build_plate_id = Application.getInstance().getBuildPlateModel().activeBuildPlate + gcode_dict = getattr(Application.getInstance().getController().getScene(), "gcode_dict") + gcode_list = gcode_dict[active_build_plate_id] + self._printGCode(gcode_list) ## Show firmware interface. # This will create the view if its not already created. diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6eef6b1e9b..87b72928ca 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3633,7 +3633,7 @@ "minimum_value": "0", "maximum_value_warning": "100", "default_value": 15, - "value": "15 if support_enable else 0", + "value": "15 if support_enable else 0 if support_tree_enable else 15", "enabled": "support_enable or support_tree_enable", "limit_to_extruder": "support_infill_extruder_nr", "settable_per_mesh": false, @@ -4233,6 +4233,18 @@ "limit_to_extruder": "support_infill_extruder_nr", "enabled": "support_enable and support_use_towers", "settable_per_mesh": true + }, + "support_mesh_drop_down": + { + "label": "Drop Down Support Mesh", + "description": "Make support everywhere below the support mesh, so that there's no overhang in the support mesh.", + "type": "bool", + "default_value": true, + "enabled": "support_mesh", + "settable_per_mesh": true, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": false } } }, @@ -5261,18 +5273,6 @@ "settable_per_meshgroup": false, "settable_globally": false }, - "support_mesh_drop_down": - { - "label": "Drop Down Support Mesh", - "description": "Make support everywhere below the support mesh, so that there's no overhang in the support mesh.", - "type": "bool", - "default_value": true, - "enabled": "support_mesh", - "settable_per_mesh": true, - "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": false - }, "anti_overhang_mesh": { "label": "Anti Overhang Mesh", diff --git a/resources/definitions/m180.def.json b/resources/definitions/malyan_m180.def.json similarity index 98% rename from resources/definitions/m180.def.json rename to resources/definitions/malyan_m180.def.json index 71aa729b7e..5e0a6038dd 100644 --- a/resources/definitions/m180.def.json +++ b/resources/definitions/malyan_m180.def.json @@ -1,4 +1,5 @@ { + "id": "malyan_m180", "version": 2, "name": "Malyan M180", "inherits": "fdmprinter", diff --git a/resources/definitions/malyan_m200.def.json b/resources/definitions/malyan_m200.def.json new file mode 100644 index 0000000000..9aae3a5244 --- /dev/null +++ b/resources/definitions/malyan_m200.def.json @@ -0,0 +1,85 @@ +{ + "id": "malyan_m200", + "version": 2, + "name": "Malyan M200", + "inherits": "fdmprinter", + "metadata": { + "author": "Brian Corbino, Tyler Gibson", + "manufacturer": "Malyan", + "category": "Other", + "file_formats": "text/x-gcode", + "platform": "malyan_m200_platform.stl", + "has_machine_quality": true, + "has_materials": true, + "preferred_quality": "*normal*", + "supports_usb_connection": true, + "visible": true, + "first_start_actions": ["MachineSettingsAction"], + "supported_actions": ["MachineSettingsAction"] + }, + + "overrides": { + "machine_name": { "default_value": "Malyan M200" }, + "speed_print": { "default_value": 50 }, + "speed_wall_0": { "value": "round(speed_print * 0.75, 2)" }, + "speed_wall_x": { "value": "speed_print" }, + "speed_support": { "value": "speed_wall_0" }, + "speed_layer_0": { "value": "round(speed_print / 2.0, 2)" }, + "speed_travel": { "default_value": 50 }, + "speed_travel_layer_0": { "default_value": 40 }, + "speed_infill": { "value": "speed_print" }, + "speed_topbottom": {"value": "speed_print / 2"}, + + "layer_height": { "minimum_value": "0.04375", "maximum_value": "machine_nozzle_size * 0.875", "maximum_value_warning": "machine_nozzle_size * 0.48125 + 0.0875", "default_value": 0.13125 }, + "line_width": { "value": "round(machine_nozzle_size * 0.875, 2)" }, + + "material_print_temperature": { "minimum_value": "0" }, + "material_print_temperature_layer_0": { "value": "min(material_print_temperature + 5, 245)" }, + "material_bed_temperature": { "minimum_value": "0" }, + "material_bed_temperature_layer_0": { "value": "min(material_bed_temperature + 5, 70)" }, + "material_standby_temperature": { "minimum_value": "0" }, + "machine_show_variants": { "default_value": true }, + "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, + "machine_start_gcode" : { + "default_value": "G21;(metric values)\nG90;(absolute positioning)\nM82;(set extruder to absolute mode)\nM107;(start with the fan off)\nG28;(Home the printer)\nG92 E0;(Reset the extruder to 0)\nG0 Z5 E5 F500;(Move up and prime the nozzle)\nG0 X-1 Z0;(Move outside the printable area)\nG1 Y60 E8 F500;(Draw a priming/wiping line to the rear)\nG1 X-1;(Move a little closer to the print area)\nG1 Y10 E16 F500;(draw more priming/wiping)\nG1 E15 F250;(Small retract)\nG92 E0;(Zero the extruder)" + }, + "machine_end_gcode" : { + "default_value": "G0 X0 Y127;(Stick out the part)\nM190 S0;(Turn off heat bed, don't wait.)\nG92 E10;(Set extruder to 10)\nG1 E7 F200;(retract 3mm)\nM104 S0;(Turn off nozzle, don't wait)\nG4 S300;(Delay 5 minutes)\nM107;(Turn off part fan)\nM84;(Turn off stepper motors.)" + }, + "machine_width": { "default_value": 120 }, + "machine_depth": { "default_value": 120 }, + "machine_height": { "default_value": 120 }, + "machine_heated_bed": { "default_value": true }, + "machine_center_is_zero": { "default_value": false }, + "material_diameter": { "value": 1.75 }, + "machine_nozzle_size": { + "default_value": 0.4, + "minimum_value": 0.15 + }, + "machine_max_feedrate_x": { "default_value": 150 }, + "machine_max_feedrate_y": { "default_value": 150 }, + "machine_max_feedrate_z": { "default_value": 1.5 }, + "machine_max_feedrate_e": { "default_value": 100 }, + "machine_max_acceleration_x": { "default_value": 800 }, + "machine_max_acceleration_y": { "default_value": 800 }, + "machine_max_acceleration_z": { "default_value": 20 }, + "machine_max_acceleration_e": { "default_value": 10000 }, + "machine_max_jerk_xy": { "default_value": 20 }, + "machine_max_jerk_z": { "default_value": 0.4 }, + "machine_max_jerk_e": { "default_value": 5}, + "adhesion_type": { "default_value": "raft" }, + "raft_margin": { "default_value": 5 }, + "raft_airgap": { "default_value": 0.2625 }, + "raft_base_thickness": { "value": "0.30625" }, + "raft_interface_thickness": { "value": "0.21875" }, + "raft_surface_layers": { "default_value": 1 }, + "skirt_line_count": { "default_value": 2}, + "brim_width" : { "default_value": 5}, + "start_layers_at_same_position": { "default_value": true}, + "retraction_combing": { "default_value": "noskin" }, + "retraction_amount" : { "default_value": 4.5}, + "retraction_speed" : { "default_value": 40}, + "coasting_enable": { "default_value": true }, + "prime_tower_enable": { "default_value": false} + } +} diff --git a/resources/definitions/monoprice_select_mini_v1.def.json b/resources/definitions/monoprice_select_mini_v1.def.json new file mode 100644 index 0000000000..7264f0a6fc --- /dev/null +++ b/resources/definitions/monoprice_select_mini_v1.def.json @@ -0,0 +1,18 @@ +{ + "id": "monoprice_select_mini_v1", + "version": 2, + "name": "Monoprice Select Mini V1", + "inherits": "malyan_m200", + "metadata": { + "author": "Brian Corbino, Tyler Gibson", + "manufacturer": "Monoprice", + "category": "Other", + "file_formats": "text/x-gcode", + "quality_definition": "malyan_m200", + "visible": true + }, + + "overrides": { + "machine_name": { "default_value": "Monoprice Select Mini V1" } + } +} diff --git a/resources/definitions/monoprice_select_mini_v2.def.json b/resources/definitions/monoprice_select_mini_v2.def.json new file mode 100644 index 0000000000..87014c136b --- /dev/null +++ b/resources/definitions/monoprice_select_mini_v2.def.json @@ -0,0 +1,25 @@ +{ + "id": "monoprice_select_mini_v2", + "version": 2, + "name": "Monoprice Select Mini V2 (E3D)", + "inherits": "malyan_m200", + "metadata": { + "author": "Tyler Gibson", + "manufacturer": "Monoprice", + "category": "Other", + "file_formats": "text/x-gcode", + "has_machine_quality": true, + "has_materials": true, + "preferred_quality": "*normal*", + "visible": true + }, + + "overrides": { + "machine_name": { "default_value": "Monoprice Select Mini V2" }, + "adhesion_type": { "default_value": "brim" }, + "retraction_combing": { "default_value": "noskin" }, + "retraction_amount" : { "default_value": 2.5}, + "retraction_speed" : { "default_value": 40}, + "material_print_temperature_layer_0": { "value": "material_print_temperature + 5" } + } +} diff --git a/resources/meshes/malyan_m200_platform.stl b/resources/meshes/malyan_m200_platform.stl new file mode 100644 index 0000000000..32b19a0911 Binary files /dev/null and b/resources/meshes/malyan_m200_platform.stl differ diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 1a4b421572..b5f51f4d63 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -47,6 +47,7 @@ Menu { model: Cura.BuildPlateModel MenuItem { + enabled: UM.Selection.hasSelection text: Cura.BuildPlateModel.getItem(index).name; onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.getItem(index).buildPlateNumber); checkable: true @@ -58,6 +59,7 @@ Menu } MenuItem { + enabled: UM.Selection.hasSelection text: "New build plate"; onTriggered: { CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.maxBuildPlate + 1); diff --git a/resources/qml/ObjectsList.qml b/resources/qml/ObjectsList.qml index a02ea2288d..489e38e8d7 100644 --- a/resources/qml/ObjectsList.qml +++ b/resources/qml/ObjectsList.qml @@ -105,7 +105,6 @@ Rectangle topMargin: UM.Theme.getSize("default_margin").height; left: parent.left; leftMargin: UM.Theme.getSize("default_margin").height; - //bottom: objectsList.top; bottomMargin: UM.Theme.getSize("default_margin").height; } @@ -139,7 +138,7 @@ Rectangle anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30 - text: Cura.ObjectsModel.getItem(index) ? Cura.ObjectsModel.getItem(index).name : ""; + text: (index >= 0) && Cura.ObjectsModel.getItem(index) ? Cura.ObjectsModel.getItem(index).name : ""; color: Cura.ObjectsModel.getItem(index).isSelected ? palette.highlightedText : (Cura.ObjectsModel.getItem(index).isOutsideBuildArea ? palette.mid : palette.text) elide: Text.ElideRight } diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index e5ed9e46c5..ac5cacdbf6 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -453,34 +453,6 @@ UM.PreferencesPage text: catalog.i18nc("@label","Opening and saving files") } - UM.TooltipArea { - width: childrenRect.width - height: childrenRect.height - text: catalog.i18nc("@info:tooltip","Use multi build plate functionality (EXPERIMENTAL)") - - CheckBox - { - id: useMultiBuildPlateCheckbox - text: catalog.i18nc("@option:check","Use multi build plate functionality (EXPERIMENTAL, restart)") - checked: boolCheck(UM.Preferences.getValue("cura/use_multi_build_plate")) - onCheckedChanged: UM.Preferences.setValue("cura/use_multi_build_plate", checked) - } - } - - UM.TooltipArea { - width: childrenRect.width - height: childrenRect.height - text: catalog.i18nc("@info:tooltip","Should newly loaded models be arranged on the build plate? Used in conjunction with multi build plate (EXPERIMENTAL)") - - CheckBox - { - id: arrangeOnLoadCheckbox - text: catalog.i18nc("@option:check","Arrange objects on load (EXPERIMENTAL)") - checked: boolCheck(UM.Preferences.getValue("cura/arrange_objects_on_load")) - onCheckedChanged: UM.Preferences.setValue("cura/arrange_objects_on_load", checked) - } - } - UM.TooltipArea { width: childrenRect.width height: childrenRect.height @@ -688,6 +660,49 @@ UM.PreferencesPage onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked) } } + + Item + { + //: Spacer + height: UM.Theme.getSize("default_margin").height + width: UM.Theme.getSize("default_margin").height + } + + Label + { + font.bold: true + text: catalog.i18nc("@label","Experimental") + } + + UM.TooltipArea { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip","Use multi build plate functionality") + + CheckBox + { + id: useMultiBuildPlateCheckbox + text: catalog.i18nc("@option:check","Use multi build plate functionality (restart required)") + checked: boolCheck(UM.Preferences.getValue("cura/use_multi_build_plate")) + onCheckedChanged: UM.Preferences.setValue("cura/use_multi_build_plate", checked) + } + } + + UM.TooltipArea { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip","Should newly loaded models be arranged on the build plate? Used in conjunction with multi build plate (EXPERIMENTAL)") + + CheckBox + { + id: arrangeOnLoadCheckbox + text: catalog.i18nc("@option:check","Do not arrange objects on load") + checked: boolCheck(UM.Preferences.getValue("cura/not_arrange_objects_on_load")) + onCheckedChanged: UM.Preferences.setValue("cura/not_arrange_objects_on_load", checked) + } + } + + } } } diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 311150c6b9..c3f36f5125 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -104,14 +104,13 @@ TabView Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") } - Row - { - width: scrollView.columnWidth; - height: parent.rowHeight; + Row { + width: scrollView.columnWidth + height: parent.rowHeight spacing: Math.floor(UM.Theme.getSize("default_margin").width/2) - Rectangle - { + // color indicator square + Rectangle { id: colorSelector color: properties.color_code @@ -121,17 +120,36 @@ TabView anchors.verticalCenter: parent.verticalCenter - MouseArea { anchors.fill: parent; onClicked: colorDialog.open(); enabled: base.editingEnabled } + // open the color selection dialog on click + MouseArea { + anchors.fill: parent + onClicked: colorDialog.open() + enabled: base.editingEnabled + } } - ReadOnlyTextField - { + + // make sure the color stays connected after changing the color + Binding { + target: colorSelector + property: "color" + value: properties.color_code + } + + // pretty color name text field + ReadOnlyTextField { id: colorLabel; text: properties.color_name; readOnly: !base.editingEnabled onEditingFinished: base.setMetaDataEntry("color_name", properties.color_name, text) } - ColorDialog { id: colorDialog; color: properties.color_code; onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color) } + // popup dialog to select a new color + // if successful it sets the properties.color_code value to the new color + ColorDialog { + id: colorDialog + color: properties.color_code + onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color) + } } Item { width: parent.width; height: UM.Theme.getSize("default_margin").height } @@ -401,11 +419,11 @@ TabView } // Tiny convenience function to check if a value really changed before trying to set it. - function setMetaDataEntry(entry_name, old_value, new_value) - { - if(old_value != new_value) - { - Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, entry_name, new_value); + function setMetaDataEntry(entry_name, old_value, new_value) { + if (old_value != new_value) { + Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, entry_name, new_value) + // make sure the UI properties are updated as well since we don't re-fetch the entire model here + properties[entry_name] = new_value } } diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 81c1bd711a..6b041b895a 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -132,93 +132,82 @@ UM.ManagementPage } buttons: [ - Button - { - text: catalog.i18nc("@action:button", "Activate"); + + // Activate button + Button { + text: catalog.i18nc("@action:button", "Activate") iconName: "list-activate"; enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId && Cura.MachineManager.hasMaterials - onClicked: - { - forceActiveFocus(); + onClicked: { + forceActiveFocus() Cura.MachineManager.setActiveMaterial(base.currentItem.id) currentItem = base.model.getItem(base.objectList.currentIndex) // Refresh the current item. } }, - Button - { + + // Create button + Button { text: catalog.i18nc("@action:button", "Create") iconName: "list-add" - onClicked: + onClicked: { + forceActiveFocus() + Cura.ContainerManager.createMaterial() + } + + Connections { - forceActiveFocus(); - var material_id = Cura.ContainerManager.createMaterial() - if(material_id == "") + target: base.objectList.model + onItemsChanged: { - return + base.objectList.currentIndex = base.getIndexById(Cura.MachineManager.activeMaterialId); } - if(Cura.MachineManager.hasMaterials) - { - Cura.MachineManager.setActiveMaterial(material_id) - } - base.objectList.currentIndex = base.getIndexById(material_id); } }, - Button - { + + // Duplicate button + Button { text: catalog.i18nc("@action:button", "Duplicate"); iconName: "list-add"; enabled: base.currentItem != null - onClicked: - { - forceActiveFocus(); - var base_file = Cura.ContainerManager.getContainerMetaDataEntry(base.currentItem.id, "base_file") - // We need to copy the base container instead of the specific variant. - var material_id = base_file == "" ? Cura.ContainerManager.duplicateMaterial(base.currentItem.id): Cura.ContainerManager.duplicateMaterial(base_file) - if(material_id == "") - { - return - } - if(Cura.MachineManager.hasMaterials) - { - Cura.MachineManager.setActiveMaterial(material_id) - } - // TODO: this doesn't work because the source is a bit delayed - base.objectList.currentIndex = base.getIndexById(material_id); + onClicked: { + forceActiveFocus() + Cura.ContainerManager.duplicateOriginalMaterial(base.currentItem.id) } }, - Button - { - text: catalog.i18nc("@action:button", "Remove"); - iconName: "list-remove"; + + // Remove button + Button { + text: catalog.i18nc("@action:button", "Remove") + iconName: "list-remove" enabled: base.currentItem != null && !base.currentItem.readOnly && !Cura.ContainerManager.isContainerUsed(base.currentItem.id) - onClicked: - { - forceActiveFocus(); - confirmDialog.open(); + onClicked: { + forceActiveFocus() + confirmDialog.open() } }, - Button - { - text: catalog.i18nc("@action:button", "Import"); - iconName: "document-import"; - onClicked: - { - forceActiveFocus(); - importDialog.open(); + + // Import button + Button { + text: catalog.i18nc("@action:button", "Import") + iconName: "document-import" + onClicked: { + forceActiveFocus() + importDialog.open() } - visible: true; + visible: true }, - Button - { + + // Export button + Button { text: catalog.i18nc("@action:button", "Export") iconName: "document-export" - onClicked: - { - forceActiveFocus(); - exportDialog.open(); + onClicked: { + forceActiveFocus() + exportDialog.open() } enabled: currentItem != null } + ] Item { diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 9c38c1e066..b96c40d9ea 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -195,11 +195,22 @@ Item text: { var result = "" - if (Cura.MachineManager.activeMachine != null) { + if(Cura.MachineManager.activeMachine != null) + { result = Cura.ProfilesModel.getItem(index).layer_height_without_unit - if (result == undefined) - result = "" + if(result == undefined) + { + result = ""; + } + else + { + result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult... + if (result == undefined || result != result) //Parse failure. + { + result = ""; + } + } } return result } diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg new file mode 100644 index 0000000000..19cc9fd00d --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fast +definition = malyan_m200 + +[metadata] +type = quality +quality_type = draft +material = generic_abs_175 +weight = -2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg new file mode 100644 index 0000000000..5677a0d58d --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Normal +definition = malyan_m200 + +[metadata] +type = quality +quality_type = fast +material = generic_abs_175 +weight = -1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg new file mode 100644 index 0000000000..7798b3f545 --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Finer +definition = malyan_m200 + +[metadata] +type = quality +quality_type = high +material = generic_abs_175 +weight = 1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg new file mode 100644 index 0000000000..c87c66c813 --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = normal +material = generic_abs_175 +weight = 0 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg new file mode 100644 index 0000000000..e6e3cfcd6c --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = superdraft +material = generic_abs_175 +weight = -5 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg new file mode 100644 index 0000000000..fb08013809 --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_abs_175 +weight = -3 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg new file mode 100644 index 0000000000..385d852688 --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Ultra Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = ultra +material = generic_abs_175 +weight = 2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg new file mode 100644 index 0000000000..7026391fb6 --- /dev/null +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Low Detail Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = verydraft +material = generic_abs_175 +weight = -4 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg new file mode 100644 index 0000000000..54be6ecbcc --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M1 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = 2 +quality_type = fine +setting_version = 4 + +[values] +layer_height = 0.04375 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg new file mode 100644 index 0000000000..568dd796f3 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M2 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = 1 +quality_type = high +setting_version = 4 + +[values] +layer_height = 0.0875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg new file mode 100644 index 0000000000..1dc436502b --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M3 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = 0 +quality_type = normal +setting_version = 4 + +[values] +layer_height = 0.13125 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg new file mode 100644 index 0000000000..314a8acd83 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = M4 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = -1 +quality_type = fast +global_quality = true +setting_version = 4 + +[values] +layer_height = 0.175 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg new file mode 100644 index 0000000000..a7fedb7e04 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M5 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = -2 +quality_type = faster +setting_version = 4 + +[values] +layer_height = 0.21875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg new file mode 100644 index 0000000000..441abc3070 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M6 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = -3 +quality_type = draft +setting_version = 4 + +[values] +layer_height = 0.2625 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg new file mode 100644 index 0000000000..2588838174 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = M7 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = -4 +quality_type = turbo +setting_version = 4 + +[values] +layer_height = 0.30625 +layer_height_0 = 0.30625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg new file mode 100644 index 0000000000..800b6104d9 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = M8 Quality +definition = malyan_m200 + +[metadata] +type = quality +weight = -5 +quality_type = hyper +global_quality = true +setting_version = 4 + +[values] +layer_height = 0.35 +layer_height_0 = 0.35 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg new file mode 100644 index 0000000000..d3104caa87 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Fast +definition = malyan_m200 + +[metadata] +type = quality +weight = -2 +quality_type = draft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.21875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg new file mode 100644 index 0000000000..aec535bd71 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Normal +definition = malyan_m200 + +[metadata] +type = quality +weight = -1 +quality_type = fast +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.175 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg new file mode 100644 index 0000000000..ca202862a2 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Finer +definition = malyan_m200 + +[metadata] +type = quality +weight = 1 +quality_type = high +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.0875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..7076718903 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Fine +definition = malyan_m200 + +[metadata] +type = quality +weight = 0 +quality_type = normal +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.13125 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg new file mode 100644 index 0000000000..7dfbdb5886 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = malyan_m200 + +[metadata] +type = quality +weight = -5 +quality_type = superdraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.35 +layer_height_0 = 0.35 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg new file mode 100644 index 0000000000..2fbf82b128 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Draft +definition = malyan_m200 + +[metadata] +type = quality +weight = -3 +quality_type = thickerdraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.2625 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg new file mode 100644 index 0000000000..90e589cca5 --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Ultra Fine +definition = malyan_m200 + +[metadata] +type = quality +weight = 2 +quality_type = ultra +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.04375 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg new file mode 100644 index 0000000000..1210ee214b --- /dev/null +++ b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Low Detail Draft +definition = malyan_m200 + +[metadata] +type = quality +weight = -4 +quality_type = verydraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.30625 +layer_height_0 = 0.30625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg new file mode 100644 index 0000000000..aef83471ba --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fast +definition = malyan_m200 + +[metadata] +type = quality +quality_type = draft +material = generic_petg_175 +weight = -2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg new file mode 100644 index 0000000000..3c7fc2c239 --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Normal +definition = malyan_m200 + +[metadata] +type = quality +quality_type = fast +material = generic_petg_175 +weight = -1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg new file mode 100644 index 0000000000..eb1654eae3 --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Finer +definition = malyan_m200 + +[metadata] +type = quality +quality_type = high +material = generic_petg_175 +weight = 1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg new file mode 100644 index 0000000000..53e60d2d62 --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = normal +material = generic_petg_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg new file mode 100644 index 0000000000..d2a96386ae --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = superdraft +material = generic_petg_175 +weight = -5 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg new file mode 100644 index 0000000000..e2f37ae43b --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_petg_175 +weight = -3 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg new file mode 100644 index 0000000000..0fa89f2569 --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Ultra Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = ultra +material = generic_petg_175 +weight = 2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg new file mode 100644 index 0000000000..84bedf5c14 --- /dev/null +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Low Detail Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = verydraft +material = generic_petg_175 +weight = -4 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg new file mode 100644 index 0000000000..4f221eceb7 --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fast +definition = malyan_m200 + +[metadata] +type = quality +quality_type = draft +material = generic_pla_175 +weight = -2 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg new file mode 100644 index 0000000000..3097fe055a --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Normal +definition = malyan_m200 + +[metadata] +type = quality +quality_type = fast +material = generic_pla_175 +weight = -1 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg new file mode 100644 index 0000000000..062c120ad0 --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Finer +definition = malyan_m200 + +[metadata] +type = quality +quality_type = high +material = generic_pla_175 +weight = 1 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg new file mode 100644 index 0000000000..e01141ed9e --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = normal +material = generic_pla_175 +weight = 0 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg new file mode 100644 index 0000000000..53eb4380eb --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = superdraft +material = generic_pla_175 +weight = -5 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg new file mode 100644 index 0000000000..32d2b419bc --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_pla_175 +weight = -3 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg new file mode 100644 index 0000000000..3865059254 --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Ultra Fine +definition = malyan_m200 + +[metadata] +type = quality +quality_type = ultra +material = generic_pla_175 +weight = 2 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg new file mode 100644 index 0000000000..a624c056be --- /dev/null +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Low Detail Draft +definition = malyan_m200 + +[metadata] +type = quality +quality_type = verydraft +material = generic_pla_175 +weight = -4 +setting_version = 4 + +[values] +material_bed_temperature = 60 +material_bed_temperature_layer_0 = 60 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg new file mode 100644 index 0000000000..a63256573a --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = draft +material = generic_abs_175 +weight = -2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg new file mode 100644 index 0000000000..49f4486596 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = fast +material = generic_abs_175 +weight = -1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg new file mode 100644 index 0000000000..eab16a8e2b --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = high +material = generic_abs_175 +weight = 1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg new file mode 100644 index 0000000000..03aeb4067b --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = normal +material = generic_abs_175 +weight = 0 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg new file mode 100644 index 0000000000..148f53ba73 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = superdraft +material = generic_abs_175 +weight = -5 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg new file mode 100644 index 0000000000..e2ad71a360 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_abs_175 +weight = -3 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg new file mode 100644 index 0000000000..7ebdf80baf --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_abs_175 +weight = 2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg new file mode 100644 index 0000000000..9965ae8bcf --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = verydraft +material = generic_abs_175 +weight = -4 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg new file mode 100644 index 0000000000..b7d0faa2c7 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = -2 +quality_type = draft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.21875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg new file mode 100644 index 0000000000..f7f338e4c9 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = -1 +quality_type = fast +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.175 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg new file mode 100644 index 0000000000..4a37a1afd8 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = 1 +quality_type = high +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.0875 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..b8e545adcf --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = 0 +quality_type = normal +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.13125 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg new file mode 100644 index 0000000000..0ef9db5875 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = -5 +quality_type = superdraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.35 +layer_height_0 = 0.35 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg new file mode 100644 index 0000000000..4dd3a7aafe --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = -3 +quality_type = thickerdraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.2625 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg new file mode 100644 index 0000000000..337f0d06bc --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = 2 +quality_type = ultra +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.04375 +layer_height_0 = 0.2625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg new file mode 100644 index 0000000000..e884077069 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +weight = -4 +quality_type = verydraft +global_quality = True +setting_version = 4 + +[values] +layer_height = 0.30625 +layer_height_0 = 0.30625 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +speed_layer_0 = =round(speed_print * 30 / 50) +speed_topbottom = 20 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg new file mode 100644 index 0000000000..4a03c17a63 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = draft +material = generic_nylon_175 +weight = -2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg new file mode 100644 index 0000000000..1c04f77b8b --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = fast +material = generic_nylon_175 +weight = -1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg new file mode 100644 index 0000000000..d57516598a --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = high +material = generic_nylon_175 +weight = 1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg new file mode 100644 index 0000000000..308ea86311 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = normal +material = generic_nylon_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg new file mode 100644 index 0000000000..db4f3ca907 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = superdraft +material = generic_nylon_175 +weight = -5 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg new file mode 100644 index 0000000000..9a1afc0e48 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_nylon_175 +weight = -3 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg new file mode 100644 index 0000000000..3453671a72 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = ultra +material = generic_nylon_175 +weight = 2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg new file mode 100644 index 0000000000..ee2531fc4e --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = verydraft +material = generic_nylon_175 +weight = -4 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg new file mode 100644 index 0000000000..aa5fc7844d --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = draft +material = generic_pc_175 +weight = -2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg new file mode 100644 index 0000000000..232c4ab6f3 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = fast +material = generic_pc_175 +weight = -1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg new file mode 100644 index 0000000000..aa9da322fb --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = high +material = generic_pc_175 +weight = 1 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg new file mode 100644 index 0000000000..145b21221b --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = normal +material = generic_pc_175 +weight = 0 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg new file mode 100644 index 0000000000..b6e53bda62 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = superdraft +material = generic_pc_175 +weight = -5 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg new file mode 100644 index 0000000000..055228ab13 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_pc_175 +weight = -3 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg new file mode 100644 index 0000000000..a3e99b998e --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = ultra +material = generic_pc_175 +weight = 2 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg new file mode 100644 index 0000000000..73f5a2f2c9 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = verydraft +material = generic_pc_175 +weight = -4 +setting_version = 4 + +[values] +material_bed_temperature = 70 +material_bed_temperature_layer_0 = 70 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg new file mode 100644 index 0000000000..8a33e03310 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = draft +material = generic_petg_175 +weight = -2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg new file mode 100644 index 0000000000..fb084fa08e --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = fast +material = generic_petg_175 +weight = -1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg new file mode 100644 index 0000000000..16891f6f43 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = high +material = generic_petg_175 +weight = 1 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg new file mode 100644 index 0000000000..bb2f0b47a8 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = normal +material = generic_petg_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg new file mode 100644 index 0000000000..78ca1b6b7a --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = superdraft +material = generic_petg_175 +weight = -5 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg new file mode 100644 index 0000000000..69606ff913 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_petg_175 +weight = -3 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg new file mode 100644 index 0000000000..7c5ac599c8 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = ultra +material = generic_petg_175 +weight = 2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg new file mode 100644 index 0000000000..ed0c2510f5 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = verydraft +material = generic_petg_175 +weight = -4 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg new file mode 100644 index 0000000000..04a955cf6c --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fast +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = draft +material = generic_pla_175 +weight = -2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg new file mode 100644 index 0000000000..6efc0935e2 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Normal +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = fast +material = generic_pla_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg new file mode 100644 index 0000000000..8fe2371e5d --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Finer +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = high +material = generic_pla_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg new file mode 100644 index 0000000000..01351154c4 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = normal +material = generic_pla_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg new file mode 100644 index 0000000000..adfced9787 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Lowest Quality Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = superdraft +material = generic_pla_175 +weight = -5 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg new file mode 100644 index 0000000000..f4522c9778 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = thickerdraft +material = generic_pla_175 +weight = -3 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg new file mode 100644 index 0000000000..2fa8eb7f81 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Ultra Fine +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = ultra +material = generic_pla_175 +weight = 2 +setting_version = 4 \ No newline at end of file diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg new file mode 100644 index 0000000000..e59cf4a490 --- /dev/null +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg @@ -0,0 +1,11 @@ +[general] +version = 2 +name = Low Detail Draft +definition = monoprice_select_mini_v2 + +[metadata] +type = quality +quality_type = verydraft +material = generic_pla_175 +weight = 0 +setting_version = 4 \ No newline at end of file diff --git a/resources/shaders/striped.shader b/resources/shaders/striped.shader index ce7d14e39e..7cf5a62c3f 100644 --- a/resources/shaders/striped.shader +++ b/resources/shaders/striped.shader @@ -32,6 +32,7 @@ fragment = uniform highp vec3 u_viewPosition; uniform mediump float u_width; + uniform mediump bool u_vertical_stripes; varying highp vec3 v_position; varying highp vec3 v_vertex; @@ -40,7 +41,9 @@ fragment = void main() { mediump vec4 finalColor = vec4(0.0); - mediump vec4 diffuseColor = (mod((-v_position.x + v_position.y), u_width) < (u_width / 2.)) ? u_diffuseColor1 : u_diffuseColor2; + mediump vec4 diffuseColor = u_vertical_stripes ? + (((mod(v_vertex.x, u_width) < (u_width / 2.)) ^^ (mod(v_vertex.z, u_width) < (u_width / 2.))) ? u_diffuseColor1 : u_diffuseColor2) : + ((mod((-v_position.x + v_position.y), u_width) < (u_width / 2.)) ? u_diffuseColor1 : u_diffuseColor2); /* Ambient Component */ finalColor += u_ambientColor; @@ -98,6 +101,7 @@ fragment41core = uniform highp vec3 u_viewPosition; uniform mediump float u_width; + uniform mediump bool u_vertical_stripes; in highp vec3 v_position; in highp vec3 v_vertex; @@ -108,7 +112,9 @@ fragment41core = void main() { mediump vec4 finalColor = vec4(0.0); - mediump vec4 diffuseColor = (mod((-v_position.x + v_position.y), u_width) < (u_width / 2.)) ? u_diffuseColor1 : u_diffuseColor2; + mediump vec4 diffuseColor = u_vertical_stripes ? + (((mod(v_vertex.x, u_width) < (u_width / 2.)) ^^ (mod(v_vertex.z, u_width) < (u_width / 2.))) ? u_diffuseColor1 : u_diffuseColor2) : + ((mod((-v_position.x + v_position.y), u_width) < (u_width / 2.)) ? u_diffuseColor1 : u_diffuseColor2); /* Ambient Component */ finalColor += u_ambientColor; @@ -138,6 +144,7 @@ u_diffuseColor2 = [0.5, 0.5, 0.5, 1.0] u_specularColor = [0.4, 0.4, 0.4, 1.0] u_shininess = 20.0 u_width = 5.0 +u_vertical_stripes = 0 [bindings] u_modelMatrix = model_matrix @@ -145,7 +152,8 @@ u_viewProjectionMatrix = view_projection_matrix u_normalMatrix = normal_matrix u_viewPosition = view_position u_lightPosition = light_0_position -u_diffuseColor = diffuse_color +u_diffuseColor1 = diffuse_color +u_diffuseColor2 = diffuse_color_2 [attributes] a_vertex = vertex