mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-20 13:17:51 -06:00
Merge branch 'network_rewrite' into feature_preheat_extruder
This commit is contained in:
commit
76fd49b185
137 changed files with 4422 additions and 177 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -47,7 +47,6 @@ plugins/Doodle3D-cura-plugin
|
||||||
plugins/FlatProfileExporter
|
plugins/FlatProfileExporter
|
||||||
plugins/GodMode
|
plugins/GodMode
|
||||||
plugins/OctoPrintPlugin
|
plugins/OctoPrintPlugin
|
||||||
plugins/PostProcessingPlugin
|
|
||||||
plugins/ProfileFlattener
|
plugins/ProfileFlattener
|
||||||
plugins/X3GWriter
|
plugins/X3GWriter
|
||||||
|
|
||||||
|
|
|
@ -319,7 +319,7 @@ class CuraApplication(QtApplication):
|
||||||
preferences.addPreference("cura/asked_dialog_on_project_save", False)
|
preferences.addPreference("cura/asked_dialog_on_project_save", False)
|
||||||
preferences.addPreference("cura/choice_on_profile_override", "always_ask")
|
preferences.addPreference("cura/choice_on_profile_override", "always_ask")
|
||||||
preferences.addPreference("cura/choice_on_open_project", "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/use_multi_build_plate", False)
|
||||||
|
|
||||||
preferences.addPreference("cura/currency", "€")
|
preferences.addPreference("cura/currency", "€")
|
||||||
|
@ -1428,11 +1428,13 @@ class CuraApplication(QtApplication):
|
||||||
self.fileLoaded.emit(filename)
|
self.fileLoaded.emit(filename)
|
||||||
arrange_objects_on_load = (
|
arrange_objects_on_load = (
|
||||||
not Preferences.getInstance().getValue("cura/use_multi_build_plate") or
|
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
|
target_build_plate = self.getBuildPlateModel().activeBuildPlate if arrange_objects_on_load else -1
|
||||||
|
|
||||||
for original_node in nodes:
|
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.setMeshData(original_node.getMeshData())
|
||||||
|
|
||||||
node.setSelectable(True)
|
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
|
# 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, _ = 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 = AddSceneNodeOperation(node, scene.getRoot())
|
||||||
op.push()
|
op.push()
|
||||||
|
|
|
@ -18,7 +18,7 @@ class OneAtATimeIterator(Iterator.Iterator):
|
||||||
def _fillStack(self):
|
def _fillStack(self):
|
||||||
node_list = []
|
node_list = []
|
||||||
for node in self._scene_node.getChildren():
|
for node in self._scene_node.getChildren():
|
||||||
if not type(node) is SceneNode:
|
if not isinstance(node, SceneNode):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if node.callDecoration("getConvexHull"):
|
if node.callDecoration("getConvexHull"):
|
||||||
|
|
|
@ -11,6 +11,7 @@ from UM.Preferences import Preferences
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -177,7 +178,7 @@ class PrintInformation(QObject):
|
||||||
self._material_amounts = material_amounts
|
self._material_amounts = material_amounts
|
||||||
self._calculateInformation(build_plate_number)
|
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
|
total_estimated_time = 0
|
||||||
|
|
||||||
if build_plate_number not in self._print_time_message_values:
|
if build_plate_number not in self._print_time_message_values:
|
||||||
|
|
|
@ -41,6 +41,14 @@ class CuraSceneController(QObject):
|
||||||
self._build_plate_model.setMaxBuildPlate(self._max_build_plate)
|
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)]
|
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)
|
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?
|
# self.buildPlateItemsChanged.emit() # TODO: necessary after setItems?
|
||||||
|
|
||||||
def _calcMaxBuildPlate(self):
|
def _calcMaxBuildPlate(self):
|
||||||
|
@ -75,11 +83,11 @@ class CuraSceneController(QObject):
|
||||||
# Single select
|
# Single select
|
||||||
item = self._objects_model.getItem(index)
|
item = self._objects_model.getItem(index)
|
||||||
node = item["node"]
|
node = item["node"]
|
||||||
Selection.clear()
|
|
||||||
Selection.add(node)
|
|
||||||
build_plate_number = node.callDecoration("getBuildPlateNumber")
|
build_plate_number = node.callDecoration("getBuildPlateNumber")
|
||||||
if build_plate_number is not None and build_plate_number != -1:
|
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
|
self._last_selected_index = index
|
||||||
|
|
||||||
|
|
|
@ -816,6 +816,22 @@ class ContainerManager(QObject):
|
||||||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||||
return self._getMaterialContainerIdForActiveMachine(clone_of_original)
|
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
|
## 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.
|
# \return \type{str} the id of the newly created container.
|
||||||
|
|
|
@ -202,7 +202,6 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
||||||
if meta_data["profile_reader"][0]["extension"] != extension:
|
if meta_data["profile_reader"][0]["extension"] != extension:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
profile_reader = plugin_registry.getPluginObject(plugin_id)
|
profile_reader = plugin_registry.getPluginObject(plugin_id)
|
||||||
try:
|
try:
|
||||||
profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader.
|
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._id = new_id
|
||||||
profile.setName(new_name)
|
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():
|
if "type" in profile.getMetaData():
|
||||||
profile.setMetaDataEntry("type", "quality_changes")
|
profile.setMetaDataEntry("type", "quality_changes")
|
||||||
else:
|
else:
|
||||||
|
@ -515,6 +518,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
extruder_quality_changes_container = self.findInstanceContainers(name = machine.qualityChanges.getName(), extruder = extruder_id)
|
extruder_quality_changes_container = self.findInstanceContainers(name = machine.qualityChanges.getName(), extruder = extruder_id)
|
||||||
if extruder_quality_changes_container:
|
if extruder_quality_changes_container:
|
||||||
extruder_quality_changes_container = extruder_quality_changes_container[0]
|
extruder_quality_changes_container = extruder_quality_changes_container[0]
|
||||||
|
|
||||||
quality_changes_id = extruder_quality_changes_container.getId()
|
quality_changes_id = extruder_quality_changes_container.getId()
|
||||||
extruder_stack.setQualityChangesById(quality_changes_id)
|
extruder_stack.setQualityChangesById(quality_changes_id)
|
||||||
else:
|
else:
|
||||||
|
@ -525,15 +529,92 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
if extruder_quality_changes_container:
|
if extruder_quality_changes_container:
|
||||||
quality_changes_id = extruder_quality_changes_container.getId()
|
quality_changes_id = extruder_quality_changes_container.getId()
|
||||||
extruder_stack.setQualityChangesById(quality_changes_id)
|
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:
|
if not extruder_quality_changes_container:
|
||||||
Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]",
|
Logger.log("w", "Could not find quality_changes named [%s] for extruder [%s]",
|
||||||
machine.qualityChanges.getName(), extruder_stack.getId())
|
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:
|
else:
|
||||||
extruder_stack.setQualityChangesById("empty_quality_changes")
|
extruder_stack.setQualityChangesById("empty_quality_changes")
|
||||||
|
|
||||||
self.addContainer(extruder_stack)
|
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
|
# Set next stack at the end
|
||||||
extruder_stack.setNextStack(machine)
|
extruder_stack.setNextStack(machine)
|
||||||
|
|
||||||
|
@ -562,6 +643,9 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
if parser["general"]["name"] == name:
|
if parser["general"]["name"] == name:
|
||||||
# load the container
|
# load the container
|
||||||
container_id = os.path.basename(file_path).replace(".inst.cfg", "")
|
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)
|
instance_container = InstanceContainer(container_id)
|
||||||
with open(file_path, "r") as f:
|
with open(file_path, "r") as f:
|
||||||
|
|
|
@ -205,8 +205,8 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
Logger.log("d", " ## Process layers job still busy, trying later")
|
Logger.log("d", " ## Process layers job still busy, trying later")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not hasattr(self._scene, "gcode_list"):
|
if not hasattr(self._scene, "gcode_dict"):
|
||||||
self._scene.gcode_list = {}
|
self._scene.gcode_dict = {}
|
||||||
|
|
||||||
# see if we really have to slice
|
# see if we really have to slice
|
||||||
active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate
|
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)
|
Logger.log("d", "Going to slice build plate [%s]!" % build_plate_to_be_sliced)
|
||||||
num_objects = self._numObjects()
|
num_objects = self._numObjects()
|
||||||
if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0:
|
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] = []
|
self._scene.gcode_dict[build_plate_to_be_sliced] = []
|
||||||
Logger.log("d", "Build plate %s has 0 objects to be sliced, skipping", 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
|
return
|
||||||
|
|
||||||
self._stored_layer_data = []
|
self._stored_layer_data = []
|
||||||
|
@ -232,10 +234,12 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self.processingProgress.emit(0.0)
|
self.processingProgress.emit(0.0)
|
||||||
self.backendStateChange.emit(BackendState.NotStarted)
|
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._slicing = True
|
||||||
self.slicingStarted.emit()
|
self.slicingStarted.emit()
|
||||||
|
|
||||||
|
self.determineAutoSlicing() # Switch timer on or off if appropriate
|
||||||
|
|
||||||
slice_message = self._socket.createMessage("cura.proto.Slice")
|
slice_message = self._socket.createMessage("cura.proto.Slice")
|
||||||
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
|
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
|
||||||
self._start_slice_job_build_plate = build_plate_to_be_sliced
|
self._start_slice_job_build_plate = build_plate_to_be_sliced
|
||||||
|
@ -391,7 +395,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self.backendStateChange.emit(BackendState.Disabled)
|
self.backendStateChange.emit(BackendState.Disabled)
|
||||||
gcode_list = node.callDecoration("getGCodeList")
|
gcode_list = node.callDecoration("getGCodeList")
|
||||||
if gcode_list is not None:
|
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:
|
if self._use_timer == enable_timer:
|
||||||
return self._use_timer
|
return self._use_timer
|
||||||
|
@ -456,6 +460,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
for build_plate_number in build_plate_changed:
|
for build_plate_number in build_plate_changed:
|
||||||
if build_plate_number not in self._build_plates_to_be_sliced:
|
if build_plate_number not in self._build_plates_to_be_sliced:
|
||||||
self._build_plates_to_be_sliced.append(build_plate_number)
|
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||||
|
self.printDurationMessage.emit(source_build_plate_number, {}, [])
|
||||||
self.processingProgress.emit(0.0)
|
self.processingProgress.emit(0.0)
|
||||||
self.backendStateChange.emit(BackendState.NotStarted)
|
self.backendStateChange.emit(BackendState.NotStarted)
|
||||||
# if not self._use_timer:
|
# if not self._use_timer:
|
||||||
|
@ -518,7 +523,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
|
|
||||||
def _onStackErrorCheckFinished(self):
|
def _onStackErrorCheckFinished(self):
|
||||||
self._is_error_check_scheduled = False
|
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.needsSlicing()
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
|
|
||||||
|
@ -558,7 +563,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self.backendStateChange.emit(BackendState.Done)
|
self.backendStateChange.emit(BackendState.Done)
|
||||||
self.processingProgress.emit(1.0)
|
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):
|
for index, line in enumerate(gcode_list):
|
||||||
replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)))
|
replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)))
|
||||||
replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths))
|
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...")
|
Logger.log("d", "See if there is more to slice...")
|
||||||
# Somehow this results in an Arcus Error
|
# Somehow this results in an Arcus Error
|
||||||
# self.slice()
|
# self.slice()
|
||||||
# Testing call slice again, allow backend to restart by using the timer
|
# Call slice again using the timer, allowing the backend to restart
|
||||||
self._invokeSlice()
|
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.
|
## Called when a g-code message is received from the engine.
|
||||||
#
|
#
|
||||||
# \param message The protobuf message containing g-code, encoded as UTF-8.
|
# \param message The protobuf message containing g-code, encoded as UTF-8.
|
||||||
def _onGCodeLayerMessage(self, message):
|
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.
|
## Called when a g-code prefix message is received from the engine.
|
||||||
#
|
#
|
||||||
# \param message The protobuf message containing the g-code prefix,
|
# \param message The protobuf message containing the g-code prefix,
|
||||||
# encoded as UTF-8.
|
# encoded as UTF-8.
|
||||||
def _onGCodePrefixMessage(self, message):
|
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.
|
## Creates a new socket connection.
|
||||||
def _createSocket(self):
|
def _createSocket(self):
|
||||||
|
|
|
@ -12,4 +12,6 @@ class ProcessGCodeLayerJob(Job):
|
||||||
self._message = message
|
self._message = message
|
||||||
|
|
||||||
def run(self):
|
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"))
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
from UM.Scene.SceneNode import SceneNode
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Mesh.MeshData import MeshData
|
from UM.Mesh.MeshData import MeshData
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
|
@ -17,6 +16,7 @@ from UM.Logger import Logger
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
|
|
||||||
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
|
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from cura import LayerDataBuilder
|
from cura import LayerDataBuilder
|
||||||
from cura import LayerDataDecorator
|
from cura import LayerDataDecorator
|
||||||
|
@ -81,7 +81,7 @@ class ProcessSlicedLayersJob(Job):
|
||||||
|
|
||||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||||
|
|
||||||
new_node = SceneNode()
|
new_node = CuraSceneNode()
|
||||||
new_node.addDecorator(BuildPlateDecorator(self._build_plate_number))
|
new_node.addDecorator(BuildPlateDecorator(self._build_plate_number))
|
||||||
|
|
||||||
# Force garbage collection.
|
# Force garbage collection.
|
||||||
|
|
|
@ -8,14 +8,14 @@ from UM.Logger import Logger
|
||||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
from cura import LayerDataBuilder
|
from cura import LayerDataBuilder
|
||||||
from cura import LayerDataDecorator
|
from cura.LayerDataDecorator import LayerDataDecorator
|
||||||
from cura.LayerPolygon import LayerPolygon
|
from cura.LayerPolygon import LayerPolygon
|
||||||
from cura.Scene.GCodeListDecorator import GCodeListDecorator
|
from cura.Scene.GCodeListDecorator import GCodeListDecorator
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
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
|
# We obtain the filament diameter from the selected printer to calculate line widths
|
||||||
self._filament_diameter = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value")
|
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
|
# Override getBoundingBox function of the sceneNode, as this node should return a bounding box, but there is no
|
||||||
# real data to calculate it from.
|
# real data to calculate it from.
|
||||||
scene_node.getBoundingBox = self._getNullBoundingBox
|
scene_node.getBoundingBox = self._getNullBoundingBox
|
||||||
|
@ -418,11 +418,17 @@ class FlavorParser:
|
||||||
self._layer_number += 1
|
self._layer_number += 1
|
||||||
current_path.clear()
|
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[0, :] = [0.0, 0.7, 0.9, 1.0]
|
||||||
material_color_map[1, :] = [0.7, 0.9, 0.0, 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)
|
layer_mesh = self._layer_data_builder.build(material_color_map)
|
||||||
decorator = LayerDataDecorator.LayerDataDecorator()
|
decorator = LayerDataDecorator()
|
||||||
decorator.setLayerData(layer_mesh)
|
decorator.setLayerData(layer_mesh)
|
||||||
scene_node.addDecorator(decorator)
|
scene_node.addDecorator(decorator)
|
||||||
|
|
||||||
|
@ -430,7 +436,10 @@ class FlavorParser:
|
||||||
gcode_list_decorator.setGCodeList(gcode_list)
|
gcode_list_decorator.setGCodeList(gcode_list)
|
||||||
scene_node.addDecorator(gcode_list_decorator)
|
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)
|
Logger.log("d", "Finished parsing %s" % file_name)
|
||||||
self._message.hide()
|
self._message.hide()
|
||||||
|
|
|
@ -61,8 +61,11 @@ class GCodeWriter(MeshWriter):
|
||||||
|
|
||||||
active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate
|
active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate
|
||||||
scene = Application.getInstance().getController().getScene()
|
scene = Application.getInstance().getController().getScene()
|
||||||
gcode_list = getattr(scene, "gcode_list")[active_build_plate]
|
gcode_dict = getattr(scene, "gcode_dict")
|
||||||
if gcode_list:
|
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:
|
for gcode in gcode_list:
|
||||||
stream.write(gcode)
|
stream.write(gcode)
|
||||||
# Serialise the current container stack and put it at the end of the file.
|
# Serialise the current container stack and put it at the end of the file.
|
||||||
|
|
|
@ -8,8 +8,9 @@ import Cura 1.0 as Cura
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
width: parent.width
|
// parent could be undefined as this component is not visible at all times
|
||||||
height: parent.height
|
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
|
// We show a nice overlay on the 3D viewer when the current output device has no monitor view
|
||||||
Rectangle
|
Rectangle
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
|
||||||
|
from UM.FlameProfiler import pyqtSlot
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
@ -22,6 +23,9 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand
|
||||||
self._node = None
|
self._node = None
|
||||||
self._stack = 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):
|
def setSelectedObjectId(self, id):
|
||||||
if id != self._selected_object_id:
|
if id != self._selected_object_id:
|
||||||
self._selected_object_id = id
|
self._selected_object_id = id
|
||||||
|
@ -36,6 +40,10 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand
|
||||||
def selectedObjectId(self):
|
def selectedObjectId(self):
|
||||||
return self._selected_object_id
|
return self._selected_object_id
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def addSkipResetSetting(self, setting_name):
|
||||||
|
self._skip_reset_setting_set.add(setting_name)
|
||||||
|
|
||||||
def setVisible(self, visible):
|
def setVisible(self, visible):
|
||||||
if not self._node:
|
if not self._node:
|
||||||
return
|
return
|
||||||
|
@ -50,6 +58,9 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand
|
||||||
|
|
||||||
# Remove all instances that are not in visibility list
|
# Remove all instances that are not in visibility list
|
||||||
for instance in all_instances:
|
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:
|
if instance.definition.key not in visible:
|
||||||
settings.removeInstance(instance.definition.key)
|
settings.removeInstance(instance.definition.key)
|
||||||
visibility_changed = True
|
visibility_changed = True
|
||||||
|
|
|
@ -18,6 +18,9 @@ Item {
|
||||||
width: childrenRect.width;
|
width: childrenRect.width;
|
||||||
height: childrenRect.height;
|
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
|
Column
|
||||||
{
|
{
|
||||||
id: items
|
id: items
|
||||||
|
@ -39,6 +42,13 @@ Item {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UM.SettingPropertyProvider
|
||||||
|
{
|
||||||
|
id: meshTypePropertyProvider
|
||||||
|
containerStackId: Cura.MachineManager.activeMachineId
|
||||||
|
watchedProperties: [ "enabled" ]
|
||||||
|
}
|
||||||
|
|
||||||
ComboBox
|
ComboBox
|
||||||
{
|
{
|
||||||
id: meshTypeSelection
|
id: meshTypeSelection
|
||||||
|
@ -49,36 +59,55 @@ Item {
|
||||||
model: ListModel
|
model: ListModel
|
||||||
{
|
{
|
||||||
id: meshTypeModel
|
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({
|
meshTypeModel.append({
|
||||||
type: "support_mesh",
|
type: "support_mesh",
|
||||||
text: catalog.i18nc("@label", "Print as support")
|
text: catalog.i18nc("@label", "Print as support")
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
meshTypePropertyProvider.key = "anti_overhang_mesh";
|
||||||
|
if(meshTypePropertyProvider.properties.enabled == "True")
|
||||||
|
{
|
||||||
meshTypeModel.append({
|
meshTypeModel.append({
|
||||||
type: "anti_overhang_mesh",
|
type: "anti_overhang_mesh",
|
||||||
text: catalog.i18nc("@label", "Don't support overlap with other models")
|
text: catalog.i18nc("@label", "Don't support overlap with other models")
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
meshTypePropertyProvider.key = "cutting_mesh";
|
||||||
|
if(meshTypePropertyProvider.properties.enabled == "True")
|
||||||
|
{
|
||||||
meshTypeModel.append({
|
meshTypeModel.append({
|
||||||
type: "cutting_mesh",
|
type: "cutting_mesh",
|
||||||
text: catalog.i18nc("@label", "Modify settings for overlap with other models")
|
text: catalog.i18nc("@label", "Modify settings for overlap with other models")
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
meshTypePropertyProvider.key = "infill_mesh";
|
||||||
|
if(meshTypePropertyProvider.properties.enabled == "True")
|
||||||
|
{
|
||||||
meshTypeModel.append({
|
meshTypeModel.append({
|
||||||
type: "infill_mesh",
|
type: "infill_mesh",
|
||||||
text: catalog.i18nc("@label", "Modify settings for infill of other models")
|
text: catalog.i18nc("@label", "Modify settings for infill of other models")
|
||||||
});
|
});
|
||||||
|
|
||||||
meshTypeSelection.updateCurrentIndex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meshTypeSelection.updateCurrentIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCurrentIndex()
|
function updateCurrentIndex()
|
||||||
{
|
{
|
||||||
var mesh_type = UM.ActiveTool.properties.getValue("MeshType");
|
var mesh_type = UM.ActiveTool.properties.getValue("MeshType");
|
||||||
|
meshTypeSelection.currentIndex = -1;
|
||||||
for(var index=0; index < meshTypeSelection.model.count; index++)
|
for(var index=0; index < meshTypeSelection.model.count; index++)
|
||||||
{
|
{
|
||||||
if(meshTypeSelection.model.get(index).type == mesh_type)
|
if(meshTypeSelection.model.get(index).type == mesh_type)
|
||||||
|
@ -91,6 +120,16 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Cura.MachineManager
|
||||||
|
onGlobalContainerChanged:
|
||||||
|
{
|
||||||
|
meshTypeSelection.model.clear();
|
||||||
|
meshTypeSelection.populateModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: UM.Selection
|
target: UM.Selection
|
||||||
|
@ -106,7 +145,7 @@ Item {
|
||||||
id: currentSettings
|
id: currentSettings
|
||||||
property int maximumHeight: 200 * screenScaleFactor
|
property int maximumHeight: 200 * screenScaleFactor
|
||||||
height: Math.min(contents.count * (UM.Theme.getSize("section").height + UM.Theme.getSize("default_lining").height), maximumHeight)
|
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
|
ScrollView
|
||||||
{
|
{
|
||||||
|
@ -124,7 +163,15 @@ Item {
|
||||||
id: addedSettingsModel;
|
id: addedSettingsModel;
|
||||||
containerId: Cura.MachineManager.activeDefinitionId
|
containerId: Cura.MachineManager.activeDefinitionId
|
||||||
expanded: [ "*" ]
|
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
|
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
|
id: settingPickDialog
|
||||||
|
|
||||||
title: catalog.i18nc("@title:window", "Select Settings to Customize for this model")
|
title: catalog.i18nc("@title:window", "Select Settings to Customize for this model")
|
||||||
width: screenScaleFactor * 360;
|
width: screenScaleFactor * 360
|
||||||
|
|
||||||
property string labelFilter: ""
|
property string labelFilter: ""
|
||||||
|
property var additional_excluded_settings
|
||||||
|
|
||||||
onVisibilityChanged:
|
onVisibilityChanged:
|
||||||
{
|
{
|
||||||
// force updating the model to sync it with addedSettingsModel
|
// force updating the model to sync it with addedSettingsModel
|
||||||
if(visible)
|
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()
|
listview.model.forceUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +455,12 @@ Item {
|
||||||
}
|
}
|
||||||
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
|
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
|
||||||
expanded: [ "*" ]
|
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
|
delegate:Loader
|
||||||
{
|
{
|
||||||
|
|
206
plugins/PostProcessingPlugin/PostProcessingPlugin.py
Normal file
206
plugins/PostProcessingPlugin/PostProcessingPlugin.py
Normal file
|
@ -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")
|
||||||
|
|
||||||
|
|
501
plugins/PostProcessingPlugin/PostProcessingPlugin.qml
Normal file
501
plugins/PostProcessingPlugin/PostProcessingPlugin.qml
Normal file
|
@ -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{ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
plugins/PostProcessingPlugin/README.md
Normal file
2
plugins/PostProcessingPlugin/README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# PostProcessingPlugin
|
||||||
|
A post processing plugin for Cura
|
111
plugins/PostProcessingPlugin/Script.py
Normal file
111
plugins/PostProcessingPlugin/Script.py
Normal file
|
@ -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()
|
11
plugins/PostProcessingPlugin/__init__.py
Normal file
11
plugins/PostProcessingPlugin/__init__.py
Normal file
|
@ -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()}
|
8
plugins/PostProcessingPlugin/plugin.json
Normal file
8
plugins/PostProcessingPlugin/plugin.json
Normal file
|
@ -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"
|
||||||
|
}
|
47
plugins/PostProcessingPlugin/postprocessing.svg
Normal file
47
plugins/PostProcessingPlugin/postprocessing.svg
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="512px"
|
||||||
|
height="512px"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
style="enable-background:new 0 0 512 512;"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="postprocessing.svg"><metadata
|
||||||
|
id="metadata9"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs7" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1104"
|
||||||
|
inkscape:window-height="1006"
|
||||||
|
id="namedview5"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.3359375"
|
||||||
|
inkscape:cx="256"
|
||||||
|
inkscape:cy="256"
|
||||||
|
inkscape:window-x="701"
|
||||||
|
inkscape:window-y="121"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" /><path
|
||||||
|
d="M 402.15234 0 C 371.74552 4.7369516e-015 345.79114 10.752017 324.21875 32.324219 C 302.57788 53.89652 291.82617 79.851497 291.82617 110.18945 C 291.82617 127.34315 295.26662 143.09419 302.16602 157.44531 L 238.38477 221.20312 C 227.77569 210.95036 218.04331 201.50935 209.66016 193.32422 C 207.33386 190.99792 202.68042 189.48707 198.60938 191.92969 L 191.74609 196.11719 C 165.34252 169.24836 154.17609 158.42965 150.57031 145.40234 C 146.84822 131.79345 150.22148 113.64862 153.71094 106.90234 C 156.61882 101.55183 165.69233 96.550326 173.36914 95.96875 L 183.37109 106.20508 C 185.69739 108.53139 189.30456 108.53139 191.63086 106.20508 L 227.57227 69.681641 C 229.89858 67.355335 229.89858 63.517712 227.57227 61.191406 L 169.53125 2.21875 C 167.20494 -0.10755598 163.48147 -0.10755598 161.27148 2.21875 L 125.33008 38.742188 C 123.00378 41.068494 123.00378 44.906116 125.33008 47.232422 L 129.16992 51.1875 C 129.16992 56.88695 128.35573 65.727167 123.70312 70.496094 C 116.49157 77.823958 102.18413 69.332919 92.878906 75.962891 C 83.689998 82.476548 72.05746 92.944493 64.613281 100.38867 C 57.285417 107.83285 29.138171 137.37722 9.015625 187.16016 C -11.106922 236.94311 4.3632369 283.12 15.296875 295.2168 C 21.11264 301.61414 31.696982 308.12804 29.835938 296.03125 C 27.974892 283.81815 24.951448 241.47942 38.792969 224.14844 C 52.634489 206.81746 70.894726 192.62799 94.623047 191.46484 C 117.42084 190.30169 130.56529 198.09417 160.10938 228.10352 L 156.85156 234.15234 C 154.75788 238.10706 155.92175 243.10728 158.24805 245.43359 C 161.95717 248.74082 172.37305 258.96006 186.52539 273.04297 L 6.9511719 452.54883 C 2.2984329 457.14417 1.1842379e-015 462.71497 0 469.14844 C -1.1842379e-015 475.69681 2.2984329 481.15473 6.9511719 485.51953 L 26.308594 505.22266 C 31.018838 509.76054 36.589603 512 42.908203 512 C 49.341623 512 54.800053 509.76054 59.337891 505.22266 L 238.96875 325.6582 C 317.6609 404.95524 424.21289 513.40234 424.21289 513.40234 L 482.25391 454.43164 C 437.71428 411.9686 358.71135 336.76293 291.93164 272.71484 L 354.68945 209.98047 C 369.08663 216.91399 384.90203 220.37891 402.15234 220.37891 C 425.29988 220.37891 446.52947 213.53073 465.77344 199.83398 C 485.08493 186.1372 498.57775 168.33291 506.31641 146.34961 C 510.08303 135.39222 512 126.69334 512 120.25586 C 512 117.79044 511.24662 115.80572 509.87695 114.16211 C 508.50726 112.5185 506.59041 111.69531 504.125 111.69531 C 502.61835 111.69531 496.86414 114.5734 486.72852 120.39453 C 476.6614 126.21564 465.50054 132.85752 453.37891 140.32227 C 441.18878 147.78698 434.7515 151.75888 433.92969 152.23828 L 386.40234 125.94141 L 386.40234 70.8125 L 458.51562 29.242188 C 461.18649 27.461587 462.48633 25.202356 462.48633 22.394531 C 462.48633 19.586706 461.1865 17.325625 458.51562 15.476562 C 451.32484 10.545729 442.4896 6.780346 432.08008 4.0410156 C 421.60206 1.3701797 411.67159 0 402.15234 0 z "
|
||||||
|
id="path3" /></svg>
|
After Width: | Height: | Size: 4.4 KiB |
48
plugins/PostProcessingPlugin/scripts/BQ_PauseAtHeight.py
Normal file
48
plugins/PostProcessingPlugin/scripts/BQ_PauseAtHeight.py
Normal file
|
@ -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
|
76
plugins/PostProcessingPlugin/scripts/ColorChange.py
Normal file
76
plugins/PostProcessingPlugin/scripts/ColorChange.py
Normal file
|
@ -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
|
43
plugins/PostProcessingPlugin/scripts/ExampleScript.py
Normal file
43
plugins/PostProcessingPlugin/scripts/ExampleScript.py
Normal file
|
@ -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
|
221
plugins/PostProcessingPlugin/scripts/PauseAtHeight.py
Normal file
221
plugins/PostProcessingPlugin/scripts/PauseAtHeight.py
Normal file
|
@ -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: <current_height> = <current_z> - <layer_0_z>
|
||||||
|
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
|
169
plugins/PostProcessingPlugin/scripts/PauseAtHeightforRepetier.py
Normal file
169
plugins/PostProcessingPlugin/scripts/PauseAtHeightforRepetier.py
Normal file
|
@ -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
|
56
plugins/PostProcessingPlugin/scripts/SearchAndReplace.py
Normal file
56
plugins/PostProcessingPlugin/scripts/SearchAndReplace.py
Normal file
|
@ -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
|
469
plugins/PostProcessingPlugin/scripts/Stretch.py
Normal file
469
plugins/PostProcessingPlugin/scripts/Stretch.py
Normal file
|
@ -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)
|
||||||
|
|
495
plugins/PostProcessingPlugin/scripts/TweakAtZ.py
Normal file
495
plugins/PostProcessingPlugin/scripts/TweakAtZ.py
Normal file
|
@ -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<factor in percent> - set speed factor override percentage
|
||||||
|
## M221 S<factor in percent> - set flow factor override percentage
|
||||||
|
## M221 S<factor in percent> T<0-#toolheads> - set flow factor override percentage for single extruder
|
||||||
|
## M104 S<temp> T<0-#toolheads> - set extruder <T> to target temperature <S>
|
||||||
|
## M140 S<temp> - set bed target temperature
|
||||||
|
## M106 S<PWM> - set fan speed to target speed <S>
|
||||||
|
## 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
|
|
@ -106,7 +106,7 @@ class SimulationPass(RenderPass):
|
||||||
nozzle_node = node
|
nozzle_node = node
|
||||||
nozzle_node.setVisible(False)
|
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")
|
layer_data = node.callDecoration("getLayerData")
|
||||||
if not layer_data:
|
if not layer_data:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -104,7 +104,7 @@ class SimulationView(View):
|
||||||
title = catalog.i18nc("@info:title", "Simulation View"))
|
title = catalog.i18nc("@info:title", "Simulation View"))
|
||||||
|
|
||||||
def _resetSettings(self):
|
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_count = 0
|
||||||
self._extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
self._extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
||||||
self._show_travel_moves = 0
|
self._show_travel_moves = 0
|
||||||
|
|
|
@ -176,7 +176,6 @@ Item
|
||||||
viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
|
viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
|
||||||
viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
|
viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label
|
Label
|
||||||
|
|
|
@ -28,6 +28,7 @@ class SolidView(View):
|
||||||
self._enabled_shader = None
|
self._enabled_shader = None
|
||||||
self._disabled_shader = None
|
self._disabled_shader = None
|
||||||
self._non_printing_shader = None
|
self._non_printing_shader = None
|
||||||
|
self._support_mesh_shader = None
|
||||||
|
|
||||||
self._extruders_model = ExtrudersModel()
|
self._extruders_model = ExtrudersModel()
|
||||||
self._theme = None
|
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_diffuseColor", Color(*self._theme.getColor("model_non_printing").getRgb()))
|
||||||
self._non_printing_shader.setUniformValue("u_opacity", 0.6)
|
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()
|
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
if global_container_stack:
|
if global_container_stack:
|
||||||
support_extruder_nr = global_container_stack.getProperty("support_extruder_nr", "value")
|
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)
|
renderer.queueNode(node, shader = self._non_printing_shader, transparent = True)
|
||||||
elif getattr(node, "_outside_buildarea", False):
|
elif getattr(node, "_outside_buildarea", False):
|
||||||
renderer.queueNode(node, shader = self._disabled_shader)
|
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:
|
else:
|
||||||
renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
|
renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
|
||||||
if node.callDecoration("isGroup") and Selection.isSelected(node):
|
if node.callDecoration("isGroup") and Selection.isSelected(node):
|
||||||
|
|
|
@ -115,7 +115,6 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
|
||||||
self._not_authenticated_message.hide()
|
self._not_authenticated_message.hide()
|
||||||
|
|
||||||
self._requestAuthentication()
|
self._requestAuthentication()
|
||||||
pass # Cura Connect doesn't do any authorization
|
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
super().connect()
|
super().connect()
|
||||||
|
|
|
@ -96,9 +96,12 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||||
|
|
||||||
Application.getInstance().getController().setActiveStage("MonitorStage")
|
Application.getInstance().getController().setActiveStage("MonitorStage")
|
||||||
|
|
||||||
gcode_list = getattr(Application.getInstance().getController().getScene(), "gcode_list")
|
# find the G-code for the active build plate to print
|
||||||
self._printGCode(gcode_list)
|
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.
|
## Show firmware interface.
|
||||||
# This will create the view if its not already created.
|
# This will create the view if its not already created.
|
||||||
|
|
|
@ -3633,7 +3633,7 @@
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "100",
|
"maximum_value_warning": "100",
|
||||||
"default_value": 15,
|
"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",
|
"enabled": "support_enable or support_tree_enable",
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
@ -4233,6 +4233,18 @@
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"enabled": "support_enable and support_use_towers",
|
"enabled": "support_enable and support_use_towers",
|
||||||
"settable_per_mesh": true
|
"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_per_meshgroup": false,
|
||||||
"settable_globally": 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":
|
"anti_overhang_mesh":
|
||||||
{
|
{
|
||||||
"label": "Anti Overhang Mesh",
|
"label": "Anti Overhang Mesh",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"id": "malyan_m180",
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"name": "Malyan M180",
|
"name": "Malyan M180",
|
||||||
"inherits": "fdmprinter",
|
"inherits": "fdmprinter",
|
85
resources/definitions/malyan_m200.def.json
Normal file
85
resources/definitions/malyan_m200.def.json
Normal file
|
@ -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}
|
||||||
|
}
|
||||||
|
}
|
18
resources/definitions/monoprice_select_mini_v1.def.json
Normal file
18
resources/definitions/monoprice_select_mini_v1.def.json
Normal file
|
@ -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" }
|
||||||
|
}
|
||||||
|
}
|
25
resources/definitions/monoprice_select_mini_v2.def.json
Normal file
25
resources/definitions/monoprice_select_mini_v2.def.json
Normal file
|
@ -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" }
|
||||||
|
}
|
||||||
|
}
|
BIN
resources/meshes/malyan_m200_platform.stl
Normal file
BIN
resources/meshes/malyan_m200_platform.stl
Normal file
Binary file not shown.
|
@ -47,6 +47,7 @@ Menu
|
||||||
{
|
{
|
||||||
model: Cura.BuildPlateModel
|
model: Cura.BuildPlateModel
|
||||||
MenuItem {
|
MenuItem {
|
||||||
|
enabled: UM.Selection.hasSelection
|
||||||
text: Cura.BuildPlateModel.getItem(index).name;
|
text: Cura.BuildPlateModel.getItem(index).name;
|
||||||
onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.getItem(index).buildPlateNumber);
|
onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.getItem(index).buildPlateNumber);
|
||||||
checkable: true
|
checkable: true
|
||||||
|
@ -58,6 +59,7 @@ Menu
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
|
enabled: UM.Selection.hasSelection
|
||||||
text: "New build plate";
|
text: "New build plate";
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.maxBuildPlate + 1);
|
CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.maxBuildPlate + 1);
|
||||||
|
|
|
@ -105,7 +105,6 @@ Rectangle
|
||||||
topMargin: UM.Theme.getSize("default_margin").height;
|
topMargin: UM.Theme.getSize("default_margin").height;
|
||||||
left: parent.left;
|
left: parent.left;
|
||||||
leftMargin: UM.Theme.getSize("default_margin").height;
|
leftMargin: UM.Theme.getSize("default_margin").height;
|
||||||
//bottom: objectsList.top;
|
|
||||||
bottomMargin: UM.Theme.getSize("default_margin").height;
|
bottomMargin: UM.Theme.getSize("default_margin").height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@ Rectangle
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||||
width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30
|
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)
|
color: Cura.ObjectsModel.getItem(index).isSelected ? palette.highlightedText : (Cura.ObjectsModel.getItem(index).isOutsideBuildArea ? palette.mid : palette.text)
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,34 +453,6 @@ UM.PreferencesPage
|
||||||
text: catalog.i18nc("@label","Opening and saving files")
|
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 {
|
UM.TooltipArea {
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
@ -688,6 +660,49 @@ UM.PreferencesPage
|
||||||
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,14 +104,13 @@ TabView
|
||||||
|
|
||||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
|
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
|
||||||
|
|
||||||
Row
|
Row {
|
||||||
{
|
width: scrollView.columnWidth
|
||||||
width: scrollView.columnWidth;
|
height: parent.rowHeight
|
||||||
height: parent.rowHeight;
|
|
||||||
spacing: Math.floor(UM.Theme.getSize("default_margin").width/2)
|
spacing: Math.floor(UM.Theme.getSize("default_margin").width/2)
|
||||||
|
|
||||||
Rectangle
|
// color indicator square
|
||||||
{
|
Rectangle {
|
||||||
id: colorSelector
|
id: colorSelector
|
||||||
color: properties.color_code
|
color: properties.color_code
|
||||||
|
|
||||||
|
@ -121,17 +120,36 @@ TabView
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
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;
|
id: colorLabel;
|
||||||
text: properties.color_name;
|
text: properties.color_name;
|
||||||
readOnly: !base.editingEnabled
|
readOnly: !base.editingEnabled
|
||||||
onEditingFinished: base.setMetaDataEntry("color_name", properties.color_name, text)
|
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 }
|
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.
|
// Tiny convenience function to check if a value really changed before trying to set it.
|
||||||
function setMetaDataEntry(entry_name, old_value, new_value)
|
function setMetaDataEntry(entry_name, old_value, new_value) {
|
||||||
{
|
if (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
|
||||||
Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, entry_name, new_value);
|
properties[entry_name] = new_value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,93 +132,82 @@ UM.ManagementPage
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons: [
|
buttons: [
|
||||||
Button
|
|
||||||
{
|
// Activate button
|
||||||
text: catalog.i18nc("@action:button", "Activate");
|
Button {
|
||||||
|
text: catalog.i18nc("@action:button", "Activate")
|
||||||
iconName: "list-activate";
|
iconName: "list-activate";
|
||||||
enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId && Cura.MachineManager.hasMaterials
|
enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId && Cura.MachineManager.hasMaterials
|
||||||
onClicked:
|
onClicked: {
|
||||||
{
|
forceActiveFocus()
|
||||||
forceActiveFocus();
|
|
||||||
Cura.MachineManager.setActiveMaterial(base.currentItem.id)
|
Cura.MachineManager.setActiveMaterial(base.currentItem.id)
|
||||||
currentItem = base.model.getItem(base.objectList.currentIndex) // Refresh the current item.
|
currentItem = base.model.getItem(base.objectList.currentIndex) // Refresh the current item.
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Button
|
|
||||||
{
|
// Create button
|
||||||
|
Button {
|
||||||
text: catalog.i18nc("@action:button", "Create")
|
text: catalog.i18nc("@action:button", "Create")
|
||||||
iconName: "list-add"
|
iconName: "list-add"
|
||||||
onClicked:
|
onClicked: {
|
||||||
|
forceActiveFocus()
|
||||||
|
Cura.ContainerManager.createMaterial()
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections
|
||||||
{
|
{
|
||||||
forceActiveFocus();
|
target: base.objectList.model
|
||||||
var material_id = Cura.ContainerManager.createMaterial()
|
onItemsChanged:
|
||||||
if(material_id == "")
|
|
||||||
{
|
{
|
||||||
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");
|
text: catalog.i18nc("@action:button", "Duplicate");
|
||||||
iconName: "list-add";
|
iconName: "list-add";
|
||||||
enabled: base.currentItem != null
|
enabled: base.currentItem != null
|
||||||
onClicked:
|
onClicked: {
|
||||||
{
|
forceActiveFocus()
|
||||||
forceActiveFocus();
|
Cura.ContainerManager.duplicateOriginalMaterial(base.currentItem.id)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Button
|
|
||||||
{
|
// Remove button
|
||||||
text: catalog.i18nc("@action:button", "Remove");
|
Button {
|
||||||
iconName: "list-remove";
|
text: catalog.i18nc("@action:button", "Remove")
|
||||||
|
iconName: "list-remove"
|
||||||
enabled: base.currentItem != null && !base.currentItem.readOnly && !Cura.ContainerManager.isContainerUsed(base.currentItem.id)
|
enabled: base.currentItem != null && !base.currentItem.readOnly && !Cura.ContainerManager.isContainerUsed(base.currentItem.id)
|
||||||
onClicked:
|
onClicked: {
|
||||||
{
|
forceActiveFocus()
|
||||||
forceActiveFocus();
|
confirmDialog.open()
|
||||||
confirmDialog.open();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Button
|
|
||||||
{
|
// Import button
|
||||||
text: catalog.i18nc("@action:button", "Import");
|
Button {
|
||||||
iconName: "document-import";
|
text: catalog.i18nc("@action:button", "Import")
|
||||||
onClicked:
|
iconName: "document-import"
|
||||||
{
|
onClicked: {
|
||||||
forceActiveFocus();
|
forceActiveFocus()
|
||||||
importDialog.open();
|
importDialog.open()
|
||||||
}
|
}
|
||||||
visible: true;
|
visible: true
|
||||||
},
|
},
|
||||||
Button
|
|
||||||
{
|
// Export button
|
||||||
|
Button {
|
||||||
text: catalog.i18nc("@action:button", "Export")
|
text: catalog.i18nc("@action:button", "Export")
|
||||||
iconName: "document-export"
|
iconName: "document-export"
|
||||||
onClicked:
|
onClicked: {
|
||||||
{
|
forceActiveFocus()
|
||||||
forceActiveFocus();
|
exportDialog.open()
|
||||||
exportDialog.open();
|
|
||||||
}
|
}
|
||||||
enabled: currentItem != null
|
enabled: currentItem != null
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
|
@ -195,11 +195,22 @@ Item
|
||||||
text:
|
text:
|
||||||
{
|
{
|
||||||
var result = ""
|
var result = ""
|
||||||
if (Cura.MachineManager.activeMachine != null) {
|
if(Cura.MachineManager.activeMachine != null)
|
||||||
|
{
|
||||||
result = Cura.ProfilesModel.getItem(index).layer_height_without_unit
|
result = Cura.ProfilesModel.getItem(index).layer_height_without_unit
|
||||||
|
|
||||||
if (result == undefined)
|
if(result == undefined)
|
||||||
result = ""
|
{
|
||||||
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg
Normal file
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg
Normal file
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg
Normal file
|
@ -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
|
23
resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg
Normal file
23
resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg
Normal file
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg
Normal file
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg
Normal file
|
@ -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
|
22
resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg
Normal file
22
resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg
Normal file
|
@ -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
|
23
resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg
Normal file
23
resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue