mirror of
https://github.com/Ultimaker/Cura.git
synced 2026-03-05 18:14:38 -07:00
Merge branch 'main' into CURA-12814
Some checks failed
conan-package / conan-package (push) Waiting to run
unit-test / Run unit tests (push) Waiting to run
conan-package-resources / conan-package (push) Has been cancelled
printer-linter-format / Printer linter auto format (push) Has been cancelled
conan-package-resources / signal-curator (push) Has been cancelled
Some checks failed
conan-package / conan-package (push) Waiting to run
unit-test / Run unit tests (push) Waiting to run
conan-package-resources / conan-package (push) Has been cancelled
printer-linter-format / Printer linter auto format (push) Has been cancelled
conan-package-resources / signal-curator (push) Has been cancelled
This commit is contained in:
commit
e5facbe5cc
8243 changed files with 9893 additions and 8442 deletions
|
|
@ -140,7 +140,7 @@ class CuraApplication(QtApplication):
|
|||
# SettingVersion represents the set of settings available in the machine/extruder definitions.
|
||||
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
|
||||
# changes of the settings.
|
||||
SettingVersion = 25
|
||||
SettingVersion = 26
|
||||
|
||||
Created = False
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ class PaintTool(Tool):
|
|||
self._view: PaintView = view
|
||||
self._view.canUndoChanged.connect(self._onCanUndoChanged)
|
||||
self._view.canRedoChanged.connect(self._onCanRedoChanged)
|
||||
self._view.currentPaintedObjectMeshDataChanged.connect(self._updateState)
|
||||
|
||||
self._picking_pass: Optional[PickingPass] = None
|
||||
self._faces_selection_pass: Optional[SelectionPass] = None
|
||||
|
|
@ -198,40 +199,6 @@ class PaintTool(Tool):
|
|||
self._view.clearPaint()
|
||||
self._updateScene(update_node = True)
|
||||
|
||||
@staticmethod
|
||||
def _get_intersect_ratio_via_pt(a: numpy.ndarray, pt: numpy.ndarray, b: numpy.ndarray, c: numpy.ndarray) -> float:
|
||||
# compute the intersection of (param) A - pt with (param) B - (param) C
|
||||
if all(a == pt) or all(b == c) or all(a == c) or all(a == b):
|
||||
return 1.0
|
||||
|
||||
# compute unit vectors of directions of lines A and B
|
||||
udir_a = a - pt
|
||||
udir_a /= numpy.linalg.norm(udir_a)
|
||||
udir_b = b - c
|
||||
udir_b /= numpy.linalg.norm(udir_b)
|
||||
|
||||
# find unit direction vector for line C, which is perpendicular to lines A and B
|
||||
udir_res = numpy.cross(udir_b, udir_a)
|
||||
udir_res_len = numpy.linalg.norm(udir_res)
|
||||
if udir_res_len == 0:
|
||||
return 1.0
|
||||
udir_res /= udir_res_len
|
||||
|
||||
# solve system of equations
|
||||
rhs = b - a
|
||||
lhs = numpy.array([udir_a, -udir_b, udir_res]).T
|
||||
try:
|
||||
solved = numpy.linalg.solve(lhs, rhs)
|
||||
except numpy.linalg.LinAlgError:
|
||||
return 1.0
|
||||
|
||||
# get the ratio
|
||||
intersect = ((a + solved[0] * udir_a) + (b + solved[1] * udir_b)) * 0.5
|
||||
a_intersect_dist = numpy.linalg.norm(a - intersect)
|
||||
if a_intersect_dist == 0:
|
||||
return 1.0
|
||||
return numpy.linalg.norm(pt - intersect) / a_intersect_dist
|
||||
|
||||
def _nodeTransformChanged(self, *args) -> None:
|
||||
self._cache_dirty = True
|
||||
|
||||
|
|
@ -453,7 +420,7 @@ class PaintTool(Tool):
|
|||
def _updateState(self):
|
||||
painted_object = self._view.getPaintedObject()
|
||||
if painted_object is not None and self._controller.getActiveTool() == self:
|
||||
if painted_object.callDecoration("getPaintTexture") is not None:
|
||||
if painted_object.callDecoration("getPaintTexture") is not None and painted_object.getMeshData().hasUVCoordinates():
|
||||
new_state = PaintTool.Paint.State.READY
|
||||
else:
|
||||
new_state = PaintTool.Paint.State.PREPARING_MODEL
|
||||
|
|
@ -472,6 +439,7 @@ class PaintTool(Tool):
|
|||
self._prepare_texture_job = None
|
||||
self._state = PaintTool.Paint.State.READY
|
||||
self.propertyChanged.emit()
|
||||
self._updateScene()
|
||||
|
||||
def _updateIgnoreUnselectedObjects(self):
|
||||
ignore_unselected_objects = self._controller.getActiveView().name == "PaintTool"
|
||||
|
|
|
|||
|
|
@ -61,11 +61,13 @@ class PaintView(CuraView):
|
|||
|
||||
canUndoChanged = pyqtSignal(bool)
|
||||
canRedoChanged = pyqtSignal(bool)
|
||||
currentPaintedObjectMeshDataChanged = pyqtSignal()
|
||||
|
||||
def setPaintedObject(self, painted_object: Optional[SceneNode]):
|
||||
if self._painted_object is not None:
|
||||
texture_changed_signal = self._painted_object.callDecoration("getPaintTextureChangedSignal")
|
||||
texture_changed_signal.disconnect(self._onCurrentPaintedObjectTextureChanged)
|
||||
self._painted_object.meshDataChanged.disconnect(self._onCurrentPaintedObjectMesDataChanged)
|
||||
|
||||
self._paint_texture = None
|
||||
self._cursor_texture = None
|
||||
|
|
@ -78,6 +80,7 @@ class PaintView(CuraView):
|
|||
if texture_changed_signal is not None:
|
||||
texture_changed_signal.connect(self._onCurrentPaintedObjectTextureChanged)
|
||||
self._onCurrentPaintedObjectTextureChanged()
|
||||
self._painted_object.meshDataChanged.connect(self._onCurrentPaintedObjectMesDataChanged)
|
||||
|
||||
self._updateCurrentBitsRanges()
|
||||
|
||||
|
|
@ -99,6 +102,10 @@ class PaintView(CuraView):
|
|||
else:
|
||||
self._cursor_texture = None
|
||||
|
||||
def _onCurrentPaintedObjectMesDataChanged(self, object: SceneNode) -> None:
|
||||
if object == self._painted_object:
|
||||
self.currentPaintedObjectMeshDataChanged.emit()
|
||||
|
||||
def canUndo(self):
|
||||
stack = self._getUndoStack()
|
||||
return stack.canUndo() if stack is not None else False
|
||||
|
|
|
|||
|
|
@ -39,6 +39,42 @@ UM.Dialog
|
|||
|
||||
anchors.fill: parent
|
||||
|
||||
// Helper function to check if a setting should use multiline text area
|
||||
// Supports "multiline" or "@[multiline]" or "@[multiline, other] comment"
|
||||
function isMultilineSetting(definition)
|
||||
{
|
||||
if (!definition || !definition.comments)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var commentsLower = definition.comments.toLowerCase();
|
||||
|
||||
// Simple format: exact match
|
||||
if (commentsLower === "multiline")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Directive format: parse @[...] and check if multiline is in the list
|
||||
var directiveStart = commentsLower.indexOf("@[");
|
||||
var directiveEnd = commentsLower.indexOf("]", directiveStart);
|
||||
if (directiveStart >= 0 && directiveEnd > directiveStart)
|
||||
{
|
||||
var directivesText = commentsLower.substring(directiveStart + 2, directiveEnd);
|
||||
var directives = directivesText.split(",");
|
||||
for (var i = 0; i < directives.length; i++)
|
||||
{
|
||||
if (directives[i].trim() === "multiline")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ButtonGroup
|
||||
{
|
||||
id: selectedScriptGroup
|
||||
|
|
@ -301,6 +337,10 @@ UM.Dialog
|
|||
{
|
||||
if (provider.properties.enabled == "True" && model.type != undefined)
|
||||
{
|
||||
if (definition && definition.comments && definition.comments.toLowerCase() === "multiline")
|
||||
{
|
||||
return UM.Theme.getSize("standard_list_lineheight").height + UM.Theme.getSize("narrow_margin").height + (UM.Theme.getSize("setting_control").height * 3);
|
||||
}
|
||||
return UM.Theme.getSize("section").height;
|
||||
}
|
||||
else
|
||||
|
|
@ -331,6 +371,19 @@ UM.Dialog
|
|||
settingLoader.item.showLinkedSettingIcon = false
|
||||
settingLoader.item.doDepthIndentation = false
|
||||
settingLoader.item.doQualityUserSettingEmphasis = false
|
||||
// Pass properties explicitly to custom components that don't extend SettingItem
|
||||
if (settingLoader.item.hasOwnProperty("definition")) {
|
||||
settingLoader.item.definition = settingLoader.definition
|
||||
}
|
||||
if (settingLoader.item.hasOwnProperty("settingDefinitionsModel")) {
|
||||
settingLoader.item.settingDefinitionsModel = settingLoader.settingDefinitionsModel
|
||||
}
|
||||
if (settingLoader.item.hasOwnProperty("propertyProvider")) {
|
||||
settingLoader.item.propertyProvider = settingLoader.propertyProvider
|
||||
}
|
||||
if (settingLoader.item.hasOwnProperty("globalPropertyProvider")) {
|
||||
settingLoader.item.globalPropertyProvider = settingLoader.globalPropertyProvider
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent:
|
||||
|
|
@ -348,7 +401,7 @@ UM.Dialog
|
|||
case "bool":
|
||||
return settingCheckBox
|
||||
case "str":
|
||||
return settingTextField
|
||||
return base.isMultilineSetting(definition) ? settingTextArea : settingTextField
|
||||
case "category":
|
||||
return settingCategory
|
||||
default:
|
||||
|
|
@ -405,6 +458,13 @@ UM.Dialog
|
|||
Cura.SettingTextField { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingTextArea;
|
||||
|
||||
SettingTextArea { }
|
||||
}
|
||||
|
||||
Component
|
||||
{
|
||||
id: settingComboBox;
|
||||
|
|
|
|||
108
plugins/PostProcessingPlugin/SettingTextArea.qml
Normal file
108
plugins/PostProcessingPlugin/SettingTextArea.qml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) 2025 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import UM 1.7 as UM
|
||||
|
||||
// Custom multiline text area component for post-processing script settings
|
||||
// Triggered when setting has "comments": "multiline" property
|
||||
Item
|
||||
{
|
||||
id: base
|
||||
|
||||
// Properties passed from the Loader
|
||||
property var definition
|
||||
property var settingDefinitionsModel
|
||||
property var propertyProvider
|
||||
property var globalPropertyProvider
|
||||
|
||||
// Standard setting item properties (required by loader but unused in this component)
|
||||
property bool showRevertButton: false
|
||||
property bool showInheritButton: false
|
||||
property bool showLinkedSettingIcon: false
|
||||
property bool doDepthIndentation: false
|
||||
property bool doQualityUserSettingEmphasis: false
|
||||
|
||||
// Internal state tracking (unused but kept for potential future use)
|
||||
property string textBeforeEdit
|
||||
property bool textHasChanged
|
||||
|
||||
// Signals for tooltip support (required by Connections in loader)
|
||||
// Note: These signals are declared but intentionally never emitted.
|
||||
// This prevents tooltips from appearing on mouse-over, which would obstruct the text area
|
||||
// while the user is typing or editing multiline content.
|
||||
signal showTooltip(string text)
|
||||
signal hideTooltip()
|
||||
|
||||
width: parent.width
|
||||
// Height calculation: label height + spacing + text area (3x normal height for multiline editing)
|
||||
height: UM.Theme.getSize("standard_list_lineheight").height + UM.Theme.getSize("narrow_margin").height + (UM.Theme.getSize("setting_control").height * 3)
|
||||
|
||||
UM.Label
|
||||
{
|
||||
id: labelText
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: UM.Theme.getSize("standard_list_lineheight").height
|
||||
text: definition ? definition.label : ""
|
||||
elide: Text.ElideRight
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
color: UM.Theme.getColor("text")
|
||||
}
|
||||
|
||||
Flickable
|
||||
{
|
||||
id: flickable
|
||||
anchors.top: labelText.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("narrow_margin").height
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
// Right margin to prevent overlap with parent ListView scrollbar
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width + UM.Theme.getSize("narrow_margin").width
|
||||
height: UM.Theme.getSize("setting_control").height * 3
|
||||
|
||||
clip: true
|
||||
ScrollBar.vertical: UM.ScrollBar { }
|
||||
|
||||
TextArea.flickable: TextArea
|
||||
{
|
||||
id: textArea
|
||||
|
||||
enabled: propertyProvider && propertyProvider.properties ? propertyProvider.properties.enabled === "True" : true
|
||||
// Explicit undefined check to prevent QML warnings about undefined QString assignment
|
||||
text: (propertyProvider && propertyProvider.properties && propertyProvider.properties.value !== undefined) ? propertyProvider.properties.value : ""
|
||||
|
||||
background: Rectangle
|
||||
{
|
||||
color: UM.Theme.getColor("setting_control")
|
||||
border.color: textArea.activeFocus ? UM.Theme.getColor("text_field_border_active") : UM.Theme.getColor("text_field_border")
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
}
|
||||
|
||||
onTextChanged:
|
||||
{
|
||||
// Save value on each keystroke when focused (live update)
|
||||
if (activeFocus && propertyProvider)
|
||||
{
|
||||
propertyProvider.setPropertyValue("value", text);
|
||||
}
|
||||
}
|
||||
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
selectionColor: UM.Theme.getColor("text_selection")
|
||||
selectedTextColor: UM.Theme.getColor("text")
|
||||
wrapMode: TextEdit.NoWrap
|
||||
selectByMouse: true
|
||||
|
||||
// Allow Enter/Return to insert newlines instead of closing dialog
|
||||
Keys.onReturnPressed: function(event) { event.accepted = false; }
|
||||
Keys.onEnterPressed: function(event) { event.accepted = false; }
|
||||
// Escape key removes focus from text area
|
||||
Keys.onEscapePressed: function(event) { focus = false; event.accepted = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Post Processing",
|
||||
"author": "Ultimaker",
|
||||
"version": "2.2.1",
|
||||
"version": "2.3.0",
|
||||
"api": 8,
|
||||
"description": "Extension that allows for user created scripts for post processing",
|
||||
"catalog": "cura"
|
||||
|
|
|
|||
|
|
@ -15,14 +15,20 @@ Designed in January 2023 by GregValiant (Greg Foresi)
|
|||
01/05/24 (GV) Revised the regex replacements.
|
||||
12/11/24 (GV) Added 'off_fan_speed' for the idle nozzle layer cooling fan. It does not have to go to 0%.
|
||||
03/22/25 (GV) Added 'Chamber Cooling Fan / Auxiliary Fan' control.
|
||||
12/26/25 (GV) Added 'Enable Script' setting so it can be left installed, but not run.
|
||||
12/26/25 (GV) Added 'Jump Start' option to get the fan spinning just before it is actually called.
|
||||
"""
|
||||
|
||||
from ..Script import Script
|
||||
from UM.Application import Application
|
||||
import re
|
||||
from UM.Logger import Logger
|
||||
|
||||
class AddCoolingProfile(Script):
|
||||
|
||||
jump_speed_marlin = 179 # ~70% of 255
|
||||
jump_speed_reprap = 0.70 # used if fan_scale_0_to_1 is true
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Advanced Cooling Fan Control",
|
||||
|
|
@ -31,6 +37,14 @@ class AddCoolingProfile(Script):
|
|||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"enable_cooling_profile":
|
||||
{
|
||||
"label": "Enable Advanced Cooling",
|
||||
"description": "Enable the script so it will run.",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"enabled": true
|
||||
},
|
||||
"fan_layer_or_feature":
|
||||
{
|
||||
"label": "Cooling Control by:",
|
||||
|
|
@ -39,14 +53,15 @@ class AddCoolingProfile(Script):
|
|||
"options": {
|
||||
"by_layer": "Layer Numbers",
|
||||
"by_feature": "Feature Types"},
|
||||
"default_value": "by_layer"
|
||||
"default_value": "by_layer",
|
||||
"enabled": "enable_cooling_profile"
|
||||
},
|
||||
"delete_existing_m106":
|
||||
{
|
||||
"label": "Remove M106 lines prior to inserting new.",
|
||||
"description": "If you have 2 or more instances of 'Advanced Cooling Fan Control' running (to cool a portion of a print differently), then you must uncheck this box or the followup instances will remove all the lines inserted by the first instance. Pay attention to the Start and Stop layers. Regardless of this setting: The script always removes M106 lines starting with the lowest layer number (when 'By Layer') or the starting layer number (when 'By Feature'). If you want to keep the M106 lines that Cura inserted up to the point where this post-processor will start making insertions, then un-check the box.",
|
||||
"type": "bool",
|
||||
"enabled": true,
|
||||
"enabled": "enable_cooling_profile",
|
||||
"default_value": true
|
||||
},
|
||||
"feature_fan_start_layer":
|
||||
|
|
@ -57,7 +72,7 @@ class AddCoolingProfile(Script):
|
|||
"default_value": 5,
|
||||
"minimum_value": 1,
|
||||
"unit": "Lay# ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_end_layer":
|
||||
{
|
||||
|
|
@ -67,7 +82,7 @@ class AddCoolingProfile(Script):
|
|||
"default_value": -1,
|
||||
"minimum_value": -1,
|
||||
"unit": "Lay# ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_1":
|
||||
{
|
||||
|
|
@ -76,7 +91,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "5/30",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_2":
|
||||
{
|
||||
|
|
@ -85,7 +100,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_3":
|
||||
{
|
||||
|
|
@ -94,7 +109,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_4":
|
||||
{
|
||||
|
|
@ -103,7 +118,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_5":
|
||||
{
|
||||
|
|
@ -112,7 +127,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_6":
|
||||
{
|
||||
|
|
@ -121,7 +136,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_7":
|
||||
{
|
||||
|
|
@ -130,7 +145,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"layer_fan_8":
|
||||
{
|
||||
|
|
@ -139,7 +154,7 @@ class AddCoolingProfile(Script):
|
|||
"type": "str",
|
||||
"default_value": "",
|
||||
"unit": "L#/% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_layer'"
|
||||
"enabled": "fan_layer_or_feature == 'by_layer' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_skirt":
|
||||
{
|
||||
|
|
@ -150,7 +165,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_wall_inner":
|
||||
{
|
||||
|
|
@ -161,7 +176,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_wall_outer":
|
||||
{
|
||||
|
|
@ -172,7 +187,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_fill":
|
||||
{
|
||||
|
|
@ -183,7 +198,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_skin":
|
||||
{
|
||||
|
|
@ -194,7 +209,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_support":
|
||||
{
|
||||
|
|
@ -205,7 +220,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_support_interface":
|
||||
{
|
||||
|
|
@ -216,7 +231,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_prime_tower":
|
||||
{
|
||||
|
|
@ -227,7 +242,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_bridge":
|
||||
{
|
||||
|
|
@ -238,14 +253,14 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'"
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
},
|
||||
"feature_fan_combing":
|
||||
{
|
||||
"label": "Fan 'OFF' during Combing:",
|
||||
"description": "When checked will set the fan to 0% for combing moves over 5 lines long in the gcode. When un-checked the fan speed during combing is whatever the previous speed is set to.",
|
||||
"type": "bool",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature'",
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile",
|
||||
"default_value": true
|
||||
},
|
||||
"feature_fan_feature_final":
|
||||
|
|
@ -257,7 +272,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "(int(feature_fan_end_layer) != -1) and (fan_layer_or_feature == 'by_feature')"
|
||||
"enabled": "(int(feature_fan_end_layer) != -1) and (fan_layer_or_feature == 'by_feature') and enable_cooling_profile"
|
||||
},
|
||||
"fan_enable_raft":
|
||||
{
|
||||
|
|
@ -265,7 +280,7 @@ class AddCoolingProfile(Script):
|
|||
"description": "Enable the fan for the raft layers. When enabled the Raft Fan Speed will continue until another Layer or Feature setting over-rides it.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": true
|
||||
"enabled": "enable_cooling_profile"
|
||||
},
|
||||
"fan_raft_percent":
|
||||
{
|
||||
|
|
@ -276,7 +291,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "fan_enable_raft"
|
||||
"enabled": "fan_enable_raft and enable_cooling_profile"
|
||||
},
|
||||
"enable_off_fan_speed_enable":
|
||||
{
|
||||
|
|
@ -292,7 +307,7 @@ class AddCoolingProfile(Script):
|
|||
"description": "For machines with independent layer cooling fans. Leaving a fan running while the other nozzle is printing can help with oozing. You can pick the speed % for the idle nozzle layer cooling fan to hold at.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "enable_off_fan_speed_enable"
|
||||
"enabled": "enable_off_fan_speed_enable and enable_cooling_profile"
|
||||
},
|
||||
"off_fan_speed":
|
||||
{
|
||||
|
|
@ -303,7 +318,7 @@ class AddCoolingProfile(Script):
|
|||
"minimum_value": 0,
|
||||
"maximum_value": 100,
|
||||
"unit": "% ",
|
||||
"enabled": "enable_off_fan_speed_enable and enable_off_fan_speed"
|
||||
"enabled": "enable_off_fan_speed_enable and enable_off_fan_speed and enable_cooling_profile"
|
||||
},
|
||||
"bv_fan_speed_control_enable":
|
||||
{
|
||||
|
|
@ -311,7 +326,7 @@ class AddCoolingProfile(Script):
|
|||
"description": "Controls the 'Build Volume Fan' or an 'Auxiliary Fan' on printers with that hardware. Provides: 'On' layer, 'Off' layer, and PWM speed control of a secondary fan.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "enable_bv_fan"
|
||||
"enabled": "enable_bv_fan and enable_cooling_profile"
|
||||
},
|
||||
"bv_fan_nr":
|
||||
{
|
||||
|
|
@ -321,7 +336,7 @@ class AddCoolingProfile(Script):
|
|||
"unit": "# ",
|
||||
"default_value": 0,
|
||||
"minimum_value": 0,
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable and enable_cooling_profile"
|
||||
},
|
||||
"bv_fan_speed":
|
||||
{
|
||||
|
|
@ -332,7 +347,7 @@ class AddCoolingProfile(Script):
|
|||
"default_value": 50,
|
||||
"maximum_value": 100,
|
||||
"minimum_value": 0,
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable and enable_cooling_profile"
|
||||
},
|
||||
"bv_fan_start_layer":
|
||||
{
|
||||
|
|
@ -342,7 +357,7 @@ class AddCoolingProfile(Script):
|
|||
"unit": "Layer# ",
|
||||
"default_value": 1,
|
||||
"minimum_value": 1,
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable and enable_cooling_profile"
|
||||
},
|
||||
"bv_fan_end_layer":
|
||||
{
|
||||
|
|
@ -352,7 +367,7 @@ class AddCoolingProfile(Script):
|
|||
"unit": "Layer# ",
|
||||
"default_value": -1,
|
||||
"minimum_value": -1,
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
|
||||
"enabled": "enable_bv_fan and bv_fan_speed_control_enable and enable_cooling_profile"
|
||||
},
|
||||
"enable_bv_fan":
|
||||
{
|
||||
|
|
@ -361,6 +376,14 @@ class AddCoolingProfile(Script):
|
|||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": false
|
||||
},
|
||||
"jump_start_enable":
|
||||
{
|
||||
"label": "Enable Jump Starting",
|
||||
"description": "Some fans take a bit of time to get up to speed. This option will enter a 75% fan speed line 5 lines before the M106 fan setting line.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "fan_layer_or_feature == 'by_feature' and enable_cooling_profile"
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
|
@ -402,12 +425,17 @@ class AddCoolingProfile(Script):
|
|||
feature_fan_combing: Whether or not to shut the cooling fan off during travel moves.
|
||||
the_start_layer: When in By Feature this is the user selected start of the fan changes.
|
||||
the_end_layer: When in By Feature this is the user selected end of the fan changes
|
||||
the_end_is_enabled: When in By Feature, if the fan control ends before the print ends, then this will enable the Final Fan Speed to carry through to the print end.
|
||||
|
||||
the_end_is_enabled: When in By Feature, if the fan control ends before the print ends, then this will enable the Final Fan Speed to carry through to the print end.
|
||||
|
||||
"""
|
||||
# Exit if the gcode has been previously post-processed.
|
||||
if ";POSTPROCESSED" in data[0]:
|
||||
return data
|
||||
|
||||
# Return if the script is not enabled.
|
||||
if not bool(self.getSettingValueByKey("enable_cooling_profile")):
|
||||
return data
|
||||
|
||||
# Initialize variables that are buried in if statements.
|
||||
t0_fan = " P0"; t1_fan = " P0"; t2_fan = " P0"; t3_fan = " P0"; is_multi_extr_print = True
|
||||
|
||||
|
|
@ -419,9 +447,8 @@ class AddCoolingProfile(Script):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
bed_adhesion = (self.extruder_list[0].getProperty("adhesion_type", "value"))
|
||||
bed_adhesion = self.extruder_list[0].getProperty("adhesion_type", "value")
|
||||
print_sequence = str(self.global_stack.getProperty("print_sequence", "value"))
|
||||
|
||||
# Assign the fan numbers to the tools
|
||||
if self.extruder_count == 1:
|
||||
is_multi_fan = False
|
||||
|
|
@ -452,6 +479,8 @@ class AddCoolingProfile(Script):
|
|||
if by_layer_or_feature == "by_layer":
|
||||
# By layer doesn't do any feature search so there is no need to look for combing moves
|
||||
feature_fan_combing = False
|
||||
# Don't need to jump start fans when By Layer
|
||||
self._jump_start = False
|
||||
fan_list[0] = self.getSettingValueByKey("layer_fan_1")
|
||||
fan_list[2] = self.getSettingValueByKey("layer_fan_2")
|
||||
fan_list[4] = self.getSettingValueByKey("layer_fan_3")
|
||||
|
|
@ -468,6 +497,7 @@ class AddCoolingProfile(Script):
|
|||
|
||||
# Assign the variable values if "By Feature"
|
||||
elif by_layer_or_feature == "by_feature":
|
||||
self._jump_start = self.getSettingValueByKey("jump_start_enable")
|
||||
the_start_layer = self.getSettingValueByKey("feature_fan_start_layer") - 1
|
||||
the_end_layer = self.getSettingValueByKey("feature_fan_end_layer")
|
||||
try:
|
||||
|
|
@ -691,6 +721,8 @@ class AddCoolingProfile(Script):
|
|||
if layer_number == str(fan_list[num]):
|
||||
layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan))
|
||||
single_fan_data[l_index] = layer
|
||||
if self._jump_start:
|
||||
single_fan_data = self._jump_start_layer_cooling_fan(single_fan_data, layer_0_index)
|
||||
return single_fan_data
|
||||
|
||||
# Multi-Fan "By Layer"
|
||||
|
|
@ -759,6 +791,8 @@ class AddCoolingProfile(Script):
|
|||
# Insure the fans get shut off if 'off_fan_speed' was enabled
|
||||
if self.extruder_count > 1 and self.getSettingValueByKey("enable_off_fan_speed"):
|
||||
multi_fan_data[-1] += "M106 S0 P1\nM106 S0 P0\n"
|
||||
if self._jump_start:
|
||||
multi_fan_data = self._jump_start_layer_cooling_fan(multi_fan_data, layer_0_index)
|
||||
return multi_fan_data
|
||||
|
||||
# Single fan by feature
|
||||
|
|
@ -786,12 +820,14 @@ class AddCoolingProfile(Script):
|
|||
if feature_fan_combing == True:
|
||||
modified_data += "M106 S0" + t0_fan + "\n"
|
||||
modified_data += line + "\n"
|
||||
|
||||
|
||||
# If an End Layer is defined and is less than the last layer then insert the Final Speed
|
||||
if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True:
|
||||
modified_data += feature_speed_list[len(feature_speed_list) - 1] + t0_fan + "\n"
|
||||
if modified_data.endswith("\n"): modified_data = modified_data[0: - 1]
|
||||
single_fan_data[l_index] = modified_data
|
||||
if self._jump_start:
|
||||
single_fan_data = self._jump_start_layer_cooling_fan(single_fan_data, layer_0_index)
|
||||
return single_fan_data
|
||||
|
||||
# Multi-fan by feature
|
||||
|
|
@ -890,6 +926,8 @@ class AddCoolingProfile(Script):
|
|||
# Insure the fans get shut off if 'off_fan_speed' was enabled
|
||||
if self.extruder_count > 1 and self.getSettingValueByKey("enable_off_fan_speed"):
|
||||
multi_fan_data[-1] += "M106 S0 P1\nM106 S0 P0\n"
|
||||
if self._jump_start:
|
||||
multi_fan_data = self._jump_start_layer_cooling_fan(multi_fan_data, layer_0_index)
|
||||
return multi_fan_data
|
||||
|
||||
# Try to catch layer input errors, set the minimum speed to 12%, and put the strings together
|
||||
|
|
@ -1005,4 +1043,33 @@ class AddCoolingProfile(Script):
|
|||
lines[fdex] = f"M106 S0 P{bv_fan_nr}\n" + line
|
||||
bv_data[index] = "\n".join(lines)
|
||||
break
|
||||
return bv_data
|
||||
return bv_data
|
||||
|
||||
def _jump_start_layer_cooling_fan(self, data: str, layer_0_index: int):
|
||||
"""
|
||||
If the fan is off - run the speed up to ~70% prior to setting the actual speed to insure the fan starts spinning.
|
||||
"""
|
||||
fan_mode = not bool(self.extruder_list[0].getProperty("machine_scale_fan_speed_zero_to_one", "value"))
|
||||
fan_is_on = False
|
||||
for lay_index, layer in enumerate(data):
|
||||
if lay_index < layer_0_index:
|
||||
continue
|
||||
lines = layer.split("\n")
|
||||
for index, line in enumerate(lines):
|
||||
if line.startswith("M106 S0") or line.startswith("M107"):
|
||||
fan_is_on = False
|
||||
elif line.startswith("M106 S") and float(self.getValue(line, 'S')) != 0:
|
||||
if not fan_is_on:
|
||||
# Insert a jump start command a few lines before the first non-zero fan speed,
|
||||
# without modifying existing comment/header lines in place.
|
||||
if index >= 5:
|
||||
insert_index = index - 5
|
||||
else:
|
||||
# Keep any initial header/comment line (e.g. ";LAYER:5") intact by
|
||||
# inserting after it when possible.
|
||||
insert_index = 1 if len(lines) > 1 else 0
|
||||
jump_start_cmd = f"M106 S{self.jump_speed_marlin} ; Jump start" if fan_mode else "M106 S{self.jump_speed_reprap} ; Jump start"
|
||||
lines.insert(insert_index, jump_start_cmd)
|
||||
fan_is_on = True
|
||||
data[lay_index] = "\n".join(lines)
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Copyright (c) 2025 GregValiant (Greg Foresi)
|
|||
from UM.Application import Application
|
||||
from ..Script import Script
|
||||
from UM.Message import Message
|
||||
from UM.Logger import Logger
|
||||
|
||||
class AnnealingOrDrying(Script):
|
||||
|
||||
|
|
@ -304,7 +305,7 @@ class AnnealingOrDrying(Script):
|
|||
data = self._anneal_print(add_messages, data, bed_temperature, chamber_temp, heated_chamber, heating_zone, lowest_temp, max_x, max_y, max_z, park_xy, park_z, speed_travel)
|
||||
elif cycle_type == "dry_cycle":
|
||||
data = self._dry_filament_only(data, bed_temperature, chamber_temp, heated_chamber, heating_zone, max_y, max_z, speed_travel)
|
||||
|
||||
|
||||
return data
|
||||
|
||||
def _anneal_print(
|
||||
|
|
@ -325,7 +326,7 @@ class AnnealingOrDrying(Script):
|
|||
"""
|
||||
The procedure disables the M140 (and M141) lines at the end of the print, and adds additional bed (and chamber) temperature commands to the end of the G-Code file.
|
||||
The bed is allowed to cool down over a period of time.
|
||||
|
||||
|
||||
:param add_messages: Whether to include M117 and M118 messages for LCD and print server
|
||||
:param anneal_data: The G-code data to be modified with annealing commands
|
||||
:param bed_temperature: Starting bed temperature in degrees Celsius
|
||||
|
|
@ -483,7 +484,7 @@ class AnnealingOrDrying(Script):
|
|||
This procedure turns the bed on, homes the printer, parks the head. After the time period the bed is turned off.
|
||||
There is no actual print in the generated gcode, just a couple of moves to get the nozzle out of the way, and the bed heat (and possibly chamber heat) control.
|
||||
It allows a user to use the bed to warm up and hopefully dry a filament roll.
|
||||
|
||||
|
||||
:param bed_temperature: Bed temperature for drying in degrees Celsius
|
||||
:param chamber_temp: Chamber/build volume temperature for drying in degrees Celsius
|
||||
:param drydata: The G-code data to be replaced with filament drying commands
|
||||
|
|
@ -494,9 +495,14 @@ class AnnealingOrDrying(Script):
|
|||
:param speed_travel: Travel speed for positioning moves in mm/min as string
|
||||
:return: Modified G-code data containing only filament drying sequence
|
||||
"""
|
||||
machine_name = str(self.global_stack.getProperty("machine_name", "value"))
|
||||
machine_gcode_flavor = str(self.global_stack.getProperty("machine_gcode_flavor", "value"))
|
||||
active_machine = ""
|
||||
if machine_gcode_flavor in ["Ultigcode", "Cheetah", "Griffin"] or "Ultimaker" in machine_name:
|
||||
active_machine = "UM"
|
||||
for num in range(2, len(drydata)):
|
||||
drydata[num] = ""
|
||||
drydata[0] = drydata[0].split("\n")[0] + "\n"
|
||||
|
||||
add_messages = bool(self.getSettingValueByKey("add_messages"))
|
||||
pause_cmd = self.getSettingValueByKey("pause_cmd")
|
||||
if pause_cmd != "":
|
||||
|
|
@ -567,5 +573,31 @@ class AnnealingOrDrying(Script):
|
|||
if heated_chamber and heating_zone == "bed_chamber":
|
||||
dry_txt += "; Chamber temperature ....... " + str(chamber_temp) + "°\n"
|
||||
Message(title = "[Dry Filament]", text = dry_txt).show()
|
||||
drydata[0] = "; <<< This is a filament drying file only. There is no actual print. >>>\n;\n" + dry_txt + ";\n"
|
||||
# UM machines require the existing 'data[0]' with some alteration
|
||||
if active_machine == "UM":
|
||||
drydata[0] = self.prep_for_um_machines(drydata, bed_temperature, chamber_temp, heating_zone, dry_time)
|
||||
drydata[0] += ";\n; <<< This is a filament drying file only. There is no actual print. >>>\n;\n" + dry_txt + ";\n"
|
||||
return drydata
|
||||
|
||||
def prep_for_um_machines(self, drydata: str, bed_temperature, chamber_temp, heating_zone: str, dry_time):
|
||||
Message(title = "⚠️⚠️⚠️ [Dry Filament] ⚠️⚠️⚠️", text = f"Your printer appears to be a 'UltiMaker' printer. 'Dry Filament' might bring warnings up on the LCD screen (ex: for 'material compatibility'). You should be able to 'Ignore' them and the gcode should run. In some cases, the machine may not want to run the gcode. Experimenting may help get past that blockage. Do not place anything on the Build Plate until the machine has settled down and the bed is heating.").show()
|
||||
# This will alter the bed/chamber/hot end temperatures for drying
|
||||
lines = drydata[0].split("\n")
|
||||
for index, line in enumerate(lines):
|
||||
if ";BUILD_PLATE.INITIAL_TEMPERATURE:" in line:
|
||||
lines[index] = f";BUILD_PLATE.INITIAL_TEMPERATURE:{bed_temperature}"
|
||||
if ";EXTRUDER_TRAIN.0.INITIAL_TEMPERATURE:" in line:
|
||||
lines[index] = f";EXTRUDER_TRAIN.0.INITIAL_TEMPERATURE:40"
|
||||
if ";EXTRUDER_TRAIN.1.INITIAL_TEMPERATURE:" in line:
|
||||
lines[index] = f";EXTRUDER_TRAIN.1.INITIAL_TEMPERATURE:40"
|
||||
if ";BUILD_VOLUME.TEMPERATURE:" in line:
|
||||
if heating_zone == "bed_chamber":
|
||||
lines[index] = f";BUILD_VOLUME.TEMPERATURE:{chamber_temp}"
|
||||
if ";PRINT.TIME:" in line:
|
||||
lines[index] = f";PRINT.TIME:{dry_time}"
|
||||
drydata[0] = "\n".join(lines)
|
||||
# This line will tell the printer sto skip these processes. Skipping requires the G28 to be added.
|
||||
um_line = ";SKIP_PROCEDURES:PRE_PRINT_SETUP,PURGE_MATERIAL_MISP,LOAD_MATERIAL_MISP,UNLOAD_MATERIAL_MISP_0,UNLOAD_MATERIAL_MISP_1,PREPARE_MISP_MATERIALS,DEPRIME_FOR_MATERIAL_CHANGE_MISP,SEND_FOLLOW_COMMAND_MISP,BREAK_FAILED_WIZARD,LOADING_FAILURE_RECOVERY_WIZARD,START_COOLDOWN_HOTEND,SET_HOTEND_TEMPERATURE_WAIT\nG28 X Y Z"
|
||||
lines.insert(len(lines)-2, um_line)
|
||||
drydata[0] = "\n".join(lines)
|
||||
return drydata[0]
|
||||
|
|
@ -29,7 +29,9 @@ Display Filename and Layer on the LCD by Amanda de Castilho on August 28, 2018
|
|||
- 'Add M118 Line' is available with either option. M118 will bounce the message back to a remote print server through the USB connection.
|
||||
- 'Add M73 Line' is used by 'Display Progress' only. There are options to incluse M73 P(percent) and M73 R(time remaining)
|
||||
- Enable 'Finish-Time' Message - when enabled, takes the Print Time and calculates when the print will end. It uses the Time Fudge Factor. The user may enter a print start time.
|
||||
Date: June 30, 2025 Cost of electricity added to the other print statistics in '_add_stats'.
|
||||
Date: June 30, 2025 Cost of electricity added to the other print statistics in '_add_stats'. (GregValiant)
|
||||
Date: Sept 24, 2025 Disabled countdown to pauses when in 'One-at-a-Time' mode. (GregValiant)
|
||||
Date: Jan 20, 2026 Added "weight" to the stats inserted in the Gcode.
|
||||
"""
|
||||
|
||||
from ..Script import Script
|
||||
|
|
@ -41,19 +43,27 @@ import math
|
|||
from UM.Message import Message
|
||||
|
||||
class DisplayInfoOnLCD(Script):
|
||||
|
||||
def initialize(self) -> None:
|
||||
|
||||
minimumCuraVersion = 5110
|
||||
|
||||
def initialize(self) -> None:
|
||||
super().initialize()
|
||||
cura_version = Application.getInstance().getVersion()
|
||||
cura_version_str = cura_version.split("-")[0]
|
||||
cura_version_int = int(cura_version_str.replace(".", ""))
|
||||
try:
|
||||
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "all_at_once":
|
||||
enable_countdown = True
|
||||
self._instance.setProperty("enable_countdown", "value", enable_countdown)
|
||||
except AttributeError:
|
||||
else:
|
||||
enable_countdown = False
|
||||
self._instance.setProperty("enable_countdown", "value", enable_countdown)
|
||||
if cura_version_int > self.minimumCuraVersion:
|
||||
cura_adjust_percent = Application.getInstance().getGlobalContainerStack().getProperty("machine_time_estimation_factor", "value")
|
||||
self._instance.setProperty("time_adj_percentage", "value", cura_adjust_percent)
|
||||
except (AttributeError, KeyError):
|
||||
# Handle cases where the global container stack or its properties are not accessible
|
||||
pass
|
||||
except KeyError:
|
||||
# Handle cases where the "print_sequence" property is missing
|
||||
pass
|
||||
cura_adjust_percent = 100
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
|
|
@ -186,10 +196,10 @@ class DisplayInfoOnLCD(Script):
|
|||
"default_value": false,
|
||||
"enabled": "add_m73_line and display_option == 'display_progress' and display_remaining_time"
|
||||
},
|
||||
"speed_factor":
|
||||
"time_adj_percentage":
|
||||
{
|
||||
"label": "Time Fudge Factor %",
|
||||
"description": "When using 'Display Progress' tweak this value to get better estimates. ([Actual Print Time]/[Cura Estimate]) x 100 = Time Fudge Factor. If Cura estimated 9hr and the print actually took 10hr30min then enter 117 here to adjust any estimate closer to reality. This Fudge Factor is also used to calculate the print finish time.",
|
||||
"label": "Print Time Estimation Factor",
|
||||
"description": "When using 'Display Progress' adjust this value to get better time estimates. '([Actual Print Time]/[Cura Estimate]) x 100 = Time Estimation Factor'. This number should match the entry in the Cura Machine Settings but it can be different.",
|
||||
"type": "float",
|
||||
"unit": "%",
|
||||
"default_value": 100,
|
||||
|
|
@ -200,14 +210,13 @@ class DisplayInfoOnLCD(Script):
|
|||
"label": "Enable Countdown to Pauses",
|
||||
"description": "If print sequence is 'one_at_a_time' this is false. This setting is always hidden.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"value": false,
|
||||
"enabled": false
|
||||
},
|
||||
"countdown_to_pause":
|
||||
{
|
||||
"label": "Countdown to Pauses",
|
||||
"description": "This must run AFTER any script that adds a pause. Instead of the remaining print time the LCD will show the estimated time to the next layer that has a pause (TP). Countdown to Pause is not available when in One-at-a-Time' mode.",
|
||||
"label": "Countdown to Pause(s)",
|
||||
"description": "This must run AFTER any script that adds a pause. Instead of the remaining print time the LCD will show the estimated time to the next layer that has a pause (TP). Countdown to Pause does not work in 'One-at-a-Time' mode.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "display_option == 'display_progress' and enable_countdown and display_remaining_time"
|
||||
|
|
@ -240,7 +249,7 @@ class DisplayInfoOnLCD(Script):
|
|||
"electricity_cost":
|
||||
{
|
||||
"label": "Electricity Cost per kWh",
|
||||
"description": "Cost of electricity per kilowatt-hour. This should be on your electric utility bill.",
|
||||
"description": "Cost of electricity per kilowatt-hour. This should be on your electric utility bill. The 'Electricity Cost' will be added to the gcode file.",
|
||||
"type": "float",
|
||||
"default_value": 0.151,
|
||||
"minimum_value": 0,
|
||||
|
|
@ -260,6 +269,7 @@ class DisplayInfoOnLCD(Script):
|
|||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
self.global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
display_option = self.getSettingValueByKey("display_option")
|
||||
self.add_m117_line = self.getSettingValueByKey("add_m117_line")
|
||||
self.add_m118_line = self.getSettingValueByKey("add_m118_line")
|
||||
|
|
@ -340,7 +350,7 @@ class DisplayInfoOnLCD(Script):
|
|||
final_lines = "\n".join(lines)
|
||||
data[layer_index] = final_lines
|
||||
if bool(self.getSettingValueByKey("enable_end_message")):
|
||||
message_str = self._message_to_user(self.getSettingValueByKey("speed_factor") / 100)
|
||||
message_str = self._message_to_user(self.getSettingValueByKey("time_adj_percentage") / 100)
|
||||
Message(title = "Display Info on LCD - Estimated Finish Time", text = message_str[0] + "\n\n" + message_str[1] + "\n" + message_str[2] + "\n" + message_str[3]).show()
|
||||
return data
|
||||
|
||||
|
|
@ -350,9 +360,10 @@ class DisplayInfoOnLCD(Script):
|
|||
data[0] = self._add_stats(data)
|
||||
# Get settings
|
||||
print_sequence = Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value")
|
||||
countdown_to_pause = bool(self.getSettingValueByKey("countdown_to_pause")) if print_sequence == "all_at_once" else False
|
||||
display_total_layers = self.getSettingValueByKey("display_total_layers")
|
||||
display_remaining_time = self.getSettingValueByKey("display_remaining_time")
|
||||
speed_factor = self.getSettingValueByKey("speed_factor") / 100
|
||||
time_adj_percentage = self.getSettingValueByKey("time_adj_percentage") / 100
|
||||
m73_time = False
|
||||
m73_percent = False
|
||||
if self.add_m73_line and self.add_m73_time:
|
||||
|
|
@ -375,7 +386,7 @@ class DisplayInfoOnLCD(Script):
|
|||
if line.startswith(";TIME:"):
|
||||
tindex = lines.index(line)
|
||||
cura_time = int(line.split(":")[1])
|
||||
print_time = cura_time * speed_factor
|
||||
print_time = cura_time * time_adj_percentage
|
||||
hhh = print_time/3600
|
||||
hr = round(hhh // 1)
|
||||
mmm = round((hhh % 1) * 60)
|
||||
|
|
@ -396,7 +407,7 @@ class DisplayInfoOnLCD(Script):
|
|||
lines.insert(tindex + 4, "M73" + self.m73_str)
|
||||
# If Countdown to pause is enabled then count the pauses
|
||||
pause_str = ""
|
||||
if bool(self.getSettingValueByKey("countdown_to_pause")):
|
||||
if countdown_to_pause:
|
||||
pause_count = 0
|
||||
pause_setting = self.getSettingValueByKey("pause_cmd").upper()
|
||||
if pause_setting != "":
|
||||
|
|
@ -420,7 +431,7 @@ class DisplayInfoOnLCD(Script):
|
|||
if self.add_m117_line:
|
||||
data[len(data)-1] += "M117 Orig Cura Est " + str(orig_hr) + "hr " + str(orig_mmm) + "min\n"
|
||||
if self.add_m118_line:
|
||||
data[len(data)-1] += "M118 Est w/FudgeFactor " + str(speed_factor * 100) + "% was " + str(hr) + "hr " + str(mmm) + "min\n"
|
||||
data[len(data)-1] += "M118 Est w/FudgeFactor " + str(time_adj_percentage * 100) + "% was " + str(hr) + "hr " + str(mmm) + "min\n"
|
||||
if not display_total_layers or not display_remaining_time:
|
||||
base_display_text = "layer "
|
||||
else:
|
||||
|
|
@ -463,7 +474,7 @@ class DisplayInfoOnLCD(Script):
|
|||
if display_remaining_time:
|
||||
time_remaining_display = " | ET " # initialize the time display
|
||||
m = (self.time_total - time_elapsed) // 60 # estimated time in minutes
|
||||
m *= speed_factor # correct for printing time
|
||||
m *= time_adj_percentage # correct for printing time
|
||||
m = int(m)
|
||||
h, m = divmod(m, 60) # convert to hours and minutes
|
||||
# add the time remaining to the display_text
|
||||
|
|
@ -523,7 +534,7 @@ class DisplayInfoOnLCD(Script):
|
|||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if line.startswith(";TIME_ELAPSED:"):
|
||||
this_time = (float(line.split(":")[1]))*speed_factor
|
||||
this_time = (float(line.split(":")[1]))*time_adj_percentage
|
||||
time_list.append(str(this_time))
|
||||
for p_cmd in pause_cmd:
|
||||
if p_cmd in layer:
|
||||
|
|
@ -533,7 +544,7 @@ class DisplayInfoOnLCD(Script):
|
|||
break
|
||||
|
||||
# Make the adjustments to the M117 (and M118) lines that are prior to a pause
|
||||
for num in range (2, len(data) - 1,1):
|
||||
for num in range (2, len(data) - 1):
|
||||
layer = data[num]
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
|
|
@ -550,16 +561,19 @@ class DisplayInfoOnLCD(Script):
|
|||
continue
|
||||
data[num] = layer
|
||||
if bool(self.getSettingValueByKey("enable_end_message")):
|
||||
message_str = self._message_to_user(data, speed_factor, pause_cmd)
|
||||
Message(title = "[Display Info on LCD] - Estimated Finish Time", text = message_str[0] + "\n\n" + message_str[1] + "\n" + message_str[2] + "\n" + message_str[3]).show()
|
||||
message_str = self._message_to_user(data, time_adj_percentage, pause_cmd)
|
||||
electric_use = self.getElectricCostLine()
|
||||
Message(title = "[Display Info on LCD] - Estimated Finish Time", text = message_str[0] + "\n\n" + message_str[1] + "\n" + message_str[2] + "\n" + message_str[3] + "\n" + electric_use).show()
|
||||
return data
|
||||
|
||||
def _message_to_user(self, data: str, speed_factor: float, pause_cmd: str) -> str:
|
||||
def _message_to_user(self, data: str, time_adj_percentage: float, pause_cmd: str) -> str:
|
||||
"""
|
||||
Message the user of the projected finish time of the print and when any pauses might occur
|
||||
"""
|
||||
print_time = Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)
|
||||
print_start_time = self.getSettingValueByKey("print_start_time")
|
||||
if print_start_time == "":
|
||||
print_start_time = datetime.datetime.now().strftime("%H:%M")
|
||||
# If the user entered a print start time make sure it is in the correct format or ignore it.
|
||||
if print_start_time == "" or print_start_time == "0" or len(print_start_time) != 5 or not ":" in print_start_time:
|
||||
print_start_time = ""
|
||||
|
|
@ -586,7 +600,7 @@ class DisplayInfoOnLCD(Script):
|
|||
#Adjust the print time if none was entered
|
||||
print_seconds = pr_hr*3600 + pr_min*60 + pr_sec
|
||||
#Adjust the total seconds by the Fudge Factor
|
||||
adjusted_print_time = print_seconds * speed_factor
|
||||
adjusted_print_time = print_seconds * time_adj_percentage
|
||||
#Break down the adjusted seconds back into hh:mm:ss
|
||||
adj_hr = int(adjusted_print_time/3600)
|
||||
print_seconds = adjusted_print_time - (adj_hr * 3600)
|
||||
|
|
@ -618,7 +632,17 @@ class DisplayInfoOnLCD(Script):
|
|||
else:
|
||||
print_start_str = "Print Start Time.................Now"
|
||||
estimate_str = "Cura Time Estimate.........." + str(print_time)
|
||||
adjusted_str = "Adjusted Time Estimate..." + str(time_change)
|
||||
# Set a default value for compatibility with earlier versions
|
||||
try:
|
||||
cura_adjust_percent = int(Application.getInstance().getGlobalContainerStack().getProperty("machine_time_estimation_factor", "value"))
|
||||
except (NameError, ValueError, TypeError):
|
||||
cura_adjust_percent = 100
|
||||
if cura_adjust_percent == 100:
|
||||
adjusted_str = "Adjusted Time Estimate..." + str(time_change)
|
||||
else:
|
||||
adjusted_str = f"(Time adjusted to {cura_adjust_percent}% per Cura Machine Settings)"
|
||||
if time_adj_percentage != cura_adjust_percent:
|
||||
adjusted_str += f"\n(Gcode was adjusted by the script setting of {time_adj_percentage * 100}%)"
|
||||
finish_str = f"{week_day} {mo_str} {new_time.strftime('%d')}, {new_time.strftime('%Y')} at {show_hr}{new_time.strftime('%M')}{show_ampm}"
|
||||
|
||||
# If there are pauses and if countdown is enabled, then add the time-to-pause to the message.
|
||||
|
|
@ -649,7 +673,6 @@ class DisplayInfoOnLCD(Script):
|
|||
return time_to_go
|
||||
|
||||
def _add_stats(self, data: str) -> str:
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
"""
|
||||
Make a list of the models in the file.
|
||||
Add some of the filament stats to the first section of the gcode.
|
||||
|
|
@ -663,50 +686,62 @@ class DisplayInfoOnLCD(Script):
|
|||
if not model_name in model_list:
|
||||
model_list.append(model_name)
|
||||
# Filament stats
|
||||
extruder_count = global_stack.getProperty("machine_extruder_count", "value")
|
||||
layheight_0 = global_stack.getProperty("layer_height_0", "value")
|
||||
extruder_count = self.global_stack.getProperty("machine_extruder_count", "value")
|
||||
layheight_0 = self.global_stack.getProperty("layer_height_0", "value")
|
||||
init_layer_hgt_line = ";Initial Layer Height: " + f"{layheight_0:.2f}".format(layheight_0)
|
||||
filament_line_t0 = ";Extruder 1 (T0)\n"
|
||||
filament_amount = Application.getInstance().getPrintInformation().materialLengths
|
||||
filament_line_t0 += f"; Filament used: {filament_amount[0]}m\n"
|
||||
filament_line_t0 += f"; Filament Type: {global_stack.extruderList[0].material.getMetaDataEntry("material", "")}\n"
|
||||
filament_line_t0 += f"; Filament Dia.: {global_stack.extruderList[0].getProperty("material_diameter", "value")}mm\n"
|
||||
filament_line_t0 += f"; Nozzle Size : {global_stack.extruderList[0].getProperty("machine_nozzle_size", "value")}mm\n"
|
||||
filament_line_t0 += f"; Print Temp. : {global_stack.extruderList[0].getProperty("material_print_temperature", "value")}°\n"
|
||||
filament_line_t0 += f"; Bed Temp. : {global_stack.extruderList[0].getProperty("material_bed_temperature", "value")}°"
|
||||
filament_weight = Application.getInstance().getPrintInformation().materialWeights
|
||||
filament_line_t0 += f"; Filament used: {filament_amount[0]}m ({round(filament_weight[0], 2)}g)\n"
|
||||
filament_line_t0 += f"; Filament Type: {self.global_stack.extruderList[0].material.getMetaDataEntry("material", "")}\n"
|
||||
filament_line_t0 += f"; Filament Dia.: {self.global_stack.extruderList[0].getProperty("material_diameter", "value")}mm\n"
|
||||
filament_line_t0 += f"; Nozzle Size : {self.global_stack.extruderList[0].getProperty("machine_nozzle_size", "value")}mm\n"
|
||||
filament_line_t0 += f"; Print Temp. : {self.global_stack.extruderList[0].getProperty("material_print_temperature", "value")}°\n"
|
||||
filament_line_t0 += f"; Bed Temp. : {self.global_stack.extruderList[0].getProperty("material_bed_temperature", "value")}°"
|
||||
|
||||
# if there is more than one extruder then get the stats for the second one.
|
||||
filament_line_t1 = ""
|
||||
if extruder_count > 1:
|
||||
filament_line_t1 = "\n;Extruder 2 (T1)\n"
|
||||
filament_line_t1 += f"; Filament used: {filament_amount[1]}m\n"
|
||||
filament_line_t1 += f"; Filament Type: {global_stack.extruderList[1].material.getMetaDataEntry("material", "")}\n"
|
||||
filament_line_t1 += f"; Filament Dia.: {global_stack.extruderList[1].getProperty("material_diameter", "value")}mm\n"
|
||||
filament_line_t1 += f"; Nozzle Size : {global_stack.extruderList[1].getProperty("machine_nozzle_size", "value")}mm\n"
|
||||
filament_line_t1 += f"; Print Temp. : {global_stack.extruderList[1].getProperty("material_print_temperature", "value")}°"
|
||||
|
||||
filament_line_t1 += f"; Filament used: {filament_amount[1]}m ({round(filament_weight[1], 2)}g)\n"
|
||||
filament_line_t1 += f"; Filament Type: {self.global_stack.extruderList[1].material.getMetaDataEntry("material", "")}\n"
|
||||
filament_line_t1 += f"; Filament Dia.: {self.global_stack.extruderList[1].getProperty("material_diameter", "value")}mm\n"
|
||||
filament_line_t1 += f"; Nozzle Size : {self.global_stack.extruderList[1].getProperty("machine_nozzle_size", "value")}mm\n"
|
||||
filament_line_t1 += f"; Print Temp. : {self.global_stack.extruderList[1].getProperty("material_print_temperature", "value")}°"
|
||||
|
||||
# Calculate the cost of electricity for the print
|
||||
electricity_cost = self.getSettingValueByKey("electricity_cost")
|
||||
printer_power_usage = self.getSettingValueByKey("printer_power_usage")
|
||||
currency_unit = Application.getInstance().getPreferences().getValue("cura/currency")
|
||||
total_cost_electricity = (printer_power_usage / 1000) * (self.time_total / 3600) * electricity_cost
|
||||
|
||||
electric_line = self.getElectricCostLine()
|
||||
|
||||
# Add the stats to the gcode file
|
||||
lines = data[0].split("\n")
|
||||
# This is a switch to avoid a 'double insertion' in a Marlin file.
|
||||
lines_inserted = False
|
||||
for index, line in enumerate(lines):
|
||||
if line.startswith(";Layer height:") or line.startswith(";TARGET_MACHINE.NAME:"):
|
||||
lines[index] = ";Layer height: " + f"{global_stack.getProperty("layer_height", "value")}"
|
||||
lines[index] += f"\n{init_layer_hgt_line}"
|
||||
lines[index] += f"\n;Base Quality Name : '{global_stack.quality.getMetaDataEntry("name", "")}'"
|
||||
lines[index] += f"\n;Custom Quality Name: '{global_stack.qualityChanges.getMetaDataEntry("name")}'"
|
||||
if not lines_inserted:
|
||||
lines[index] = ";Layer height: " + f"{self.global_stack.getProperty("layer_height", "value")}"
|
||||
lines[index] += f"\n{init_layer_hgt_line}"
|
||||
lines[index] += f"\n;Base Quality Name : '{self.global_stack.quality.getMetaDataEntry("name", "")}'"
|
||||
lines[index] += f"\n;Custom Quality Name: '{self.global_stack.qualityChanges.getMetaDataEntry("name")}'"
|
||||
lines_inserted = True
|
||||
if line.startswith(";Filament used"):
|
||||
lines[index] = filament_line_t0 + filament_line_t1 + f"\n;Electric Cost: {currency_unit}{total_cost_electricity:.2f}".format(total_cost_electricity)
|
||||
lines[index] = filament_line_t0 + filament_line_t1 + "\n;" + electric_line
|
||||
# The target machine "machine_name" is actually the printer model. This adds the user defined printer name to the "TARGET_MACHINE" line.
|
||||
if line.startswith(";TARGET_MACHINE"):
|
||||
machine_model = str(global_stack.getProperty("machine_name", "value"))
|
||||
machine_name = str(global_stack.getName())
|
||||
machine_model = str(self.global_stack.getProperty("machine_name", "value"))
|
||||
machine_name = str(self.global_stack.getName())
|
||||
lines[index] += f" / {machine_name}"
|
||||
if "MINX" in line or "MIN.X" in line:
|
||||
# Add the Object List
|
||||
lines[index - 1] += f"\n;Model List: {str(model_list)}"
|
||||
return "\n".join(lines)
|
||||
return "\n".join(lines)
|
||||
|
||||
def getElectricCostLine(self) -> str:
|
||||
electricity_cost = self.getSettingValueByKey("electricity_cost")
|
||||
printer_power_usage = self.getSettingValueByKey("printer_power_usage")
|
||||
if electricity_cost == 0 or printer_power_usage == 0:
|
||||
return ""
|
||||
currency_unit = Application.getInstance().getPreferences().getValue("cura/currency")
|
||||
total_cost_electricity = (printer_power_usage / 1000) * (self.time_total / 3600) * electricity_cost
|
||||
electric_line = f"Electric Cost: {currency_unit}{total_cost_electricity:.2f}"
|
||||
return electric_line
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@
|
|||
|
||||
# Modification 06.09.2020
|
||||
# add checkbox, now you can choose and use configuration from the firmware itself.
|
||||
# Modification 01.13.2026 by @hobbe
|
||||
# convert G-code Before and G-Code After inputs to text areas (#21298).
|
||||
# Modification 01.17.2026 by @GregValiant
|
||||
# Move the inserted text below the ";LAYER:??" line.
|
||||
|
||||
from typing import List
|
||||
from ..Script import Script
|
||||
|
||||
from UM.Application import Application # To get the current printer's settings.
|
||||
|
||||
class FilamentChange(Script):
|
||||
|
|
@ -24,21 +27,21 @@ class FilamentChange(Script):
|
|||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"enabled":
|
||||
"enable_filament_change":
|
||||
{
|
||||
"label": "Enable",
|
||||
"description": "Uncheck to temporarily disable this feature.",
|
||||
"label": "Enable 'Filament Change'",
|
||||
"description": "Uncheck to disable this feature.",
|
||||
"type": "bool",
|
||||
"default_value": true
|
||||
},
|
||||
"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": "",
|
||||
"description": "The layer(s) where the color change occurs. Enter the layer number from the Cura Preview. The change will occur at the START of the layer(s). Delimit multiple 'Layer Numbers' with commas (Ex: 12,25,134).",
|
||||
"unit": "Lay#",
|
||||
"type": "str",
|
||||
"default_value": "1",
|
||||
"enabled": "enabled"
|
||||
"enabled": "enable_filament_change"
|
||||
},
|
||||
"firmware_config":
|
||||
{
|
||||
|
|
@ -46,7 +49,7 @@ class FilamentChange(Script):
|
|||
"description": "Use the settings in your firmware, or customise the parameters of the filament change here.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "enabled"
|
||||
"enabled": "enable_filament_change"
|
||||
},
|
||||
"initial_retract":
|
||||
{
|
||||
|
|
@ -55,7 +58,7 @@ class FilamentChange(Script):
|
|||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 30.0,
|
||||
"enabled": "enabled and not firmware_config"
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"later_retract":
|
||||
{
|
||||
|
|
@ -64,7 +67,7 @@ class FilamentChange(Script):
|
|||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 300.0,
|
||||
"enabled": "enabled and not firmware_config"
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"x_position":
|
||||
{
|
||||
|
|
@ -73,7 +76,7 @@ class FilamentChange(Script):
|
|||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"enabled": "enabled and not firmware_config"
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"y_position":
|
||||
{
|
||||
|
|
@ -82,7 +85,7 @@ class FilamentChange(Script):
|
|||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"enabled": "enabled and not firmware_config"
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"z_position":
|
||||
{
|
||||
|
|
@ -92,7 +95,7 @@ class FilamentChange(Script):
|
|||
"type": "float",
|
||||
"default_value": 0,
|
||||
"minimum_value": 0,
|
||||
"enabled": "enabled and not firmware_config"
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"retract_method":
|
||||
{
|
||||
|
|
@ -101,8 +104,8 @@ class FilamentChange(Script):
|
|||
"type": "enum",
|
||||
"options": {"U": "Marlin (M600 U)", "L": "Reprap (M600 L)"},
|
||||
"default_value": "U",
|
||||
"enabled": "enabled and not firmware_config"
|
||||
},
|
||||
"enabled": "enable_filament_change and not firmware_config"
|
||||
},
|
||||
"machine_gcode_flavor":
|
||||
{
|
||||
"label": "G-code flavor",
|
||||
|
|
@ -129,16 +132,16 @@ class FilamentChange(Script):
|
|||
"description": "Use this to insert a custom G-code macro before the filament change happens",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "enabled"
|
||||
"enabled": "enable_filament_change"
|
||||
},
|
||||
"before_macro":
|
||||
{
|
||||
"label": "G-code Before",
|
||||
"description": "Any custom G-code to run before the filament change happens, for example, M300 S1000 P10000 for a long beep.",
|
||||
"unit": "",
|
||||
"type": "str",
|
||||
"comments": "multiline",
|
||||
"default_value": "M300 S1000 P10000",
|
||||
"enabled": "enabled and enable_before_macro"
|
||||
"enabled": "enable_filament_change and enable_before_macro"
|
||||
},
|
||||
"enable_after_macro":
|
||||
{
|
||||
|
|
@ -146,16 +149,16 @@ class FilamentChange(Script):
|
|||
"description": "Use this to insert a custom G-code macro after the filament change",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "enabled"
|
||||
"enabled": "enable_filament_change"
|
||||
},
|
||||
"after_macro":
|
||||
{
|
||||
"label": "G-code After",
|
||||
"description": "Any custom G-code to run after the filament has been changed right before continuing the print, for example, you can add a sequence to purge filament and wipe the nozzle.",
|
||||
"unit": "",
|
||||
"type": "str",
|
||||
"comments": "multiline",
|
||||
"default_value": "M300 S440 P500",
|
||||
"enabled": "enabled and enable_after_macro"
|
||||
"enabled": "enable_filament_change and enable_after_macro"
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
|
@ -171,20 +174,19 @@ class FilamentChange(Script):
|
|||
for key in ["machine_gcode_flavor"]:
|
||||
self._instance.setProperty(key, "value", global_container_stack.getProperty(key, "value"))
|
||||
|
||||
# Set retract method based on gcode flavor
|
||||
gcode_flavor = global_container_stack.getProperty("machine_gcode_flavor", "value")
|
||||
if gcode_flavor == "RepRap (RepRap)":
|
||||
self._instance.setProperty("retract_method", "value", "L")
|
||||
else:
|
||||
self._instance.setProperty("retract_method", "value", "U")
|
||||
|
||||
def execute(self, data: List[str]):
|
||||
"""Inserts the filament change g-code at specific layer numbers.
|
||||
|
||||
:param data: A list of layers of g-code.
|
||||
:return: A similar list, with filament change commands inserted.
|
||||
"""
|
||||
enabled = self.getSettingValueByKey("enabled")
|
||||
enabled = self.getSettingValueByKey("enable_filament_change")
|
||||
|
||||
# Return if the script is not enabled
|
||||
if not enabled:
|
||||
return data
|
||||
|
||||
# Initialize variables
|
||||
layer_nums = self.getSettingValueByKey("layer_number")
|
||||
initial_retract = self.getSettingValueByKey("initial_retract")
|
||||
later_retract = self.getSettingValueByKey("later_retract")
|
||||
|
|
@ -197,50 +199,50 @@ class FilamentChange(Script):
|
|||
enable_after_macro = self.getSettingValueByKey("enable_after_macro")
|
||||
after_macro = self.getSettingValueByKey("after_macro")
|
||||
|
||||
if not enabled:
|
||||
return data
|
||||
|
||||
color_change = ";BEGIN FilamentChange plugin\n"
|
||||
# Put together the insertion string
|
||||
color_change = "\n;BEGIN FilamentChange\n"
|
||||
|
||||
if enable_before_macro:
|
||||
color_change = color_change + before_macro + "\n"
|
||||
color_change += before_macro + "\n"
|
||||
|
||||
color_change = color_change + "M600"
|
||||
color_change += "M600"
|
||||
|
||||
if not firmware_config:
|
||||
if initial_retract is not None and initial_retract > 0.:
|
||||
color_change = color_change + (" E%.2f" % initial_retract)
|
||||
color_change += (" E%.2f" % initial_retract)
|
||||
|
||||
if later_retract is not None and later_retract > 0.:
|
||||
# Reprap uses 'L': https://reprap.org/wiki/G-code#M600:_Filament_change_pause
|
||||
# Marlin uses 'U' https://marlinfw.org/docs/gcode/M600.html
|
||||
retract_method = self.getSettingValueByKey("retract_method")
|
||||
color_change = color_change + (" %s%.2f" % (retract_method, later_retract))
|
||||
color_change += (" %s%.2f" % (retract_method, later_retract))
|
||||
|
||||
if x_pos is not None:
|
||||
color_change = color_change + (" X%.2f" % x_pos)
|
||||
color_change += (" X%.2f" % x_pos)
|
||||
|
||||
if y_pos is not None:
|
||||
color_change = color_change + (" Y%.2f" % y_pos)
|
||||
color_change += (" Y%.2f" % y_pos)
|
||||
|
||||
if z_pos is not None and z_pos > 0.:
|
||||
color_change = color_change + (" Z%.2f" % z_pos)
|
||||
|
||||
color_change = color_change + "\n"
|
||||
color_change += (" Z%.2f" % z_pos)
|
||||
|
||||
color_change += "\n"
|
||||
if enable_after_macro:
|
||||
color_change = color_change + after_macro + "\n"
|
||||
color_change += after_macro + "\n"
|
||||
|
||||
color_change = color_change + ";END FilamentChange plugin\n"
|
||||
color_change += ";END FilamentChange\n"
|
||||
|
||||
# Make the insertions
|
||||
layer_targets = layer_nums.split(",")
|
||||
if len(layer_targets) > 0:
|
||||
for layer_num in layer_targets:
|
||||
try:
|
||||
layer_num = int(layer_num.strip()) + 1 #Needs +1 because the 1st layer is reserved for start g-code.
|
||||
except ValueError: #Layer number is not an integer.
|
||||
continue
|
||||
if 0 < layer_num < len(data):
|
||||
data[layer_num] = color_change + data[layer_num]
|
||||
|
||||
for index, layer in enumerate(data):
|
||||
for layer_num in layer_targets:
|
||||
try:
|
||||
layer_str = f"{self._layer_keyword}{int(layer_num.strip()) - 1}\n"
|
||||
except ValueError: #Layer number is not an integer.
|
||||
continue
|
||||
if layer_str in data[index]:
|
||||
layer_of_interest = data[index].split("\n")
|
||||
layer_of_interest.insert(1, color_change)
|
||||
data[index] = "\n".join(layer_of_interest)
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
~Added support for Relative Extrusion
|
||||
~Added support for Firmware Retraction
|
||||
~Added support for 'G2' and 'G3' moves.
|
||||
~The script supports a maximum of 2 extruders.
|
||||
~'One-at-a-Time' is not supported and a kick-out is added
|
||||
~The script supports a maximum of 2 extruders. You can have more, but they are ignored.
|
||||
(see change note below) ~'One-at-a-Time' is now supported
|
||||
|
||||
Previous contributions by:
|
||||
Original Authors and contributors to the ChangeAtZ post-processing script and the earlier TweakAtZ:
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
Modified by Wes Hanney, Retract Length + Speed, Clean up
|
||||
Modified by Alex Jaxon, Added option to modify Build Volume Temperature
|
||||
Re-write by GregValiant, to work with new variables in Cura 5.x and with the changes noted above
|
||||
Dec 12, 2025 ~ Added support for 'One at a Time' print sequence.
|
||||
"""
|
||||
|
||||
from UM.Application import Application
|
||||
|
|
@ -34,7 +35,11 @@ from UM.Message import Message
|
|||
from UM.Logger import Logger
|
||||
|
||||
class TweakAtZ(Script):
|
||||
version = "2.0.0"
|
||||
version = "2.1" # Updated from 2.0 on Dec 12, 2025
|
||||
# These are for one-at-a-time mode
|
||||
start_list = []
|
||||
end_list = []
|
||||
print_start_adj = 2 # Accounts for the first layer being in data[2]
|
||||
|
||||
def initialize(self) -> None:
|
||||
"""
|
||||
|
|
@ -63,7 +68,7 @@ class TweakAtZ(Script):
|
|||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Tweak At Z (2.0)",
|
||||
"name": "Tweak at Z (""" + self.version + """)",
|
||||
"key": "TweakAtZ",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
|
|
@ -75,6 +80,13 @@ class TweakAtZ(Script):
|
|||
"default_value": true,
|
||||
"enabled": true
|
||||
},
|
||||
"enable_one_at_a_time_mode": {
|
||||
"label": "Enable 'One at a Time' mode",
|
||||
"description": "If your print sequence is 'One at a Time' enable this so each model will have its own adjustments. The models are treated as if they are all the same. If you have different models and model heights you will need to experiment. NOTE: This setting has no effect on 'All at Once' prints.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "taz_enabled"
|
||||
},
|
||||
"by_layer_or_height": {
|
||||
"label": "'By Layer' or 'By Height'",
|
||||
"description": "Which criteria to use to start and end the changes.",
|
||||
|
|
@ -352,13 +364,6 @@ class TweakAtZ(Script):
|
|||
Logger.log("i", "[Tweak at Z] is not enabled")
|
||||
return data
|
||||
|
||||
# Message the user and exit if the print sequence is 'One at a Time'
|
||||
if self.global_stack.getProperty("print_sequence", "value") == "one_at_a_time":
|
||||
Message(title = "[Tweak at Z]", text = "One-at-a-Time mode is not supported. The script will exit without making any changes.").show()
|
||||
data[0] += "; [Tweak at Z] Did not run (One at a Time mode is not supported)\n"
|
||||
Logger.log("i", "TweakAtZ does not support 'One at a Time' mode")
|
||||
return data
|
||||
|
||||
# Exit if the gcode has been previously post-processed.
|
||||
if ";POSTPROCESSED" in data[0]:
|
||||
return data
|
||||
|
|
@ -375,6 +380,11 @@ class TweakAtZ(Script):
|
|||
self.orig_bv_temp = self.global_stack.getProperty("build_volume_temperature", "value")
|
||||
self.z_hop_enabled = bool(self.extruder_list[0].getProperty("retraction_hop_enabled", "value"))
|
||||
self.raft_enabled = True if str(self.global_stack.getProperty("adhesion_type", "value")) == "raft" else False
|
||||
|
||||
# Script settings
|
||||
self.print_sequence = self.global_stack.getProperty("print_sequence", "value")
|
||||
self.by_layer_or_height = self.getSettingValueByKey("by_layer_or_height")
|
||||
|
||||
# The Start and end layer numbers are used when 'By Layer' is selected
|
||||
self.start_layer = self.getSettingValueByKey("a_start_layer") - 1
|
||||
end_layer = int(self.getSettingValueByKey("a_end_layer"))
|
||||
|
|
@ -451,9 +461,34 @@ class TweakAtZ(Script):
|
|||
}
|
||||
|
||||
# Run the selected procedures
|
||||
for setting, method in procedures.items():
|
||||
if self.getSettingValueByKey(setting):
|
||||
method(data)
|
||||
if self.print_sequence == "all_at_once":
|
||||
for setting, method in procedures.items():
|
||||
if self.getSettingValueByKey(setting):
|
||||
method(data)
|
||||
elif self.print_sequence == "one_at_a_time" and bool(self.getSettingValueByKey("enable_one_at_a_time_mode")):
|
||||
# Put together a list of the starts and ends of each model on the build plate.
|
||||
starts_and_ends = self.one_at_a_time_lists(data)
|
||||
# To accommodate existing code the temp_start and temp_end were necessary
|
||||
temp_start = self.start_index
|
||||
temp_end = self.end_index
|
||||
|
||||
"""
|
||||
Make adjustments to the start and end indexes based on the indexes of the LAYER:0's
|
||||
This was required to get One at a Time to work with By Height and By Layer.
|
||||
"""
|
||||
for num in range(0, len(self.start_list)):
|
||||
self.start_index = self.start_list[num] + temp_start - self.print_start_adj
|
||||
if end_layer != -1 or self.by_layer_or_height == "by_height":
|
||||
self.end_index = self.start_list[num] + temp_end - self.print_start_adj
|
||||
elif end_layer == -1 and self.by_layer_or_height == "by_layer":
|
||||
self.end_index = self.end_list[num]
|
||||
# Run each procedure with different starts and ends
|
||||
for setting, method in procedures.items():
|
||||
if self.getSettingValueByKey(setting):
|
||||
method(data)
|
||||
self.start_index = temp_start
|
||||
self.end_index = temp_end
|
||||
|
||||
data = self._format_lines(data)
|
||||
return data
|
||||
|
||||
|
|
@ -744,10 +779,6 @@ class TweakAtZ(Script):
|
|||
if not self.retract_enabled:
|
||||
return
|
||||
|
||||
# Exit if neither child setting is checked.
|
||||
if not (change_retract_amt or change_retract_speed):
|
||||
return
|
||||
|
||||
speed_retract_0 = int(self.extruder_list[0].getProperty("retraction_speed", "value") * 60)
|
||||
retract_amt_0 = self.extruder_list[0].getProperty("retraction_amount", "value")
|
||||
change_retract_amt = self.getSettingValueByKey("g_change_retract_amount")
|
||||
|
|
@ -755,6 +786,10 @@ class TweakAtZ(Script):
|
|||
new_retract_speed = int(self.getSettingValueByKey("g_retract_speed") * 60)
|
||||
new_retract_amt = self.getSettingValueByKey("g_retract_amount")
|
||||
|
||||
# Exit if neither child setting is checked.
|
||||
if not (change_retract_amt or change_retract_speed):
|
||||
return
|
||||
|
||||
# Use M207 and M208 to adjust firmware retraction when required
|
||||
if self.firmware_retraction:
|
||||
lines = data[self.start_index].splitlines()
|
||||
|
|
@ -987,3 +1022,23 @@ class TweakAtZ(Script):
|
|||
|
||||
def _f_x_y_not_z(self, line):
|
||||
return " F" in line and " X" in line and " Y" in line and not " Z" in line
|
||||
|
||||
def one_at_a_time_lists(self, data):
|
||||
"""
|
||||
This puts together a list of starts and their related list of ends.
|
||||
This is required for One-at-a-Time mode.
|
||||
"""
|
||||
self.start_list = []
|
||||
self.end_list = []
|
||||
for index, layer in enumerate(data):
|
||||
if index < 2 or index > len(data) - 1:
|
||||
continue
|
||||
if ";LAYER:0" in layer:
|
||||
self.start_list.append(index)
|
||||
self.end_list.append(index - 1)
|
||||
if "M140 S0" in layer:
|
||||
self.end_list.append(index-1)
|
||||
break
|
||||
# Delete the initial stop index as it is not required. This also leaves both lists the same length.
|
||||
self.end_list.pop(0)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from UM.Logger import Logger
|
|||
class ZHopOnTravel(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Z-Hop on Travel",
|
||||
|
|
@ -40,7 +40,7 @@ class ZHopOnTravel(Script):
|
|||
"settings": {
|
||||
"zhop_travel_enabled": {
|
||||
"label": "Enable script",
|
||||
"description": "Enables the script so it will run. 'One-at-a-Time' is not supported. This script is slow running because it must check the length of all travel moves in your layer range. ",
|
||||
"description": "Enables the script so it will run. 'One-at-a-Time' is not supported. This script is slow running because it must check the length of all travel moves in your layer range.",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"enabled": true
|
||||
|
|
@ -112,10 +112,17 @@ class ZHopOnTravel(Script):
|
|||
},
|
||||
"infill_only": {
|
||||
"label": "Add Z-hops to Infill Only",
|
||||
"description": "Only add Z-hops to 'Infill' within the layer range. (NOTE: For technical reasons it is not possible to add Z-hops to travel moves that start somewhere and just 'cross infill'.)",
|
||||
"description": "Only add Z-hops to 'Infill' within the layer range. (NOTE1: For technical reasons it is not possible to add Z-hops to travel moves that start somewhere and just 'move across infill'.) (NOTE2: You may use 'Infill Only' or 'Interface Only', but not both in a single instance of this post-processor. If you want both then add another instance.)",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "zhop_travel_enabled"
|
||||
"enabled": "zhop_travel_enabled and not interface_only"
|
||||
},
|
||||
"interface_only": {
|
||||
"label": "Add Z-hops to Support Interface Only",
|
||||
"description": "Only add Z-hops to 'Support Interface' within the layer range. (NOTE1: For technical reasons it is not possible to add Z-hops to travel moves that start somewhere and just 'cross the interface'.) (NOTE2: You may use 'Infill Only' or 'Interface Only', but not both in a single instance of this post-processor. If you want both then add another instance.)",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "zhop_travel_enabled and not infill_only"
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
|
@ -176,6 +183,7 @@ class ZHopOnTravel(Script):
|
|||
hop_height = round(self.getSettingValueByKey("hop_height"),2)
|
||||
list_or_range = self.getSettingValueByKey("list_or_range")
|
||||
infill_only = self.getSettingValueByKey("infill_only")
|
||||
interface_only = self.getSettingValueByKey("interface_only")
|
||||
layer_list = []
|
||||
index_list = []
|
||||
|
||||
|
|
@ -250,6 +258,7 @@ class ZHopOnTravel(Script):
|
|||
|
||||
# Make the insertions
|
||||
in_the_infill = False
|
||||
in_the_interface = False
|
||||
for num in range(start_index, len(data)-1):
|
||||
# Leave if the num > highest index number to speed up the script.
|
||||
if num > index_list[len(index_list)-1]:
|
||||
|
|
@ -272,6 +281,10 @@ class ZHopOnTravel(Script):
|
|||
in_the_infill = False
|
||||
if line.startswith(";TYPE:FILL"):
|
||||
in_the_infill = True
|
||||
if line.startswith(";") and in_the_interface == True:
|
||||
in_the_interface = False
|
||||
if line.startswith(";TYPE:SUPPORT-INTERFACE"):
|
||||
in_the_interface = True
|
||||
if line.startswith("G92") and " E" in line:
|
||||
self._cur_e = self.getValue(line, "E")
|
||||
self._prev_e = self._cur_e
|
||||
|
|
@ -313,6 +326,9 @@ class ZHopOnTravel(Script):
|
|||
if infill_only and not in_the_infill:
|
||||
hop_start = 0
|
||||
hop_end = 0
|
||||
if interface_only and not in_the_interface:
|
||||
hop_start = 0
|
||||
hop_end = 0
|
||||
if hop_start > 0:
|
||||
# For any lines that are XYZ moves right before layer change
|
||||
if " Z" in line:
|
||||
|
|
|
|||
|
|
@ -181,10 +181,16 @@ class CloudApiClient:
|
|||
|
||||
body = json.dumps({"data": data}).encode() if data else b""
|
||||
url = f"{self.CLUSTER_API_ROOT}/clusters/{cluster_id}/print_jobs/{cluster_job_id}/action/{action}"
|
||||
|
||||
def on_error(cloud_error: CloudError, error: "QNetworkReply.NetworkError", http_code: int):
|
||||
cloud_error_str = f"{cloud_error.title} (id:{cloud_error.id} code:{cloud_error.code}) {cloud_error.detail} ({cloud_error.meta})"
|
||||
Logger.warning(f"CloudApiClient.doPrintJobAction failed for {url} with {http_code}: {cloud_error_str}")
|
||||
|
||||
self._http.post(url,
|
||||
scope=self._scope,
|
||||
data=body,
|
||||
timeout=self.DEFAULT_REQUEST_TIMEOUT)
|
||||
timeout=self.DEFAULT_REQUEST_TIMEOUT,
|
||||
error_callback=self._parseError(on_error))
|
||||
|
||||
def _createEmptyRequest(self, path: str, content_type: Optional[str] = "application/json") -> QNetworkRequest:
|
||||
"""We override _createEmptyRequest in order to add the user credentials.
|
||||
|
|
|
|||
|
|
@ -90,19 +90,22 @@ class ClusterApiClient:
|
|||
"""Move a print job to the top of the queue."""
|
||||
|
||||
url = "{}/print_jobs/{}/action/move".format(self.CLUSTER_API_PREFIX, print_job_uuid)
|
||||
self._manager.post(self.createEmptyRequest(url), json.dumps({"to_position": 0, "list": "queued"}).encode())
|
||||
reply = self._manager.post(self.createEmptyRequest(url), json.dumps({"to_position": 0, "list": "queued"}).encode())
|
||||
self._trackReply(reply)
|
||||
|
||||
def forcePrintJob(self, print_job_uuid: str) -> None:
|
||||
"""Override print job configuration and force it to be printed."""
|
||||
|
||||
url = "{}/print_jobs/{}".format(self.CLUSTER_API_PREFIX, print_job_uuid)
|
||||
self._manager.put(self.createEmptyRequest(url), json.dumps({"force": True}).encode())
|
||||
reply = self._manager.put(self.createEmptyRequest(url), json.dumps({"force": True}).encode())
|
||||
self._trackReply(reply)
|
||||
|
||||
def deletePrintJob(self, print_job_uuid: str) -> None:
|
||||
"""Delete a print job from the queue."""
|
||||
|
||||
url = "{}/print_jobs/{}".format(self.CLUSTER_API_PREFIX, print_job_uuid)
|
||||
self._manager.deleteResource(self.createEmptyRequest(url))
|
||||
reply = self._manager.deleteResource(self.createEmptyRequest(url))
|
||||
self._trackReply(reply)
|
||||
|
||||
def setPrintJobState(self, print_job_uuid: str, state: str) -> None:
|
||||
"""Set the state of a print job."""
|
||||
|
|
@ -110,7 +113,8 @@ class ClusterApiClient:
|
|||
url = "{}/print_jobs/{}/action".format(self.CLUSTER_API_PREFIX, print_job_uuid)
|
||||
# We rewrite 'resume' to 'print' here because we are using the old print job action endpoints.
|
||||
action = "print" if state == "resume" else state
|
||||
self._manager.put(self.createEmptyRequest(url), json.dumps({"action": action}).encode())
|
||||
reply = self._manager.put(self.createEmptyRequest(url), json.dumps({"action": action}).encode())
|
||||
self._trackReply(reply)
|
||||
|
||||
def getPrintJobPreviewImage(self, print_job_uuid: str, on_finished: Callable) -> None:
|
||||
"""Get the preview image data of a print job."""
|
||||
|
|
@ -169,6 +173,25 @@ class ClusterApiClient:
|
|||
except (JSONDecodeError, TypeError, ValueError):
|
||||
Logger.log("e", "Could not parse response from network: %s", str(response))
|
||||
|
||||
def _trackReply(self, reply: QNetworkReply) -> None:
|
||||
"""Track a reply to prevent garbage collection and ensure proper completion.
|
||||
|
||||
Use this for fire-and-forget requests that don't need response handling.
|
||||
:param reply: The reply that should be tracked.
|
||||
"""
|
||||
|
||||
def cleanup() -> None:
|
||||
try:
|
||||
self._anti_gc_callbacks.remove(cleanup)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
if reply.error() != QNetworkReply.NetworkError.NoError:
|
||||
Logger.warning(f"Cluster API request error: {reply.errorString()}")
|
||||
|
||||
self._anti_gc_callbacks.append(cleanup)
|
||||
reply.finished.connect(cleanup)
|
||||
|
||||
def _addCallback(self, reply: QNetworkReply, on_finished: Union[Callable[[ClusterApiClientModel], Any],
|
||||
Callable[[List[ClusterApiClientModel]], Any]], model: Type[ClusterApiClientModel] = None,
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
# Copyright (c) 2026 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import configparser
|
||||
import io
|
||||
from typing import Tuple, List
|
||||
|
||||
from UM.VersionUpgrade import VersionUpgrade
|
||||
|
||||
_REMOVED_SETTINGS = {
|
||||
"skin_edge_support_thickness",
|
||||
"skin_edge_support_layers",
|
||||
"extra_infill_lines_to_support_skins",
|
||||
"bridge_sparse_infill_max_density",
|
||||
}
|
||||
|
||||
_HIGH_SPEED_PRINTERS = {
|
||||
"ultimaker_factor4",
|
||||
}
|
||||
|
||||
_OVERLAPPING_INFILLS = {
|
||||
"grid",
|
||||
"triangles",
|
||||
"cubic"
|
||||
}
|
||||
|
||||
_NEW_SETTING_VERSION = "26"
|
||||
|
||||
|
||||
class VersionUpgrade511to512(VersionUpgrade):
|
||||
def upgradePreferences(self, serialized: str, filename: str):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialized)
|
||||
|
||||
# Update version number.
|
||||
parser["metadata"]["setting_version"] = _NEW_SETTING_VERSION
|
||||
|
||||
# Remove deleted settings from the visible settings list.
|
||||
if "general" in parser and "visible_settings" in parser["general"]:
|
||||
visible_settings = set(parser["general"]["visible_settings"].split(";"))
|
||||
for removed in _REMOVED_SETTINGS:
|
||||
if removed in visible_settings:
|
||||
visible_settings.remove(removed)
|
||||
|
||||
parser["general"]["visible_settings"] = ";".join(visible_settings)
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
|
||||
def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
|
||||
parser = configparser.ConfigParser(interpolation = None, comment_prefixes = ())
|
||||
parser.read_string(serialized)
|
||||
|
||||
# Update version number.
|
||||
parser["metadata"]["setting_version"] = _NEW_SETTING_VERSION
|
||||
|
||||
if "values" in parser:
|
||||
# Enable the new skin_support based on the value of bridge_sparse_infill_max_density
|
||||
if "bridge_sparse_infill_max_density" in parser["values"]:
|
||||
parser["values"]["skin_support"] = f"=infill_sparse_density < {parser["values"]["bridge_sparse_infill_max_density"]}"
|
||||
|
||||
# Remove deleted settings from the instance containers.
|
||||
for removed in _REMOVED_SETTINGS:
|
||||
if removed in parser["values"]:
|
||||
del parser["values"][removed]
|
||||
|
||||
# Force honeycomb infill pattern for high speed printers if using an overlapping pattern
|
||||
printer_definition = ""
|
||||
if "general" in parser and "definition" in parser["general"]:
|
||||
printer_definition = parser["general"]["definition"]
|
||||
|
||||
infill_pattern = ""
|
||||
if "infill_pattern" in parser["values"]:
|
||||
infill_pattern = parser["values"]["infill_pattern"]
|
||||
|
||||
if printer_definition in _HIGH_SPEED_PRINTERS and infill_pattern in _OVERLAPPING_INFILLS:
|
||||
parser["values"]["infill_pattern"] = "honeycomb"
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
|
||||
def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialized)
|
||||
|
||||
# Update version number.
|
||||
if "metadata" not in parser:
|
||||
parser["metadata"] = {}
|
||||
|
||||
parser["metadata"]["setting_version"] = _NEW_SETTING_VERSION
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
60
plugins/VersionUpgrade/VersionUpgrade511to512/__init__.py
Normal file
60
plugins/VersionUpgrade/VersionUpgrade511to512/__init__.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (c) 2026 UltiMaker
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import Any, Dict, TYPE_CHECKING
|
||||
|
||||
from . import VersionUpgrade511to512
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Application import Application
|
||||
|
||||
upgrade = VersionUpgrade511to512.VersionUpgrade511to512()
|
||||
|
||||
def getMetaData() -> Dict[str, Any]:
|
||||
return {
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("preferences", 7000025): ("preferences", 7000026, upgrade.upgradePreferences),
|
||||
("machine_stack", 6000025): ("machine_stack", 6000026, upgrade.upgradeStack),
|
||||
("extruder_train", 6000025): ("extruder_train", 6000026, upgrade.upgradeStack),
|
||||
("definition_changes", 4000025): ("definition_changes", 4000026, upgrade.upgradeInstanceContainer),
|
||||
("quality_changes", 4000025): ("quality_changes", 4000026, upgrade.upgradeInstanceContainer),
|
||||
("quality", 4000025): ("quality", 4000026, upgrade.upgradeInstanceContainer),
|
||||
("user", 4000025): ("user", 4000026, upgrade.upgradeInstanceContainer),
|
||||
("intent", 4000025): ("intent", 4000026, upgrade.upgradeInstanceContainer),
|
||||
},
|
||||
"sources": {
|
||||
"preferences": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"."}
|
||||
},
|
||||
"machine_stack": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./machine_instances"}
|
||||
},
|
||||
"extruder_train": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./extruders"}
|
||||
},
|
||||
"definition_changes": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./definition_changes"}
|
||||
},
|
||||
"quality_changes": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./quality_changes"}
|
||||
},
|
||||
"quality": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./quality"}
|
||||
},
|
||||
"user": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./user"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def register(app: "Application") -> Dict[str, Any]:
|
||||
return {"version_upgrade": upgrade}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Version Upgrade 5.11 to 5.12",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"description": "Upgrades configurations from Cura 5.11 to Cura 5.12",
|
||||
"api": 8,
|
||||
"i18n-catalog": "cura"
|
||||
}
|
||||
126
resources/definitions/elegoo_centauri_carbon.def.json
Normal file
126
resources/definitions/elegoo_centauri_carbon.def.json
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "ELEGOO Centauri Carbon",
|
||||
"inherits": "elegoo_base",
|
||||
"metadata":
|
||||
{
|
||||
"visible": true,
|
||||
"author": "Steven Molen",
|
||||
"manufacturer": "ELEGOO",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "elegoo_platform.3mf",
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
"has_variants": true,
|
||||
"machine_extruder_trains": { "0": "elegoo_centauri_carbon_extruder_0" },
|
||||
"preferred_material": "generic_pla_175",
|
||||
"preferred_quality_type": "elegoo_cc_layer_020",
|
||||
"preferred_variant_name": "0.40mm_Elegoo_Nozzle",
|
||||
"variants_name": "Nozzle Size"
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"machine_name": { "default_value": "ELEGOO Centauri Carbon" },
|
||||
"machine_width": { "default_value": 257 },
|
||||
"machine_depth": { "default_value": 257 },
|
||||
"machine_height": { "default_value": 257 },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_head_with_fans_polygon":
|
||||
{
|
||||
"value": [
|
||||
[-57, 68],
|
||||
[-57, -57],
|
||||
[57, 68],
|
||||
[57, -57]
|
||||
]
|
||||
},
|
||||
"gantry_height": { "value": 90 },
|
||||
|
||||
"machine_max_acceleration_x": { "value": 20000 },
|
||||
"machine_max_acceleration_y": { "value": 20000 },
|
||||
"machine_max_acceleration_z": { "value": 500 },
|
||||
"machine_max_acceleration_e": { "value": 5000 },
|
||||
"machine_acceleration": { "value": 10000 },
|
||||
"machine_max_jerk_xy": { "value": 9.0 },
|
||||
"machine_max_jerk_z": { "value": 3.0 },
|
||||
"machine_max_jerk_e": { "value": 2.5 },
|
||||
|
||||
"acceleration_print":
|
||||
{
|
||||
"value": 10000,
|
||||
"maximum_value_warning": 20000
|
||||
},
|
||||
"acceleration_wall": { "value": "acceleration_print / 2" },
|
||||
"acceleration_layer_0": { "value": 1000 },
|
||||
|
||||
"speed_print":
|
||||
{
|
||||
"default_value": 200,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_wall_0":
|
||||
{
|
||||
"value": 160,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_wall_x":
|
||||
{
|
||||
"value": 200,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_infill":
|
||||
{
|
||||
"value": 200,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_topbottom":
|
||||
{
|
||||
"value": 150,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_travel":
|
||||
{
|
||||
"value": 400,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_layer_0":
|
||||
{
|
||||
"value": 50,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_travel_layer_0":
|
||||
{
|
||||
"value": 100,
|
||||
"maximum_value_warning": 500
|
||||
},
|
||||
"speed_support_interface": { "value": 80, "maximum_value_warning": 500 },
|
||||
|
||||
"retraction_amount": { "default_value": 0.8 },
|
||||
"retraction_speed": { "default_value": 30 },
|
||||
"retraction_retract_speed": { "value": 30 },
|
||||
"retraction_prime_speed": { "value": 30 },
|
||||
"retraction_hop": { "value": 0.4 },
|
||||
"retraction_hop_enabled": { "value": true },
|
||||
"retraction_count_max": { "value": 100 },
|
||||
"retraction_combing": { "value": "'no_outer_surfaces'" },
|
||||
|
||||
"infill_pattern": { "value": "'zigzag'" },
|
||||
"top_layers": { "value": 5 },
|
||||
"bottom_layers": { "value": 3 },
|
||||
"top_bottom_thickness": { "value": 1.0 },
|
||||
|
||||
"support_angle": { "value": 40 },
|
||||
"support_z_distance": { "value": 0.15 },
|
||||
"support_xy_distance": { "value": 0.5 },
|
||||
"support_interface_enable": { "value": true },
|
||||
|
||||
"adhesion_type": { "value": "'skirt'" },
|
||||
"skirt_line_count": { "value": 2 },
|
||||
"skirt_gap": { "value": 2 },
|
||||
|
||||
"machine_start_gcode": { "default_value": ";;===== Elegoo Centauri Carbon Start G-code =====\n;printer_model:ELEGOO Centauri Carbon\nM400 ; wait for buffer to clear\nM220 S100 ;Set the feed speed to 100%\nM221 S100 ;Set the flow rate to 100%\nM104 S140\nM140 S{material_bed_temperature_layer_0}\nG90\nG28 ;home\nM729 ;Clean Nozzle\nM106 P2 S255\nM190 S{material_bed_temperature_layer_0}\nM106 P2 S0\n\n;=============turn on fans to prevent PLA jamming=================\nM106 P3 S180\n\n;Enable pressure advance\nSET_PRESSURE_ADVANCE ADVANCE=0.024\nM400\nM204 S10000 ;Set acceleration\n\nG1 X128 Y-1.2 F20000\nG1 Z0.3 F900\nM109 S{material_print_temperature_layer_0}\nM83\nG92 E0 ;Reset Extruder\n;Purge line - values from official Elegoo config\nG1 X-1.2 E10.156 F6000 ;Draw the first line\nG1 Y98.8 E7.934\nG1 X-0.5 Y100 E0.1\nG1 Y-0.3 E7.934\nG1 X78 E6.284\nG3 I-1 J0 Z0.6 F1200.0 ;Move to side a little\nG1 F20000\nG92 E0 ;Reset Extruder\n" },
|
||||
|
||||
"machine_end_gcode": { "default_value": ";===== Elegoo Centauri Carbon End G-code =====\nM400 ; wait for buffer to clear\nM140 S0 ;Turn-off bed\nM106 S255 ;Cooling nozzle\nM83\nG92 E0 ; zero the extruder\nG1 E-1 F3000 ; retract\nG90\nG1 Z{max(layer_height * (layer_count - 1) + 50, 100)} F20000 ; Move print head up\nM204 S5000\nM400\nM83\nG1 X202 F20000\nM400\nG1 Y250 F20000\nG1 Y255 F1200\nM400\nG92 E0\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\nM84 ;Disable all steppers" }
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
"author": "Ultimaker",
|
||||
"manufacturer": "Unknown",
|
||||
"position": "0",
|
||||
"setting_version": 25,
|
||||
"setting_version": 26,
|
||||
"type": "extruder"
|
||||
},
|
||||
"settings":
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"type": "machine",
|
||||
"author": "Unknown",
|
||||
"manufacturer": "Unknown",
|
||||
"setting_version": 25,
|
||||
"setting_version": 26,
|
||||
"file_formats": "text/x-gcode;model/stl;application/x-wavefront-obj;application/x3g",
|
||||
"visible": false,
|
||||
"has_materials": true,
|
||||
|
|
@ -2189,7 +2189,7 @@
|
|||
"default_value": 2,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "infill_line_width",
|
||||
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else (1 if infill_pattern == 'cross' or infill_pattern == 'cross_3d' else (1.6 if infill_pattern == 'lightning' else 1)))))",
|
||||
"value": "0 if infill_sparse_density == 0 else (((infill_line_width * 100) / infill_sparse_density) * (((4/3) - (1/3) * (infill_sparse_density / 100.0)) if infill_pattern in ['honeycomb', 'octagon'] else (2 if infill_pattern == 'grid' else (3 if infill_pattern in ['triangles', 'trihexagon', 'cubic', 'cubicsubdiv'] else (2 if infill_pattern in ['tetrahedral', 'quarter_cubic'] else (1 if infill_pattern in ['cross', 'cross_3d'] else (1.6 if infill_pattern == 'lightning' else 1)))))))",
|
||||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
|
|
@ -2198,15 +2198,12 @@
|
|||
"infill_pattern":
|
||||
{
|
||||
"label": "Infill Pattern",
|
||||
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction. Lightning infill tries to minimize the infill, by only supporting the ceiling of the object.",
|
||||
"description": "<html>The pattern of the infill material of the print.<ul><li>The Line and Zig Zag infill swap direction on alternate layers, reducing material cost.</li><li>The Grid, Triangle, Tri-Hexagon, Cubic, Octet, Quarter Cubic, Cross, and Concentric patterns are fully printed every layer.</li><li>Gyroid, Honeycomb, Octagon, Cubic, Quarter Cubic, and Octet infill change with every layer to provide a more equal distribution of strength over each direction.</li><li>Lightning infill tries to minimize the infill, by only supporting the ceiling of the object.</li></ul>\u26a0 Grid, Triangles, and Cubic infill patterns contain intersecting lines, that may cause your nozzle to bump into printed lines, and your printer to vibrate. Use with caution.<br/></html>",
|
||||
"type": "enum",
|
||||
"options":
|
||||
{
|
||||
"grid": "Grid",
|
||||
"lines": "Lines",
|
||||
"triangles": "Triangles",
|
||||
"trihexagon": "Tri-Hexagon",
|
||||
"cubic": "Cubic",
|
||||
"cubicsubdiv": "Cubic Subdivision",
|
||||
"tetrahedral": "Octet",
|
||||
"quarter_cubic": "Quarter Cubic",
|
||||
|
|
@ -2215,7 +2212,12 @@
|
|||
"cross": "Cross",
|
||||
"cross_3d": "Cross 3D",
|
||||
"gyroid": "Gyroid",
|
||||
"lightning": "Lightning"
|
||||
"lightning": "Lightning",
|
||||
"honeycomb": "Honeycomb",
|
||||
"octagon": "Octagon",
|
||||
"grid": "Grid",
|
||||
"cubic": "Cubic",
|
||||
"triangles": "Triangles"
|
||||
},
|
||||
"default_value": "grid",
|
||||
"enabled": "infill_line_distance > 0",
|
||||
|
|
@ -2230,7 +2232,7 @@
|
|||
"type": "bool",
|
||||
"default_value": false,
|
||||
"value": "infill_pattern == 'cross' or infill_pattern == 'cross_3d'",
|
||||
"enabled": "infill_pattern == 'lines' or infill_pattern == 'grid' or infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' or infill_pattern == 'cross' or infill_pattern == 'cross_3d' or infill_pattern == 'gyroid'",
|
||||
"enabled": "infill_pattern == 'lines' or infill_pattern == 'grid' or infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' or infill_pattern == 'cross' or infill_pattern == 'cross_3d' or infill_pattern == 'gyroid' or infill_pattern == 'honeycomb' or infill_pattern == 'octagon'",
|
||||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
|
|
@ -2251,7 +2253,8 @@
|
|||
"description": "A list of integer line directions to use. Elements from the list are used sequentially as the layers progress and when the end of the list is reached, it starts at the beginning again. The list items are separated by commas and the whole list is contained in square brackets. Default is an empty list which means use the traditional default angles (45 and 135 degrees for the lines and zig zag patterns and 45 degrees for all other patterns).",
|
||||
"type": "[int]",
|
||||
"default_value": "[ ]",
|
||||
"enabled": "infill_pattern not in ('concentric', 'cross', 'cross_3d', 'gyroid', 'lightning') and infill_sparse_density > 0",
|
||||
"value": "[0, 90] if infill_pattern == 'octagon' else [0, 60, 120] if infill_pattern == 'honeycomb' else [0] if infill_pattern == 'gyroid' else [ ]",
|
||||
"enabled": "infill_pattern not in ('concentric', 'cross', 'cross_3d', 'lightning') and infill_sparse_density > 0",
|
||||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
|
|
@ -2462,7 +2465,7 @@
|
|||
"description": "Print a solid infill pattern just below skin to avoid printing the skin over air.",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"value": "infill_sparse_density < 50",
|
||||
"value": "infill_sparse_density < 40",
|
||||
"enabled": "infill_sparse_density > 0 and top_layers > 0",
|
||||
"settable_per_mesh": true,
|
||||
"settable_per_extruder": true
|
||||
|
|
@ -4816,7 +4819,7 @@
|
|||
"retraction_combing_avoid_distance":
|
||||
{
|
||||
"label": "Inside Travel Avoid Distance",
|
||||
"description": "The distance between the nozzle and already printed outer walls when travelling inside a model.",
|
||||
"description": "The distance between the nozzle and outer walls when travelling inside a model.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0.6,
|
||||
|
|
@ -5575,7 +5578,9 @@
|
|||
"concentric": "Concentric",
|
||||
"zigzag": "Zig Zag",
|
||||
"cross": "Cross",
|
||||
"gyroid": "Gyroid"
|
||||
"gyroid": "Gyroid",
|
||||
"honeycomb": "Honeycomb",
|
||||
"octagon": "Octagon"
|
||||
},
|
||||
"default_value": "zigzag",
|
||||
"enabled": "support_enable or support_meshes_present",
|
||||
|
|
@ -5656,8 +5661,8 @@
|
|||
"description": "Connect the ends of the support lines together. Enabling this setting can make your support more sturdy and reduce underextrusion, but it will cost more material.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"value": "support_pattern == 'cross' or support_pattern == 'gyroid'",
|
||||
"enabled": "(support_enable or support_meshes_present) and (support_pattern == 'lines' or support_pattern == 'grid' or support_pattern == 'triangles' or support_pattern == 'cross' or support_pattern == 'gyroid')",
|
||||
"value": "support_pattern == 'cross' or support_pattern == 'gyroid' or support_pattern == 'honeycomb' or support_pattern == 'octagon'",
|
||||
"enabled": "(support_enable or support_meshes_present) and (support_pattern == 'lines' or support_pattern == 'grid' or support_pattern == 'triangles' or support_pattern == 'cross' or support_pattern == 'gyroid' or support_pattern == 'honeycomb' or support_pattern == 'octagon')",
|
||||
"limit_to_extruder": "support_infill_extruder_nr",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": true
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
"gantry_height": { "value": 35 },
|
||||
"gradual_support_infill_steps": { "value": "3 if support_interface_enable and support_structure != 'tree' else 0" },
|
||||
"group_outer_walls": { "value": "False" },
|
||||
"infill_angles": { "value": "[-40, 50] if infill_pattern in ('grid', 'lines', 'zigzag') else [ ]" },
|
||||
"infill_angles": { "value": "[-40, 50] if infill_pattern in ('grid', 'lines', 'zigzag') else [0, 60, 120] if infill_pattern == 'honeycomb' else [ ]" },
|
||||
"infill_before_walls": { "value": "False if infill_sparse_density > 50 else True" },
|
||||
"infill_enable_travel_optimization": { "value": "True" },
|
||||
"infill_material_flow":
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
"value": "(1 + (skin_material_flow-infill_sparse_density) / 100 if infill_sparse_density > skin_material_flow else 1) * material_flow"
|
||||
},
|
||||
"infill_overlap": { "value": "0" },
|
||||
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 50 else 'gyroid' if 15 < speed_infill / ( infill_line_width * 300 / infill_sparse_density ) < 25 else 'triangles'" },
|
||||
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 50 else 'honeycomb'" },
|
||||
"infill_sparse_density": { "maximum_value": "100" },
|
||||
"infill_wipe_dist": { "value": "0" },
|
||||
"inset_direction": { "value": "'inside_out'" },
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@
|
|||
"machine_start_gcode": { "default_value": "G0 Z20" },
|
||||
"machine_width": { "default_value": 283.3 },
|
||||
"material_bed_temperature": { "enabled": "machine_heated_bed" },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"material_final_print_temperature":
|
||||
{
|
||||
"maximum_value": "material_print_temperature",
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@
|
|||
"infill_material_flow": { "value": "material_flow if infill_sparse_density < 95 else 95" },
|
||||
"infill_move_inwards_length": { "value": "3*machine_nozzle_size" },
|
||||
"infill_overlap": { "value": 10 },
|
||||
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 50 else 'grid'" },
|
||||
"infill_pattern": { "value": "'zigzag'" },
|
||||
"infill_sparse_density": { "value": 15 },
|
||||
"infill_wall_line_count": { "value": "1 if infill_sparse_density > 80 else 0" },
|
||||
"initial_bottom_layers": { "value": "2 if extruderValueFromContainer(top_bottom_extruder_nr, 'bottom_layers', 2) == bottom_layers else bottom_layers" },
|
||||
|
|
@ -425,7 +425,7 @@
|
|||
"material_pressure_advance_factor":
|
||||
{
|
||||
"enabled": true,
|
||||
"value": 0.5
|
||||
"value": 0.75
|
||||
},
|
||||
"material_print_temperature": { "maximum_value_warning": 320 },
|
||||
"material_print_temperature_layer_0": { "maximum_value_warning": 320 },
|
||||
|
|
@ -456,6 +456,7 @@
|
|||
"seam_overhang_angle": { "value": 35 },
|
||||
"skin_material_flow": { "value": 93 },
|
||||
"skin_outline_count": { "value": 0 },
|
||||
"skin_preshrink": { "value": 0 },
|
||||
"skin_support_speed": { "value": "speed_infill * infill_material_flow / skin_support_material_flow" },
|
||||
"skirt_brim_minimal_length": { "value": 1000 },
|
||||
"skirt_line_count": { "value": 5 },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata":
|
||||
{
|
||||
"machine": "elegoo_centauri_carbon",
|
||||
"position": "0"
|
||||
},
|
||||
"overrides":
|
||||
{
|
||||
"extruder_nr": { "default_value": 0 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"machine_nozzle_size": { "default_value": 0.4 },
|
||||
"machine_nozzle_offset_x": { "default_value": 0 },
|
||||
"machine_nozzle_offset_y": { "default_value": 0 }
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_abs
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_abs
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_abs
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_abs
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = DBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = D020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = D030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = FBE 0.40mm
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_005
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = quick
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_005
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = engineering
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_015
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = engineering
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_010
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = engineering
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = quick
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_020
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ intent_category = quick
|
|||
is_experimental = True
|
||||
material = generic_pla
|
||||
quality_type = Elegoo_layer_030
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = 0.40mm_Elegoo_Nozzle
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_abs
|
||||
quality_type = draft
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_abs
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_abs
|
||||
quality_type = high
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_abs
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_cpe
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_cpe
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_nylon
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_nylon
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pc
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pc
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_petg
|
||||
quality_type = draft
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_petg
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_petg
|
||||
quality_type = high
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_petg
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_petg
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = quick
|
||||
material = generic_pla
|
||||
quality_type = draft
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = fast
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = high
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_pla
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = VO 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_petg
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = AA 0.25
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_pla
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = AA 0.25
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = visual
|
||||
material = generic_tough_pla
|
||||
quality_type = normal
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = AA 0.25
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_abs
|
||||
quality_type = draft
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = AA 0.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ version = 4
|
|||
intent_category = engineering
|
||||
material = generic_asa
|
||||
quality_type = draft
|
||||
setting_version = 25
|
||||
setting_version = 26
|
||||
type = intent
|
||||
variant = AA 0.4
|
||||
|
||||
|
|
|
|||
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