Merge branch 'master' into quarter_cubic_infill

This commit is contained in:
Ghostkeeper 2017-08-30 11:03:04 +02:00
commit 2c7c29dc71
No known key found for this signature in database
GPG key ID: C5F96EE2BC0F7E75
224 changed files with 93289 additions and 70955 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@ __pycache__
docs/html
*.log
resources/i18n/en
resources/i18n/7s
resources/i18n/x-test
resources/firmware
resources/materials

4
Jenkinsfile vendored
View file

@ -15,13 +15,13 @@ parallel_nodes(['linux && cura', 'windows && cura']) {
// Perform the "build". Since Uranium is Python code, this basically only ensures CMake is setup.
stage('Build') {
def branch = env.BRANCH_NAME
if(!(branch =~ /^2.\d+$/)) {
if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) {
branch = "master"
}
// Ensure CMake is setup. Note that since this is Python code we do not really "build" it.
def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
cmake("..", "-DCMAKE_PREFIX_PATH=${env.CURA_ENVIRONMENT_PATH}/${branch} -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=${uranium_dir}")
cmake("..", "-DCMAKE_PREFIX_PATH=\"${env.CURA_ENVIRONMENT_PATH}/${branch}\" -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=\"${uranium_dir}\"")
}
// Try and run the unit tests. If this stage fails, we consider the build to be "unstable".

View file

@ -50,12 +50,11 @@ Third party plugins
* [X3G Writer](https://github.com/Ghostkeeper/X3GWriter): Adds support for exporting X3G files.
* [Auto orientation](https://github.com/nallath/CuraOrientationPlugin): Calculate the optimal orientation for a model.
* [OctoPrint Plugin](https://github.com/fieldofview/OctoPrintPlugin): Send printjobs directly to OctoPrint and monitor their progress in Cura.
* [WirelessPrinting Plugin](https://github.com/probonopd/WirelessPrinting): Print wirelessly from Cura to your 3D printer connected to an ESP8266 module.
* [Electric Print Cost Calculator Plugin](https://github.com/zoff99/ElectricPrintCostCalculator): Calculate the electric costs of a print.
Making profiles for other printers
----------------------------------
There are two ways of doing it. You can either use the generator [here](http://quillford.github.io/CuraProfileMaker/) or you can use [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original.def.json) as a template.
If your make of printer is not in the list of supported printers, and using the "Custom FDM Printer" does not offer enough flexibility, you can use [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original.def.json) as a template.
* Change the machine ID to something unique
* Change the machine_name to your printer's name
@ -63,12 +62,12 @@ There are two ways of doing it. You can either use the generator [here](http://q
* Set your machine's dimensions with machine_width, machine_depth, and machine_height
* If your printer's origin is in the center of the bed, set machine_center_is_zero to true.
* Set your print head dimensions with the machine_head_shape parameters
* Set the nozzle offset with machine_nozzle_offset_x and machine_nozzle_offset_y
* Set the start and end gcode in machine_start_gcode and machine_end_gcode
* If your printer has a heated bed, set visible to true under material_bed_temperature
Once you are done, put the profile you have made into resources/definitions, or in definitions in your cura profile folder.
If you want to make a definition for a multi-extrusion printer, have a look at [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original_dual.def.json) as a template, along with the two extruder definitions it references [here](https://github.com/Ultimaker/Cura/blob/master/resources/extruders/ultimaker_original_dual_1st.def.json) and [here](https://github.com/Ultimaker/Cura/blob/master/resources/extruders/ultimaker_original_dual_2nd.def.json)
Translating Cura
----------------
If you'd like to contribute a translation of Cura, please first look for [any existing translation](https://github.com/Ultimaker/Cura/tree/master/resources/i18n). If your language is already there in the source code but not in Cura's interface, it may be partially translated.
@ -89,4 +88,4 @@ To submit your translation, ideally you would make two pull requests where all `
After the translation is submitted, the Cura maintainers will check for its completeness and check whether it is consistent. We will take special care to look for common mistakes, such as translating mark-up `<message>` code and such. We are often not fluent in every language, so we expect the translator and the international users to make corrections where necessary. Of course, there will always be some mistakes in every translation.
When the next Cura release comes around, some of the texts will have changed and some new texts will have been added. Around the time when the beta is released we will invoke a string freeze, meaning that no developer is allowed to make changes to the texts. Then we will update the translation template `.pot` files and ask all our translators to update their translations. If you are unable to update the translation in time for the actual release, we will remove the language from the drop-down menu in the Preferences window. The translation stays in Cura however, so that someone might pick it up again later and update it with the newest texts. Also, users who had previously selected the language can still continue Cura in their language but English text will appear among the original text.
When the next Cura release comes around, some of the texts will have changed and some new texts will have been added. Around the time when the beta is released we will invoke a string freeze, meaning that no developer is allowed to make changes to the texts. Then we will update the translation template `.pot` files and ask all our translators to update their translations. If you are unable to update the translation in time for the actual release, we will remove the language from the drop-down menu in the Preferences window. The translation stays in Cura however, so that someone might pick it up again later and update it with the newest texts. Also, users who had previously selected the language can still continue Cura in their language but English text will appear among the original text.

View file

@ -7,9 +7,9 @@ Comment=Cura converts 3D models into paths for a 3D printer. It prepares your pr
Comment[de]=Cura wandelt 3D-Modelle in Pfade für einen 3D-Drucker um. Es bereitet Ihren Druck für maximale Genauigkeit, minimale Druckzeit und guter Zuverlässigkeit mit vielen zusätzlichen Funktionen vor, damit Ihr Druck großartig wird.
Exec=@CMAKE_INSTALL_FULL_BINDIR@/cura %F
TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
Icon=@CMAKE_INSTALL_FULL_DATADIR@/cura/resources/images/cura-icon.png
Icon=cura-icon
Terminal=false
Type=Application
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;
Categories=Graphics;
Keywords=3D;Printing;

View file

@ -1,4 +1,4 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from cura.Settings.ExtruderManager import ExtruderManager
@ -27,8 +27,9 @@ import math
from typing import List
# Setting for clearance around the prime
PRIME_CLEARANCE = 6.5
PRIME_CLEARANCE = 6.5 #Setting for clearance around the prime.
MAJOR_GRID_SIZE = 10 #Size of the grid cells.
MINOR_GRID_SIZE = 1
## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas.
@ -44,6 +45,8 @@ class BuildVolume(SceneNode):
self._z_axis_color = None
self._disallowed_area_color = None
self._error_area_color = None
self._grid_color = None
self._grid_minor_color = None
self._width = 0
self._height = 0
@ -56,8 +59,9 @@ class BuildVolume(SceneNode):
self._origin_line_length = 20
self._origin_line_width = 0.5
self._plate_mesh = None
self._grid_mesh = None
self._grid_shader = None
self._plate_shader = None
self._disallowed_areas = []
self._disallowed_area_mesh = None
@ -167,14 +171,15 @@ class BuildVolume(SceneNode):
if not self._shader:
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
self._grid_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "grid.shader"))
self._plate_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
theme = Application.getInstance().getTheme()
self._grid_shader.setUniformValue("u_gridColor0", Color(*theme.getColor("buildplate").getRgb()))
self._grid_shader.setUniformValue("u_gridColor1", Color(*theme.getColor("buildplate_alt").getRgb()))
self._plate_shader.setUniformValue("u_color", Color(*theme.getColor("buildplate").getRgb()))
self._plate_shader.setUniformValue("u_z_bias", 0.000001)
renderer.queueNode(self, mode = RenderBatch.RenderMode.Lines)
renderer.queueNode(self, mesh = self._origin_mesh)
renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
renderer.queueNode(self, mesh = self._plate_mesh, shader = self._plate_shader, backface_cull = True)
renderer.queueNode(self, mesh = self._grid_mesh, mode = RenderBatch.RenderMode.Lines, transparent = True)
if self._disallowed_area_mesh:
renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9)
@ -247,6 +252,8 @@ class BuildVolume(SceneNode):
self._z_axis_color = Color(*theme.getColor("z_axis").getRgb())
self._disallowed_area_color = Color(*theme.getColor("disallowed_area").getRgb())
self._error_area_color = Color(*theme.getColor("error_area").getRgb())
self._grid_color = Color(*theme.getColor("buildplate_grid").getRgb())
self._grid_minor_color = Color(*theme.getColor("buildplate_grid_minor").getRgb())
min_w = -self._width / 2
max_w = self._width / 2
@ -277,7 +284,7 @@ class BuildVolume(SceneNode):
self.setMeshData(mb.build())
# Build plate grid mesh
# Build plate surface.
mb = MeshBuilder()
mb.addQuad(
Vector(min_w, min_h - z_fight_distance, min_d),
@ -289,6 +296,30 @@ class BuildVolume(SceneNode):
for n in range(0, 6):
v = mb.getVertex(n)
mb.setVertexUVCoordinates(n, v[0], v[2])
self._plate_mesh = mb.build()
#Build plate grid mesh.
mb = MeshBuilder()
for x in range(0, int(math.ceil(max_w)), MAJOR_GRID_SIZE):
mb.addLine(Vector(x, min_h, min_d), Vector(x, min_h, max_d), color = self._grid_color)
#Start from 0 in both cases, so you need to do this in two for loops.
mb.addLine(Vector(-x, min_h, min_d), Vector(-x, min_h, max_d), color = self._grid_color)
for y in range(0, int(math.ceil(max_d)), MAJOR_GRID_SIZE):
mb.addLine(Vector(min_w, min_h, y), Vector(max_w, min_h, y), color = self._grid_color)
mb.addLine(Vector(min_w, min_h, -y), Vector(max_w, min_h, -y), color = self._grid_color)
#More fine grained grid.
for x in range(0, int(math.ceil(max_w)), MINOR_GRID_SIZE):
if x % MAJOR_GRID_SIZE == 0: #Don't overlap with the major grid.
pass
mb.addLine(Vector(x, min_h, min_d), Vector(x, min_h, max_d), color = self._grid_minor_color)
mb.addLine(Vector(-x, min_h, min_d), Vector(-x, min_h, max_d), color = self._grid_minor_color)
for y in range(0, int(math.ceil(max_d)), MINOR_GRID_SIZE):
if y % MAJOR_GRID_SIZE == 0:
pass
mb.addLine(Vector(min_w, min_h, y), Vector(max_w, min_h, y), color = self._grid_minor_color)
mb.addLine(Vector(min_w, min_h, -y), Vector(max_w, min_h, -y), color = self._grid_minor_color)
self._grid_mesh = mb.build()
else:
@ -304,7 +335,7 @@ class BuildVolume(SceneNode):
mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0), color = self._volume_outline_color)
self.setMeshData(mb.build().getTransformed(scale_matrix))
# Build plate grid mesh
# Build plate surface.
mb = MeshBuilder()
mb.addVertex(0, min_h - z_fight_distance, 0)
mb.addArc(max_w, Vector.Unit_Y, center = Vector(0, min_h - z_fight_distance, 0))
@ -318,7 +349,40 @@ class BuildVolume(SceneNode):
for n in range(0, mb.getVertexCount()):
v = mb.getVertex(n)
mb.setVertexUVCoordinates(n, v[0], v[2] * aspect)
self._grid_mesh = mb.build().getTransformed(scale_matrix)
self._plate_mesh = mb.build().getTransformed(scale_matrix)
#Build plate grid mesh.
#We need to constrain the length of the lines to the build plate ellipsis. Time to get out the calculator!
mb = MeshBuilder()
for x in range(0, int(math.ceil(max_w)), MAJOR_GRID_SIZE):
#x / max_w is the fraction along the build plate we have progressed, counting from the centre.
#So x / max_w is sin(a), where a is the angle towards an endpoint of the grid line from the centre.
#So math.asin(x / max_w) is a.
#So math.cos(math.asin(x / max_w)) is half of the length of the grid line on a unit circle, which scales between 0 and 1.
length_factor = math.cos(math.asin(x / max_w))
mb.addLine(Vector(x, min_h, min_d * length_factor), Vector(x, min_h, max_d * length_factor), color = self._grid_color)
#Start from 0 in both cases, so you need to do this in two for loops.
mb.addLine(Vector(-x, min_h, min_d * length_factor), Vector(-x, min_h, max_d * length_factor), color = self._grid_color)
for y in range(0, int(math.ceil(max_d)), MAJOR_GRID_SIZE):
length_factor = math.sin(math.acos(y / max_d))
mb.addLine(Vector(min_w * length_factor, min_h, y), Vector(max_w * length_factor, min_h, y), color = self._grid_color)
mb.addLine(Vector(min_w * length_factor, min_h, -y), Vector(max_w * length_factor, min_h, -y), color = self._grid_color)
#More fine grained grid.
for x in range(0, int(math.ceil(max_w)), MINOR_GRID_SIZE):
if x % MAJOR_GRID_SIZE == 0: #Don't overlap with the major grid.
pass
length_factor = math.cos(math.asin(x / max_w))
mb.addLine(Vector(x, min_h, min_d * length_factor), Vector(x, min_h, max_d * length_factor), color = self._grid_minor_color)
mb.addLine(Vector(-x, min_h, min_d * length_factor), Vector(-x, min_h, max_d * length_factor), color = self._grid_minor_color)
for y in range(0, int(math.ceil(max_d)), MINOR_GRID_SIZE):
if y % MAJOR_GRID_SIZE == 0:
pass
length_factor = math.sin(math.acos(y / max_d))
mb.addLine(Vector(min_w * length_factor, min_h, y), Vector(max_w * length_factor, min_h, y), color = self._grid_minor_color)
mb.addLine(Vector(min_w * length_factor, min_h, -y), Vector(max_w * length_factor, min_h, -y), color = self._grid_minor_color)
self._grid_mesh = mb.build()
# Indication of the machine origin
if self._global_container_stack.getProperty("machine_center_is_zero", "value"):
@ -442,7 +506,7 @@ class BuildVolume(SceneNode):
def _updateExtraZClearance(self) -> None:
extra_z = 0.0
extruders = ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())
extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
use_extruders = False
for extruder in extruders:
if extruder.getProperty("retraction_hop_enabled", "value"):
@ -489,6 +553,7 @@ class BuildVolume(SceneNode):
self._updateDisallowedAreas()
self._updateRaftThickness()
self._updateExtraZClearance()
if self._engine_ready:
self.rebuild()
@ -527,6 +592,10 @@ class BuildVolume(SceneNode):
self._updateExtraZClearance()
rebuild_me = True
if setting_key in self._limit_to_extruder_settings:
self._updateDisallowedAreas()
rebuild_me = True
if rebuild_me:
self.rebuild()
@ -542,6 +611,8 @@ class BuildVolume(SceneNode):
# would hit performance.
def _updateDisallowedAreasAndRebuild(self):
self._updateDisallowedAreas()
self._updateRaftThickness()
self._updateExtraZClearance()
self.rebuild()
def _updateDisallowedAreas(self):
@ -904,6 +975,7 @@ class BuildVolume(SceneNode):
if not self._global_container_stack:
return 0
container_stack = self._global_container_stack
used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
# If we are printing one at a time, we need to add the bed adhesion size to the disallowed areas of the objects
if container_stack.getProperty("print_sequence", "value") == "one_at_a_time":
@ -914,24 +986,18 @@ class BuildVolume(SceneNode):
skirt_distance = self._getSettingFromAdhesionExtruder("skirt_gap")
skirt_line_count = self._getSettingFromAdhesionExtruder("skirt_line_count")
bed_adhesion_size = skirt_distance + (skirt_line_count * self._getSettingFromAdhesionExtruder("skirt_brim_line_width")) * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0
if len(ExtruderManager.getInstance().getUsedExtruderStacks()) > 1:
adhesion_extruder_nr = int(self._global_container_stack.getProperty("adhesion_extruder_nr", "value"))
extruder_values = ExtruderManager.getInstance().getAllExtruderValues("skirt_brim_line_width")
line_width_factors = ExtruderManager.getInstance().getAllExtruderValues("initial_layer_line_width_factor")
del extruder_values[adhesion_extruder_nr] # Remove the value of the adhesion extruder nr.
del line_width_factors[adhesion_extruder_nr]
for i in range(min(len(extruder_values), len(line_width_factors))):
bed_adhesion_size += extruder_values[i] * line_width_factors[i] / 100.0
if len(used_extruders) > 1:
for extruder_stack in used_extruders:
bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0
#We don't create an additional line for the extruder we're printing the skirt with.
bed_adhesion_size -= self._getSettingFromAdhesionExtruder("skirt_brim_line_width", "value") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor", "value") / 100.0
elif adhesion_type == "brim":
bed_adhesion_size = self._getSettingFromAdhesionExtruder("brim_line_count") * self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0
if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1:
adhesion_extruder_nr = int(self._global_container_stack.getProperty("adhesion_extruder_nr", "value"))
extruder_values = ExtruderManager.getInstance().getAllExtruderValues("skirt_brim_line_width")
line_width_factors = ExtruderManager.getInstance().getAllExtruderValues("initial_layer_line_width_factor")
del extruder_values[adhesion_extruder_nr] # Remove the value of the adhesion extruder nr.
del line_width_factors[adhesion_extruder_nr]
for i in range(min(len(extruder_values), len(line_width_factors))):
bed_adhesion_size += extruder_values[i] * line_width_factors[i] / 100.0
for extruder_stack in used_extruders:
bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0
#We don't create an additional line for the extruder we're printing the brim with.
bed_adhesion_size -= self._getSettingFromAdhesionExtruder("skirt_brim_line_width", "value") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor", "value") / 100.0
elif adhesion_type == "raft":
bed_adhesion_size = self._getSettingFromAdhesionExtruder("raft_margin")
elif adhesion_type == "none":
@ -951,7 +1017,6 @@ class BuildVolume(SceneNode):
move_from_wall_radius = 0 # Moves that start from outer wall.
move_from_wall_radius = max(move_from_wall_radius, max(self._getSettingFromAllExtruders("infill_wipe_dist")))
used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
avoid_enabled_per_extruder = [stack.getProperty("travel_avoid_other_parts","value") for stack in used_extruders]
travel_avoid_distance_per_extruder = [stack.getProperty("travel_avoid_distance", "value") for stack in used_extruders]
for avoid_other_parts_enabled, avoid_distance in zip(avoid_enabled_per_extruder, travel_avoid_distance_per_extruder): #For each extruder (or just global).
@ -975,3 +1040,4 @@ class BuildVolume(SceneNode):
_ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"]
_distance_settings = ["infill_wipe_dist", "travel_avoid_distance", "support_offset", "support_enable", "travel_avoid_other_parts"]
_extruder_settings = ["support_enable", "support_bottom_enable", "support_roof_enable", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_bottom_extruder_nr", "support_roof_extruder_nr", "brim_line_count", "adhesion_extruder_nr", "adhesion_type"] #Settings that can affect which extruders are used.
_limit_to_extruder_settings = ["wall_extruder_nr", "wall_0_extruder_nr", "wall_x_extruder_nr", "top_bottom_extruder_nr", "infill_extruder_nr", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_bottom_extruder_nr", "support_roof_extruder_nr", "adhesion_extruder_nr"]

View file

@ -119,6 +119,12 @@ class CuraApplication(QtApplication):
Q_ENUMS(ResourceTypes)
# FIXME: This signal belongs to the MachineManager, but the CuraEngineBackend plugin requires on it.
# Because plugins are initialized before the ContainerRegistry, putting this signal in MachineManager
# will make it initialized before ContainerRegistry does, and it won't find the active machine, thus
# Cura will always show the Add Machine Dialog upon start.
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
def __init__(self):
# this list of dir names will be used by UM to detect an old cura directory
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
@ -196,7 +202,8 @@ class CuraApplication(QtApplication):
self._additional_components = {} # Components to add to certain areas in the interface
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType,
tray_icon_name = "cura-icon-32.png")
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
@ -276,7 +283,7 @@ class CuraApplication(QtApplication):
preferences.addPreference("cura/categories_expanded", "")
preferences.addPreference("cura/jobname_prefix", True)
preferences.addPreference("view/center_on_select", True)
preferences.addPreference("view/center_on_select", False)
preferences.addPreference("mesh/scale_to_fit", False)
preferences.addPreference("mesh/scale_tiny_meshes", True)
preferences.addPreference("cura/dialog_on_project_save", True)
@ -361,6 +368,12 @@ class CuraApplication(QtApplication):
def _onEngineCreated(self):
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
## The "Quit" button click event handler.
@pyqtSlot()
def closeApplication(self):
Logger.log("i", "Close application")
self._main_window.close()
## A reusable dialogbox
#
showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])

View file

@ -65,6 +65,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._monitor_view_qml_path = ""
self._monitor_component = None
self._monitor_item = None
self._control_view_qml_path = ""
self._control_component = None
self._control_item = None
self._qml_context = None
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
@ -131,7 +136,35 @@ class PrinterOutputDevice(QObject, OutputDevice):
return self._monitor_item
@pyqtProperty(QObject, constant=True)
def controlItem(self):
if not self._control_component:
self._createControlViewFromQML()
return self._control_item
def _createControlViewFromQML(self):
if not self._control_view_qml_path:
return
path = QUrl.fromLocalFile(self._control_view_qml_path)
# Because of garbage collection we need to keep this referenced by python.
self._control_component = QQmlComponent(Application.getInstance()._engine, path)
# Check if the context was already requested before (Printer output device might have multiple items in the future)
if self._qml_context is None:
self._qml_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._qml_context.setContextProperty("OutputDevice", self)
self._control_item = self._control_component.create(self._qml_context)
if self._control_item is None:
Logger.log("e", "QQmlComponent status %s", self._control_component.status())
Logger.log("e", "QQmlComponent error string %s", self._control_component.errorString())
def _createMonitorViewFromQML(self):
if not self._monitor_view_qml_path:
return
path = QUrl.fromLocalFile(self._monitor_view_qml_path)
# Because of garbage collection we need to keep this referenced by python.
@ -584,7 +617,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
@pyqtSlot("long")
@pyqtSlot("long", "long")
def setHeadZ(self, z, speed = 3000):
self._setHeadY(z, speed)
self._setHeadZ(z, speed)
## Move the head of the printer.
# Note that this is a relative move. If you want to move the head to a specific position you can use

View file

@ -333,11 +333,25 @@ class ContainerManager(QObject):
@pyqtSlot(str, result = bool)
def isContainerUsed(self, container_id):
Logger.log("d", "Checking if container %s is currently used", container_id)
containers = self._container_registry.findContainerStacks()
for stack in containers:
if container_id in [child.getId() for child in stack.getContainers()]:
Logger.log("d", "The container is in use by %s", stack.getId())
return True
# check if this is a material container. If so, check if any material with the same base is being used by any
# stacks.
container_ids_to_check = [container_id]
container_results = self._container_registry.findInstanceContainers(id = container_id, type = "material")
if container_results:
this_container = container_results[0]
material_base_file = this_container.getMetaDataEntry("base_file", this_container.getId())
# check all material container IDs with the same base
material_containers = self._container_registry.findInstanceContainers(base_file = material_base_file,
type = "material")
if material_containers:
container_ids_to_check = [container.getId() for container in material_containers]
all_stacks = self._container_registry.findContainerStacks()
for stack in all_stacks:
for used_container_id in container_ids_to_check:
if used_container_id in [child.getId() for child in stack.getContainers()]:
Logger.log("d", "The container is in use by %s", stack.getId())
return True
return False
@pyqtSlot(str, result = str)
@ -415,7 +429,7 @@ class ContainerManager(QObject):
if not Platform.isWindows():
if os.path.exists(file_url):
result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"),
catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_url))
catalog.i18nc("@label Don't translate the XML tag <filename>!", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_url))
if result == QMessageBox.No:
return { "status": "cancelled", "message": "User cancelled"}

View file

@ -110,7 +110,7 @@ class CuraContainerRegistry(ContainerRegistry):
if not Platform.isWindows():
if os.path.exists(file_name):
result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"),
catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
catalog.i18nc("@label Don't translate the XML tag <filename>!", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
if result == QMessageBox.No:
return
found_containers = []
@ -140,15 +140,15 @@ class CuraContainerRegistry(ContainerRegistry):
success = profile_writer.write(file_name, found_containers)
except Exception as e:
Logger.log("e", "Failed to export profile to %s: %s", file_name, str(e))
m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0)
m = Message(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to export profile to <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)), lifetime = 0)
m.show()
return
if not success:
Logger.log("w", "Failed to export profile to %s: Writer plugin reported failure.", file_name)
m = Message(catalog.i18nc("@info:status", "Failed to export profile to <filename>{0}</filename>: Writer plugin reported failure.", file_name), lifetime = 0)
m = Message(catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Failed to export profile to <filename>{0}</filename>: Writer plugin reported failure.", file_name), lifetime = 0)
m.show()
return
m = Message(catalog.i18nc("@info:status", "Exported profile to <filename>{0}</filename>", file_name))
m = Message(catalog.i18nc("@info:status Don't translate the XML tag <filename>!", "Exported profile to <filename>{0}</filename>", file_name))
m.show()
## Gets the plugin object matching the criteria
@ -174,7 +174,7 @@ class CuraContainerRegistry(ContainerRegistry):
def importProfile(self, file_name):
Logger.log("d", "Attempting to import profile %s", file_name)
if not file_name:
return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")}
return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")}
plugin_registry = PluginRegistry.getInstance()
extension = file_name.split(".")[-1]
@ -196,7 +196,7 @@ class CuraContainerRegistry(ContainerRegistry):
except Exception as e:
# Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None.
Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name,profile_reader.getPluginId(), str(e))
return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
if profile_or_list: # Success!
name_seed = os.path.splitext(os.path.basename(file_name))[0]
new_name = self.uniqueName(name_seed)
@ -205,7 +205,7 @@ class CuraContainerRegistry(ContainerRegistry):
result = self._configureProfile(profile, name_seed, new_name)
if result is not None:
return {"status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName())}
else:
@ -239,7 +239,7 @@ class CuraContainerRegistry(ContainerRegistry):
result = self._configureProfile(profile, profile_id, new_name)
if result is not None:
return {"status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, result)}
profile_index += 1
@ -292,10 +292,18 @@ class CuraContainerRegistry(ContainerRegistry):
profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0])
quality_type_criteria["definition"] = "fdmprinter"
machine_definition = Application.getInstance().getGlobalContainerStack().getBottom()
del quality_type_criteria["definition"]
materials = None
if "material" in quality_type_criteria:
materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"])
del quality_type_criteria["material"]
# Check to make sure the imported profile actually makes sense in context of the current configuration.
# This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as
# successfully imported but then fail to show up.
qualities = self.findInstanceContainers(**quality_type_criteria)
from cura.QualityManager import QualityManager
qualities = QualityManager.getInstance()._getFilteredContainersForStack(machine_definition, materials, **quality_type_criteria)
if not qualities:
return catalog.i18nc("@info:status", "Could not find a quality type {0} for the current configuration.", quality_type)

View file

@ -432,6 +432,7 @@ class CuraContainerStack(ContainerStack):
# - If the machine definition has a metadata entry "has_machine_materials", the definition of the material should
# be the same as the machine definition for this stack. Otherwise, the definition should be "fdmprinter".
# - The container should have a metadata entry "type" with value "material".
# - The material should have an approximate diameter that matches the machine
# - If the machine definition has a metadata entry "has_variants" and set to True, the "variant" metadata entry of
# the material should be the same as the ID of the variant in the stack. Only applies if "has_machine_materials" is also True.
# - If the stack currently has a material set, try to find a material that matches the current material by name.
@ -460,6 +461,9 @@ class CuraContainerStack(ContainerStack):
if preferred_material:
search_criteria["id"] = preferred_material
approximate_material_diameter = str(round(self.getProperty("material_diameter", "value")))
search_criteria["approximate_diameter"] = approximate_material_diameter
materials = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if not materials:
Logger.log("w", "The preferred material \"{material}\" could not be found for stack {stack}", material = preferred_material, stack = self.id)

View file

@ -76,6 +76,8 @@ class CuraStackBuilder:
stack.setName(definition.getName())
stack.setDefinition(definition)
stack.addMetaDataEntry("position", definition.getMetaDataEntry("position"))
if "next_stack" in kwargs: #Add stacks before containers are added, since they may trigger a setting update.
stack.setNextStack(kwargs["next_stack"])
user_container = InstanceContainer(new_stack_id + "_user")
user_container.addMetaDataEntry("type", "user")
@ -86,13 +88,12 @@ class CuraStackBuilder:
stack.setUserChanges(user_container)
if "next_stack" in kwargs:
stack.setNextStack(kwargs["next_stack"])
# Important! The order here matters, because that allows the stack to
# assume the material and variant have already been set.
if "definition_changes" in kwargs:
stack.setDefinitionChangesById(kwargs["definition_changes"])
else:
stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
if "variant" in kwargs:
stack.setVariantById(kwargs["variant"])
@ -140,6 +141,8 @@ class CuraStackBuilder:
# assume the material and variant have already been set.
if "definition_changes" in kwargs:
stack.setDefinitionChangesById(kwargs["definition_changes"])
else:
stack.setDefinitionChanges(cls.createDefinitionChangesContainer(stack, new_stack_id + "_settings"))
if "variant" in kwargs:
stack.setVariantById(kwargs["variant"])
@ -158,3 +161,20 @@ class CuraStackBuilder:
registry.addContainer(user_container)
return stack
@classmethod
def createDefinitionChangesContainer(cls, container_stack, container_name, container_index = None):
from cura.CuraApplication import CuraApplication
unique_container_name = ContainerRegistry.getInstance().uniqueName(container_name)
definition_changes_container = InstanceContainer(unique_container_name)
definition = container_stack.getBottom()
definition_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes")
definition_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
ContainerRegistry.getInstance().addContainer(definition_changes_container)
container_stack.definitionChanges = definition_changes_container
return definition_changes_container

View file

@ -434,19 +434,30 @@ class ExtruderManager(QObject):
extruder_stack_id = self.extruderIds["0"]
used_extruder_stack_ids.add(extruder_stack_id)
#Get whether any of them use support.
per_mesh_stack = mesh.callDecoration("getStack")
if per_mesh_stack:
support_enabled |= per_mesh_stack.getProperty("support_enable", "value")
support_bottom_enabled |= per_mesh_stack.getProperty("support_bottom_enable", "value")
support_roof_enabled |= per_mesh_stack.getProperty("support_roof_enable", "value")
else: #Take the setting from the build extruder stack.
extruder_stack = container_registry.findContainerStacks(id = extruder_stack_id)[0]
support_enabled |= extruder_stack.getProperty("support_enable", "value")
support_bottom_enabled |= extruder_stack.getProperty("support_bottom_enable", "value")
support_roof_enabled |= extruder_stack.getProperty("support_roof_enable", "value")
# Get whether any of them use support.
stack_to_use = mesh.callDecoration("getStack") # if there is a per-mesh stack, we use it
if not stack_to_use:
# if there is no per-mesh stack, we use the build extruder for this mesh
stack_to_use = container_registry.findContainerStacks(id = extruder_stack_id)[0]
#The support extruders.
support_enabled |= stack_to_use.getProperty("support_enable", "value")
support_bottom_enabled |= stack_to_use.getProperty("support_bottom_enable", "value")
support_roof_enabled |= stack_to_use.getProperty("support_roof_enable", "value")
# Check limit to extruders
limit_to_extruder_feature_list = ["wall_0_extruder_nr",
"wall_x_extruder_nr",
"roofing_extruder_nr",
"top_bottom_extruder_nr",
"infill_extruder_nr",
]
for extruder_nr_feature_name in limit_to_extruder_feature_list:
extruder_nr = int(global_stack.getProperty(extruder_nr_feature_name, "value"))
if extruder_nr == -1:
continue
used_extruder_stack_ids.add(self.extruderIds[str(extruder_nr)])
# Check support extruders
if support_enabled:
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))])
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))])

View file

@ -7,7 +7,7 @@ from UM.Decorators import override
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
from . import Exceptions
from .CuraContainerStack import CuraContainerStack
@ -57,21 +57,32 @@ class ExtruderStack(CuraContainerStack):
# \throws Exceptions.NoGlobalStackError Raised when trying to get a property from an extruder without
# having a next stack set.
@override(ContainerStack)
def getProperty(self, key: str, property_name: str) -> Any:
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
if not self._next_stack:
raise Exceptions.NoGlobalStackError("Extruder {id} is missing the next stack!".format(id = self.id))
if not super().getProperty(key, "settable_per_extruder"):
return self.getNextStack().getProperty(key, property_name)
if context is None:
context = PropertyEvaluationContext()
context.pushContainer(self)
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
if not super().getProperty(key, "settable_per_extruder", context):
result = self.getNextStack().getProperty(key, property_name, context)
context.popContainer()
return result
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
if limit_to_extruder is not None:
limit_to_extruder = str(limit_to_extruder)
if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder):
if str(limit_to_extruder) in self.getNextStack().extruders:
result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name)
result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
if result is not None:
context.popContainer()
return result
return super().getProperty(key, property_name)
result = super().getProperty(key, property_name, context)
context.popContainer()
return result
@override(CuraContainerStack)
def _getMachineDefinition(self) -> ContainerInterface:
@ -91,6 +102,8 @@ class ExtruderStack(CuraContainerStack):
# When there is a setting that is not settable per extruder that depends on a value from a setting that is,
# we do not always get properly informed that we should re-evaluate the setting. So make sure to indicate
# something changed for those settings.
if not self.getNextStack():
return #There are no global settings to depend on.
definitions = self.getNextStack().definition.findDefinitions(key = key)
if definitions:
has_global_dependencies = False

View file

@ -11,6 +11,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.SettingInstance import InstanceState
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import PropertyEvaluationContext
from UM.Logger import Logger
from . import Exceptions
@ -61,8 +62,10 @@ class GlobalStack(CuraContainerStack):
# already have the maximum number of extruders.
def addExtruder(self, extruder: ContainerStack) -> None:
extruder_count = self.getProperty("machine_extruder_count", "value")
if extruder_count and len(self._extruders) + 1 > extruder_count:
Logger.log("w", "Adding extruder {meta} to {id} but its extruder count is {count}".format(id = self.id, count = extruder_count, meta = str(extruder.getMetaData())))
if extruder_count <= 1:
Logger.log("i", "Not adding extruder[%s] to [%s] because it is a single-extrusion machine.",
extruder.id, self.id)
return
position = extruder.getMetaDataEntry("position")
@ -73,7 +76,9 @@ class GlobalStack(CuraContainerStack):
if any(item.getId() == extruder.id for item in self._extruders.values()):
Logger.log("w", "Extruder [%s] has already been added to this stack [%s]", extruder.id, self._id)
return
self._extruders[position] = extruder
Logger.log("i", "Extruder[%s] added to [%s] at position [%s]", extruder.id, self.id, position)
## Overridden from ContainerStack
#
@ -87,29 +92,38 @@ class GlobalStack(CuraContainerStack):
#
# \return The value of the property for the specified setting, or None if not found.
@override(ContainerStack)
def getProperty(self, key: str, property_name: str) -> Any:
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
if not self.definition.findDefinitions(key = key):
return None
# Handle the "resolve" property.
if self._shouldResolve(key, property_name):
self._resolving_settings.add(key)
resolve = super().getProperty(key, "resolve")
resolve = super().getProperty(key, "resolve", context)
self._resolving_settings.remove(key)
if resolve is not None:
return resolve
if context is None:
context = PropertyEvaluationContext()
context.pushContainer(self)
# Handle the "limit_to_extruder" property.
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
if limit_to_extruder is not None:
limit_to_extruder = str(limit_to_extruder)
if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders:
if super().getProperty(key, "settable_per_extruder"):
result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name)
if super().getProperty(key, "settable_per_extruder", context):
result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
if result is not None:
context.popContainer()
return result
else:
Logger.log("e", "Setting {setting} has limit_to_extruder but is not settable per extruder!", setting = key)
return super().getProperty(key, property_name)
result = super().getProperty(key, property_name, context)
context.popContainer()
return result
## Overridden from ContainerStack
#

View file

@ -91,6 +91,8 @@ class MachineManager(QObject):
self._printer_output_devices = []
Application.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._onOutputDevicesChanged)
# There might already be some output devices by the time the signal is connected
self._onOutputDevicesChanged()
if active_machine_id != "" and ContainerRegistry.getInstance().findContainerStacks(id = active_machine_id):
# An active machine was saved, so restore it.
@ -305,6 +307,7 @@ class MachineManager(QObject):
self._stacks_have_errors = self._checkStacksHaveErrors()
if old_stacks_have_errors != self._stacks_have_errors:
self.stacksValidationChanged.emit()
Application.getInstance().stacksValidationFinished.emit()
def _onActiveExtruderStackChanged(self):
self.blurSettings.emit() # Ensure no-one has focus.
@ -501,16 +504,6 @@ class MachineManager(QObject):
return result
@pyqtProperty("QVariantList", notify = activeVariantChanged)
def activeMaterialIds(self):
result = []
if ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks() is not None:
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
if stack.variant and stack.variant != self._empty_variant_container:
result.append(stack.variant.getId())
return result
@pyqtProperty("QVariantList", notify = activeMaterialChanged)
def activeMaterialNames(self):
result = []
@ -913,6 +906,8 @@ class MachineManager(QObject):
global_quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [], global_quality = True)
else:
global_quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
if not global_quality:
global_quality = self._empty_quality_container
# Find the values for each extruder.
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
@ -926,6 +921,8 @@ class MachineManager(QObject):
quality_changes = quality_changes_list[0]
else:
quality_changes = global_quality_changes
if not quality_changes:
quality_changes = self._empty_quality_changes_container
material = stack.material
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])

View file

@ -0,0 +1,65 @@
from typing import Any, Optional
from UM.Application import Application
from UM.Decorators import override
from UM.Settings.Interfaces import PropertyEvaluationContext
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.SettingInstance import InstanceState
class PerObjectContainerStack(ContainerStack):
@override(ContainerStack)
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
if context is None:
context = PropertyEvaluationContext()
context.pushContainer(self)
global_stack = Application.getInstance().getGlobalContainerStack()
# Return the user defined value if present, otherwise, evaluate the value according to the default routine.
if self.getContainer(0).hasProperty(key, property_name):
if self.getContainer(0)._instances[key].state == InstanceState.User:
result = super().getProperty(key, property_name, context)
context.popContainer()
return result
# Handle the "limit_to_extruder" property.
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
if limit_to_extruder is not None:
limit_to_extruder = str(limit_to_extruder)
# if this stack has the limit_to_extruder "not overriden", use the original limit_to_extruder as the current
# limit_to_extruder, so the values retrieved will be from the perspective of the original limit_to_extruder
# stack.
if limit_to_extruder == "-1":
if "original_limit_to_extruder" in context.context:
limit_to_extruder = context.context["original_limit_to_extruder"]
if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in global_stack.extruders:
# set the original limit_to_extruder if this is the first stack that has a non-overriden limit_to_extruder
if "original_limit_to_extruder" not in context.context:
context.context["original_limit_to_extruder"] = limit_to_extruder
if super().getProperty(key, "settable_per_extruder", context):
result = global_stack.extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
if result is not None:
context.popContainer()
return result
result = super().getProperty(key, property_name, context)
context.popContainer()
return result
@override(ContainerStack)
def setNextStack(self, stack: ContainerStack):
super().setNextStack(stack)
# trigger signal to re-evaluate all default settings
for key, instance in self.getContainer(0)._instances.items():
# only evaluate default settings
if instance.state != InstanceState.Default:
continue
self._collectPropertyChanges(key, "value")
self._emitCollectedPropertyChanges()

View file

@ -108,9 +108,9 @@ class ProfilesModel(InstanceContainersModel):
#Quality has no value for layer height either. Get the layer height from somewhere lower in the stack.
skip_until_container = global_container_stack.material
if not skip_until_container: #No material in stack.
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack.
skip_until_container = global_container_stack.variant
if not skip_until_container: #No variant in stack.
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No variant in stack.
skip_until_container = global_container_stack.getBottom()
item["layer_height"] = str(global_container_stack.getRawProperty("layer_height", "value", skip_until_container = skip_until_container.getId())) + unit #Fall through to the currently loaded material.
yield item
yield item

View file

@ -5,13 +5,13 @@ import copy
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Signal import Signal, signalemitter
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Logger import Logger
from UM.Application import Application
from cura.Settings.PerObjectContainerStack import PerObjectContainerStack
from cura.Settings.ExtruderManager import ExtruderManager
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
@ -24,7 +24,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
self._stack = ContainerStack(stack_id = id(self))
self._stack = PerObjectContainerStack(stack_id = id(self))
self._stack.setDirty(False) # This stack does not need to be saved.
self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer"))

View file

@ -17,6 +17,7 @@ from .WorkspaceDialog import WorkspaceDialog
import xml.etree.ElementTree as ET
from cura.Settings.CuraStackBuilder import CuraStackBuilder
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.ExtruderStack import ExtruderStack
from cura.Settings.GlobalStack import GlobalStack
@ -221,10 +222,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
elif container_type == "definition_changes":
definition_name = instance_container.getName()
num_settings_overriden_by_definition_changes += len(instance_container._instances)
definition_changes = self._container_registry.findDefinitionContainers(id = container_id)
definition_changes = self._container_registry.findInstanceContainers(id = container_id)
containers_found_dict["definition_changes"] = True
# Check if there is any difference the loaded settings from the project file and the settings in Cura.
if definition_changes:
if definition_changes[0] != instance_container:
definition_changes_conflict = True
elif container_type == "quality":
if not quality_name:
quality_name = instance_container.getName()
elif container_type == "user":
num_user_settings += len(instance_container._instances)
elif container_type in self._ignored_instance_container_types:
@ -254,12 +260,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
for index, container_id in enumerate(id_list):
# take into account the old empty container IDs
container_id = self._old_empty_profile_id_dict.get(container_id, container_id)
# HACK: there used to be 5, now we have one more 5 - definition changes
if len(id_list) == 6 and index == 5:
if global_stack.getContainer(5).getId() != "empty":
machine_conflict = True
break
index = 6
if global_stack.getContainer(index).getId() != container_id:
machine_conflict = True
break
@ -295,12 +295,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
for index, container_id in enumerate(id_list):
# take into account the old empty container IDs
container_id = self._old_empty_profile_id_dict.get(container_id, container_id)
# HACK: there used to be 5, now we have one more 5 - definition changes
if len(id_list) == 6 and index == 5:
if existing_extruder_stack.getContainer(5).getId() != "empty":
machine_conflict = True
break
index = 6
if existing_extruder_stack.getContainer(index).getId() != container_id:
machine_conflict = True
break
@ -444,6 +438,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
global_stack_id_original = self._stripFileToId(global_stack_file)
global_stack_id_new = global_stack_id_original
global_stack_name_original = self._getMachineNameFromSerializedStack(archive.open(global_stack_file).read().decode("utf-8"))
global_stack_name_new = global_stack_name_original
global_stack_need_rename = False
extruder_stack_id_map = {} # new and old ExtruderStack IDs map
@ -453,6 +449,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
global_stack_id_new = self.getNewId(global_stack_id_original)
global_stack_need_rename = True
global_stack_name_new = self._container_registry.uniqueName(global_stack_name_original)
for each_extruder_stack_file in extruder_stack_files:
old_container_id = self._stripFileToId(each_extruder_stack_file)
new_container_id = old_container_id
@ -663,7 +661,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
stack.setMetaDataEntry("machine", global_stack_id_new)
# Only machines need a new name, stacks may be non-unique
stack.setName(self._container_registry.uniqueName(stack.getName()))
stack.setName(global_stack_name_new)
container_stacks_added.append(stack)
self._container_registry.addContainer(stack)
@ -672,6 +670,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
Logger.log("e", "Resolve strategy of %s for machine is not supported",
self._resolve_strategies["machine"])
# Create a new definition_changes container if it was empty
if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer():
stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings"))
global_stack = stack
Job.yieldThread()
except:
@ -681,51 +682,65 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._container_registry.removeContainer(container.getId())
return
#
# Use the number of extruders from the global stack instead of the number of extruder stacks this project file
# contains. The Custom FDM Printer can have multiple extruders, but the actual number of extruders in used is
# defined in the global stack.
# Because for single-extrusion machines, there won't be an extruder stack, so relying on the the extruder count
# in the global stack can avoid problems in those cases.
#
extruder_count_from_global_stack = global_stack.getProperty("machine_extruder_count", "value")
# --
# load extruder stack files
try:
for extruder_stack_file in extruder_stack_files:
container_id = self._stripFileToId(extruder_stack_file)
extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8")
if extruder_count_from_global_stack > 1:
try:
for extruder_stack_file in extruder_stack_files:
container_id = self._stripFileToId(extruder_stack_file)
extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8")
if self._resolve_strategies["machine"] == "override":
# deserialize new extruder stack over the current ones
stack = self._overrideExtruderStack(global_stack, extruder_file_content)
if self._resolve_strategies["machine"] == "override":
# deserialize new extruder stack over the current ones
stack = self._overrideExtruderStack(global_stack, extruder_file_content)
elif self._resolve_strategies["machine"] == "new":
new_id = extruder_stack_id_map[container_id]
stack = ExtruderStack(new_id)
elif self._resolve_strategies["machine"] == "new":
new_id = extruder_stack_id_map[container_id]
stack = ExtruderStack(new_id)
# HACK: the global stack can have a new name, so we need to make sure that this extruder stack
# references to the new name instead of the old one. Normally, this can be done after
# deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
# also does addExtruder() to its machine stack, so we have to make sure that it's pointing
# to the right machine BEFORE deserialization.
extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content)
extruder_config.set("metadata", "machine", global_stack_id_new)
tmp_string_io = io.StringIO()
extruder_config.write(tmp_string_io)
extruder_file_content = tmp_string_io.getvalue()
# HACK: the global stack can have a new name, so we need to make sure that this extruder stack
# references to the new name instead of the old one. Normally, this can be done after
# deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
# also does addExtruder() to its machine stack, so we have to make sure that it's pointing
# to the right machine BEFORE deserialization.
extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content)
extruder_config.set("metadata", "machine", global_stack_id_new)
tmp_string_io = io.StringIO()
extruder_config.write(tmp_string_io)
extruder_file_content = tmp_string_io.getvalue()
stack.deserialize(extruder_file_content)
stack.deserialize(extruder_file_content)
# Ensure a unique ID and name
stack._id = new_id
# Ensure a unique ID and name
stack._id = new_id
self._container_registry.addContainer(stack)
extruder_stacks_added.append(stack)
containers_added.append(stack)
else:
Logger.log("w", "Unknown resolve strategy: %s", self._resolve_strategies["machine"])
self._container_registry.addContainer(stack)
extruder_stacks_added.append(stack)
containers_added.append(stack)
else:
Logger.log("w", "Unknown resolve strategy: %s", self._resolve_strategies["machine"])
extruder_stacks.append(stack)
except:
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
# Something went really wrong. Try to remove any data that we added.
for container in containers_added:
self._container_registry.removeContainer(container.getId())
return
# Create a new definition_changes container if it was empty
if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer():
stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings"))
extruder_stacks.append(stack)
except:
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
# Something went really wrong. Try to remove any data that we added.
for container in containers_added:
self._container_registry.removeContainer(container.getId())
return
#
# Replacing the old containers if resolve is "new".
@ -803,36 +818,31 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
each_extruder_stack.definitionChanges = each_changes_container
if self._resolve_strategies["material"] == "new":
# the actual material instance container can have an ID such as
# <material>_<machine>_<variant>
# which cannot be determined immediately, so here we use a HACK to find the right new material
# instance ID:
# - get the old material IDs for all material
# - find the old material with the longest common prefix in ID, that's the old material
# - update the name by replacing the old prefix with the new
# - find the new material container and set it to the stack
old_to_new_material_dict = {}
for each_material in material_containers:
old_material = global_stack.material
# check if the old material container has been renamed to this material container ID
# if the container hasn't been renamed, we do nothing.
new_id = self._id_mapping.get(old_material.getId())
if new_id is None or new_id != each_material.getId():
continue
if old_material.getId() in self._id_mapping:
global_stack.material = each_material
# find the material's old name
for old_id, new_id in self._id_mapping.items():
if each_material.getId() == new_id:
old_to_new_material_dict[old_id] = each_material
break
# replace old material in global and extruder stacks with new
self._replaceStackMaterialWithNew(global_stack, old_to_new_material_dict)
if extruder_stacks:
for each_extruder_stack in extruder_stacks:
old_material = each_extruder_stack.material
# check if the old material container has been renamed to this material container ID
# if the container hasn't been renamed, we do nothing.
new_id = self._id_mapping.get(old_material.getId())
if new_id is None or new_id != each_material.getId():
continue
if old_material.getId() in self._id_mapping:
each_extruder_stack.material = each_material
self._replaceStackMaterialWithNew(each_extruder_stack, old_to_new_material_dict)
if extruder_stacks:
for stack in extruder_stacks:
ExtruderManager.getInstance().registerExtruder(stack, global_stack.getId())
else:
# Machine has no extruders, but it needs to be registered with the extruder manager.
ExtruderManager.getInstance().registerExtruder(None, global_stack.getId())
Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
@ -853,6 +863,61 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
nodes = []
return nodes
## HACK: Replaces the material container in the given stack with a newly created material container.
# This function is used when the user chooses to resolve material conflicts by creating new ones.
def _replaceStackMaterialWithNew(self, stack, old_new_material_dict):
# The material containers in the project file are 'parent' material such as "generic_pla",
# but a material container used in a global/extruder stack is a 'child' material,
# such as "generic_pla_ultimaker3_AA_0.4", which can be formalised as the following:
#
# <material_name>_<machine_name>_<variant_name>
#
# In the project loading, when a user chooses to resolve material conflicts by creating new ones,
# the old 'parent' material ID and the new 'parent' material ID are known, but not the child material IDs.
# In this case, the global stack and the extruder stacks need to use the newly created material, but the
# material containers they use are 'child' material. So, here, we need to find the right 'child' material for
# the stacks.
#
# This hack approach works as follows:
# - No matter there is a child material or not, the actual material we are looking for has the prefix
# "<material_name>", which is the old material name. For the material in a stack, we know that the new
# material's ID will be "<new_material_name>_blabla..", so we just need to replace the old material ID
# with the new one to get the new 'child' material.
# - Because the material containers have IDs such as "m #nn", if we use simple prefix matching, there can
# be a problem in the following scenario:
# - there are two materials in the project file, namely "m #1" and "m #11"
# - the child materials in use are for example: "m #1_um3_aa04", "m #11_um3_aa04"
# - if we only check for a simple prefix match, then "m #11_um3_aa04" will match with "m #1", but they
# are not the same material
# To avoid this, when doing the prefix matching, we use the result with the longest mactching prefix.
# find the old material ID
old_material_id_in_stack = stack.material.getId()
best_matching_old_material_id = None
best_matching_old_meterial_prefix_length = -1
for old_parent_material_id in old_new_material_dict:
if len(old_parent_material_id) < best_matching_old_meterial_prefix_length:
continue
if len(old_parent_material_id) <= len(old_material_id_in_stack):
if old_parent_material_id == old_material_id_in_stack[0:len(old_parent_material_id)]:
best_matching_old_meterial_prefix_length = len(old_parent_material_id)
best_matching_old_material_id = old_parent_material_id
if best_matching_old_material_id is None:
Logger.log("w", "Cannot find any matching old material ID for stack [%s] material [%s]. Something can go wrong",
stack.getId(), old_material_id_in_stack)
return
# find the new material container
new_material_id = old_new_material_dict[best_matching_old_material_id].getId() + old_material_id_in_stack[len(best_matching_old_material_id):]
new_material_containers = self._container_registry.findInstanceContainers(id = new_material_id, type = "material")
if not new_material_containers:
Logger.log("e", "Cannot find new material container [%s]", new_material_id)
return
# replace the material in the given stack
stack.material = new_material_containers[0]
def _stripFileToId(self, file):
mime_type = MimeTypeDatabase.getMimeTypeForFile(file)
file = mime_type.stripExtension(file)
@ -875,6 +940,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
container_list = container_string.split(",")
container_ids = [container_id for container_id in container_list if container_id != ""]
# HACK: there used to be 6 containers numbering from 0 to 5 in a stack,
# now we have 7: index 5 becomes "definition_changes"
if len(container_ids) == 6:
# Hack; We used to not save the definition changes. Fix this.
container_ids.insert(5, "empty")
return container_ids
def _getMachineNameFromSerializedStack(self, serialized):
@ -887,5 +958,3 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"})
for entry in metadata:
return entry.text
pass

View file

@ -87,18 +87,18 @@ UM.Dialog
{
text: catalog.i18nc("@action:label", "Printer settings")
font.bold: true
width: parent.width / 3
width: (parent.width / 3) | 0
}
Item
{
// spacer
height: spacerHeight
width: parent.width / 3
width: (parent.width / 3) | 0
}
UM.TooltipArea
{
id: machineResolveTooltip
width: parent.width / 3
width: (parent.width / 3) | 0
height: visible ? comboboxHeight : 0
visible: manager.machineConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the machine be resolved?")
@ -122,12 +122,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Type")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: manager.machineType
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
@ -138,12 +138,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: manager.machineName
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
@ -160,18 +160,18 @@ UM.Dialog
{
text: catalog.i18nc("@action:label", "Profile settings")
font.bold: true
width: parent.width / 3
width: (parent.width / 3) | 0
}
Item
{
// spacer
height: spacerHeight
width: parent.width / 3
width: (parent.width / 3) | 0
}
UM.TooltipArea
{
id: qualityChangesResolveTooltip
width: parent.width / 3
width: (parent.width / 3) | 0
height: visible ? comboboxHeight : 0
visible: manager.qualityChangesConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the profile be resolved?")
@ -195,12 +195,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: manager.qualityName
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
Row
@ -210,12 +210,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Not in profile")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
width: parent.width / 3
width: (parent.width / 3) | 0
}
visible: manager.numUserSettings != 0
}
@ -226,12 +226,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Derivative from")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
width: parent.width / 3
width: (parent.width / 3) | 0
}
visible: manager.numSettingsOverridenByQualityChanges != 0
}
@ -248,18 +248,18 @@ UM.Dialog
{
text: catalog.i18nc("@action:label", "Material settings")
font.bold: true
width: parent.width / 3
width: (parent.width / 3) | 0
}
Item
{
// spacer
height: spacerHeight
width: parent.width / 3
width: (parent.width / 3) | 0
}
UM.TooltipArea
{
id: materialResolveTooltip
width: parent.width / 3
width: (parent.width / 3) | 0
height: visible ? comboboxHeight : 0
visible: manager.materialConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the material be resolved?")
@ -287,12 +287,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: modelData
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
}
@ -315,12 +315,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Mode")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: manager.activeMode
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
Row
@ -330,12 +330,12 @@ UM.Dialog
Label
{
text: catalog.i18nc("@action:label", "Visible settings:")
width: parent.width / 3
width: (parent.width / 3) | 0
}
Label
{
text: catalog.i18nc("@action:label", "%1 out of %2" ).arg(manager.numVisibleSettings).arg(manager.totalNumberOfSettings)
width: parent.width / 3
width: (parent.width / 3) | 0
}
}
Item // Spacer

View file

@ -2,11 +2,9 @@ from UM.Workspace.WorkspaceWriter import WorkspaceWriter
from UM.Application import Application
from UM.Preferences import Preferences
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack
from cura.Settings.ExtruderManager import ExtruderManager
import zipfile
from io import StringIO
import copy
import configparser

View file

@ -11,8 +11,8 @@ import UM 1.1 as UM
UM.Dialog
{
id: base
minimumWidth: UM.Theme.getSize("modal_window_minimum").width * 0.75
minimumHeight: UM.Theme.getSize("modal_window_minimum").height * 0.75
minimumWidth: (UM.Theme.getSize("modal_window_minimum").width * 0.75) | 0
minimumHeight: (UM.Theme.getSize("modal_window_minimum").height * 0.75) | 0
width: minimumWidth
height: minimumHeight
title: catalog.i18nc("@label", "Changelog")

View file

@ -1,3 +1,86 @@
[2.7.0]
*Top surface skin
Specify print settings of the top-most layers separately in order to improve print duration and achieve higher quality top surfaces.
*Print thin walls
An experimental function that enables features to be printed up to two times smaller than the nozzle size.
*Ironing (a.k.a. Neosanding)
An experimental function that enables the heated nozzle to travel over printed top layers without extrusion to create a smooth finish. Made after an idea by Neotko.
*Gradual support infill
Supports will print faster and with less material while improving overhang quality.
*Support infill layer thickness
Users are able to configure “Support infill layer thickness” for thicker support layers.
*Relative Z seam
A function that positions the Z seam relative to the bounding box of the model, so that the seam stays at the same location no matter what the position of the object is.
*Prime tower purge
In order to prevent under extrusion when printing a prime tower, and to prevent a prime tower failing half way through a job, a feature has been added to wipe off oozed/purged material in the middle of a hollow prime tower before starting to print the next layer of it. The amount of material to purge can be specified in the “Prime Tower Purge Volume” setting.
*First layer line width
A multiplier setting for the line width of the first layer of a print. Multiplying line width gives fewer lines but with greater width, which improves build plate adhesion.
*Pause standby and resume temperature
Turn off the nozzle when printing with extended pauses to prevent burned filament and nozzle clogging. At the end of a pause, the nozzle will reach printing temperature before resuming a print.
*Extruder per feature
Assign specific print features (walls, infill, skin, etc.) to a specific nozzle. A possible application of this would be to print an outer shell of an object with a fine nozzle at a greater level of detail while using a larger second nozzle to print infill faster.
*Dark theme
A dark theme for Cura. Select this theme to reduce eyestrain when working in dark environments. Activate it by selecting “Preferences > Themes > Dark".
*Top navigation bar redesign
The top bar user interface been improved so that “Prepare” and “Print” have moved from the right side of the interface to the left side.
*New keyboard shortcuts
Models can now be manipulated on the build plate using hotkeys Q, A, Z, W, and tab keys. Q selects “move”, A selects “scale”, Z selects “rotate”, and W selects “mirror”. Use the tab key to navigate between settings.
*Plugin browser
Easily download and install plugins using an integrated plugin browser. Go to “Extensions > Plugin Browser > Browse plugins” to select it.
*Import SolidWorks files as STL
A new plugin that enables SolidWorks compatible .SLDPRT files to be imported directly into Cura, where they are automatically converted to .STL format. This plugin can be found in the plugin browser.
*Zoom towards mouse cursor position
Cura preferences now include an option to zoom towards the cursor position on screen.
*Increased scroll speed in setting lists
The scroll speed in the setting lists is now three times faster than previous versions.
*Extra tooltips
Extra tooltips have been added to clarify the machine settings.
*Polish now supported
Polish language support added. This can be selected in the preferences menu.
*Chinese now supported
Chinese language support added. This can be selected in the preferences menu.
*Bug fixes
- Cura project Mac extensions
- Crashes when adding printers
- Jerk fixes
- Z-hop over-extrusion
- Material diameter in machine settings
*3rd party printers
- Peopoly Moai
- DiscoEasy200
- Cartesio
- EasyArt Ares
- 3Dator
- Rigid3D
- Type A Series 1
- HelloBEEPrusa
[2.6.2]
*Bug fixes
- Fixed an issue with Cura crashing on older versions of MacOS.
[2.6.1]
*New profiles
The Polypropylene material is added and supported with the Ultimaker 3. Support for CPE+ and PC with 0.8mm nozzles is added as well.

View file

@ -76,14 +76,23 @@ class CuraEngineBackend(QObject, Backend):
self._scene = Application.getInstance().getController().getScene()
self._scene.sceneChanged.connect(self._onSceneChanged)
# Triggers for when to (re)start slicing:
# Triggers for auto-slicing. Auto-slicing is triggered as follows:
# - auto-slicing is started with a timer
# - whenever there is a value change, we start the timer
# - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the
# auto-slicing timer when that error check is finished
# If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer,
# and only wait for the error check to be finished to start the auto-slicing timer again.
#
self._global_container_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged()
self._active_extruder_stack = None
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
self._onActiveExtruderChanged()
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
# A flag indicating if an error check was scheduled
# If so, we will stop the auto-slice timer and start upon the error check
self._is_error_check_scheduled = False
# Listeners for receiving messages from the back-end.
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
@ -418,6 +427,7 @@ class CuraEngineBackend(QObject, Backend):
## Convenient function: set need_slicing, emit state and clear layer data
def needsSlicing(self):
self.stopSlicing()
self._need_slicing = True
self.processingProgress.emit(0.0)
self.backendStateChange.emit(BackendState.NotStarted)
@ -426,11 +436,21 @@ class CuraEngineBackend(QObject, Backend):
self._clearLayerData()
## A setting has changed, so check if we must reslice.
#
# \param instance The setting instance that has changed.
# \param property The property of the setting instance that has changed.
# \param instance The setting instance that has changed.
# \param property The property of the setting instance that has changed.
def _onSettingChanged(self, instance, property):
if property == "value": # Only reslice if the value has changed.
if property == "value": # Only reslice if the value has changed.
self.needsSlicing()
self._onChanged()
elif property == "validationState":
if self._use_timer:
self._is_error_check_scheduled = True
self._change_timer.stop()
def _onStackErrorCheckFinished(self):
self._is_error_check_scheduled = False
if self._need_slicing:
self.needsSlicing()
self._onChanged()
@ -525,7 +545,12 @@ class CuraEngineBackend(QObject, Backend):
def _onChanged(self, *args, **kwargs):
self.needsSlicing()
if self._use_timer:
self._change_timer.start()
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
# otherwise business as usual
if self._is_error_check_scheduled:
self._change_timer.stop()
else:
self._change_timer.start()
## Called when the back-end connects to the front-end.
def _onBackendConnected(self):
@ -591,9 +616,10 @@ class CuraEngineBackend(QObject, Backend):
self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged)
self._global_container_stack.containersChanged.disconnect(self._onChanged)
extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
if extruders:
for extruder in extruders:
extruder.propertyChanged.disconnect(self._onSettingChanged)
for extruder in extruders:
extruder.propertyChanged.disconnect(self._onSettingChanged)
extruder.containersChanged.disconnect(self._onChanged)
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
@ -601,27 +627,11 @@ class CuraEngineBackend(QObject, Backend):
self._global_container_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed.
self._global_container_stack.containersChanged.connect(self._onChanged)
extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
if extruders:
for extruder in extruders:
extruder.propertyChanged.connect(self._onSettingChanged)
self._onActiveExtruderChanged()
for extruder in extruders:
extruder.propertyChanged.connect(self._onSettingChanged)
extruder.containersChanged.connect(self._onChanged)
self._onChanged()
def _onActiveExtruderChanged(self):
if self._global_container_stack:
# Connect all extruders of the active machine. This might cause a few connects that have already happend,
# but that shouldn't cause issues as only new / unique connections are added.
extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
if extruders:
for extruder in extruders:
extruder.propertyChanged.connect(self._onSettingChanged)
if self._active_extruder_stack:
self._active_extruder_stack.containersChanged.disconnect(self._onChanged)
self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_extruder_stack:
self._active_extruder_stack.containersChanged.connect(self._onChanged)
def _onProcessLayersFinished(self, job):
self._process_layers_job = None

View file

@ -177,7 +177,7 @@ class ProcessSlicedLayersJob(Job):
position = int(extruder.getMetaDataEntry("position", default="0")) # Get the position
try:
default_color = ExtrudersModel.defaultColors[position]
except KeyError:
except IndexError:
default_color = "#e0e000"
color_code = extruder.material.getMetaDataEntry("color_code", default=default_color)
color = colorCodeToRGBA(color_code)

View file

@ -1,4 +1,4 @@
# Copyright (c) 2015 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import numpy
@ -306,31 +306,38 @@ class StartSliceJob(Job):
# \param message object_lists message to put the per object settings in
def _handlePerObjectSettings(self, node, message):
stack = node.callDecoration("getStack")
# Check if the node has a stack attached to it and the stack has any settings in the top container.
if stack:
# Check all settings for relations, so we can also calculate the correct values for dependant settings.
changed_setting_keys = set(stack.getTop().getAllKeys())
for key in stack.getTop().getAllKeys():
instance = stack.getTop().getInstance(key)
self._addRelations(changed_setting_keys, instance.definition.relations)
Job.yieldThread()
if not stack: # Check if the node has a stack attached to it and the stack has any settings in the top container.
return
# Ensure that the engine is aware what the build extruder is
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
# Check all settings for relations, so we can also calculate the correct values for dependent settings.
top_of_stack = stack.getTop() #Cache for efficiency.
changed_setting_keys = set(top_of_stack.getAllKeys())
for key in top_of_stack.getAllKeys():
instance = top_of_stack.getInstance(key)
self._addRelations(changed_setting_keys, instance.definition.relations)
Job.yieldThread()
# Get values for all changed settings
for key in changed_setting_keys:
setting = message.addRepeatedMessage("settings")
setting.name = key
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
# Ensure that the engine is aware what the build extruder is
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
# Get values for all changed settings
for key in changed_setting_keys:
setting = message.addRepeatedMessage("settings")
setting.name = key
extruder = int(round(float(stack.getProperty(key, "limit_to_extruder"))))
if extruder >= 0 and key not in top_of_stack.getAllKeys(): #Limited to a specific extruder, but not overridden by per-object settings.
limited_stack = ExtruderManager.getInstance().getActiveExtruderStacks()[extruder]
else:
limited_stack = stack #Just take from the per-object settings itself.
setting.value = str(limited_stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
## Recursive function to put all settings that require eachother for value changes in a list
# \param relations_set \type{set} Set of keys (strings) of settings that are influenced
# \param relations list of relation objects that need to be checked.
def _addRelations(self, relations_set, relations):
for relation in filter(lambda r: r.role == "value", relations):
for relation in filter(lambda r: r.role == "value" or r.role == "limit_to_extruder", relations):
if relation.type == RelationType.RequiresTarget:
continue

View file

@ -63,14 +63,18 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("layerview_row_spacing").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
Label
{
id: layersLabel
anchors.left: parent.left
text: catalog.i18nc("@label","View Mode: Layers")
font.bold: true
font: UM.Theme.getFont("default_bold");
color: UM.Theme.getColor("text")
Layout.fillWidth: true
elide: Text.ElideMiddle;
}
Label
@ -86,6 +90,7 @@ Item
id: layerViewTypesLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Color scheme")
font: UM.Theme.getFont("default");
visible: !UM.LayerView.compatibilityMode
Layout.fillWidth: true
color: UM.Theme.getColor("text")
@ -117,6 +122,8 @@ Item
model: layerViewTypes
visible: !UM.LayerView.compatibilityMode
style: UM.Theme.styles.combobox
anchors.right: parent.right
anchors.rightMargin: 10
onActivated:
{
@ -142,6 +149,8 @@ Item
id: compatibilityModeLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Compatibility Mode")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
visible: UM.LayerView.compatibilityMode
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
@ -175,17 +184,18 @@ Item
Repeater {
model: Cura.ExtrudersModel{}
CheckBox {
id: extrudersModelCheckBox
checked: view_settings.extruder_opacities[index] > 0.5 || view_settings.extruder_opacities[index] == undefined || view_settings.extruder_opacities[index] == ""
onClicked: {
view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0
UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|"));
}
text: model.name
visible: !UM.LayerView.compatibilityMode
enabled: index + 1 <= 4
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.right: extrudersModelCheckBox.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: model.color
@ -197,6 +207,18 @@ Item
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
style: UM.Theme.styles.checkbox
Label
{
text: model.name
elide: Text.ElideRight
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter
anchors.left: extrudersModelCheckBox.left;
anchors.right: extrudersModelCheckBox.right;
anchors.leftMargin: UM.Theme.getSize("checkbox").width + UM.Theme.getSize("default_margin").width /2
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
}
}
}
@ -233,14 +255,15 @@ Item
}
CheckBox {
id: legendModelCheckBox
checked: model.initialValue
onClicked: {
UM.Preferences.setValue(model.preference, checked);
}
text: label
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.right: legendModelCheckBox.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
@ -252,6 +275,18 @@ Item
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
style: UM.Theme.styles.checkbox
Label
{
text: label
font: UM.Theme.getFont("default")
elide: Text.ElideRight
color: UM.Theme.getColor("text")
anchors.verticalCenter: parent.verticalCenter
anchors.left: legendModelCheckBox.left;
anchors.right: legendModelCheckBox.right;
anchors.leftMargin: UM.Theme.getSize("checkbox").width + UM.Theme.getSize("default_margin").width /2
anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
}
}
}
@ -293,9 +328,11 @@ Item
Label {
text: label
visible: view_settings.show_legend
id: typesLegendModelLabel
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.right: typesLegendModelLabel.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor(model.colorId)
@ -307,6 +344,7 @@ Item
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default")
}
}
}

View file

@ -16,6 +16,7 @@ from UM.Logger import Logger
from cura.CuraApplication import CuraApplication
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.CuraStackBuilder import CuraStackBuilder
import UM.i18n
catalog = UM.i18n.i18nCatalog("cura")
@ -62,7 +63,8 @@ class MachineSettingsAction(MachineAction):
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = self._global_container_stack.definitionChanges
if definition_changes_container == self._empty_container:
definition_changes_container = self._createDefinitionChangesContainer(self._global_container_stack, self._global_container_stack.getName() + "_settings")
definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer(
self._global_container_stack, self._global_container_stack.getName() + "_settings")
# Notify the UI in which container to store the machine settings data
container_index = self._global_container_stack.getContainerIndex(definition_changes_container)
@ -88,19 +90,8 @@ class MachineSettingsAction(MachineAction):
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = extruder_container_stack.definitionChanges
if definition_changes_container == self._empty_container:
definition_changes_container = self._createDefinitionChangesContainer(extruder_container_stack, extruder_container_stack.getId() + "_settings")
def _createDefinitionChangesContainer(self, container_stack, container_name, container_index = None):
definition_changes_container = InstanceContainer(container_name)
definition = container_stack.getBottom()
definition_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes")
definition_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
self._container_registry.addContainer(definition_changes_container)
container_stack.definitionChanges = definition_changes_container
return definition_changes_container
definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer(
extruder_container_stack, extruder_container_stack.getId() + "_settings")
containerIndexChanged = pyqtSignal()

View file

@ -70,7 +70,7 @@ Cura.MachineAction
anchors.top: pageTitle.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
property real columnWidth: Math.floor((width - 3 * UM.Theme.getSize("default_margin").width) / 2)
property real columnWidth: ((width - 3 * UM.Theme.getSize("default_margin").width) / 2) | 0
Tab
{
@ -233,6 +233,7 @@ Cura.MachineAction
property string label: catalog.i18nc("@label", "Gantry height")
property string unit: catalog.i18nc("@label", "mm")
property string tooltip: catalog.i18nc("@tooltip", "The height difference between the tip of the nozzle and the gantry system (X and Y axes). Used to prevent collisions between previous prints and the gantry when printing \"One at a Time\".")
property bool forceUpdateOnChange: true
}
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }

View file

@ -22,7 +22,7 @@ Button {
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
height: label.height / 2
height: (label.height / 2) | 0
width: height
source: control.checked ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_right");
color: control.hovered ? palette.highlight : palette.buttonText

View file

@ -1,4 +1,4 @@
// Copyright (c) 2016 Ultimaker B.V.
// Copyright (c) 2017 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
@ -38,6 +38,7 @@ Item {
height: parent.height
width: UM.Theme.getSize("setting").width + UM.Theme.getSize("setting").height
style: UM.Theme.styles.scrollview
ListView
{
id: contents
@ -66,6 +67,7 @@ Item {
property var definition: model
property var settingDefinitionsModel: addedSettingsModel
property var propertyProvider: provider
property var globalPropertyProvider: inheritStackProvider
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
@ -110,10 +112,10 @@ Item {
Button
{
width: UM.Theme.getSize("setting").height / 2;
height: UM.Theme.getSize("setting").height;
width: (UM.Theme.getSize("setting").height / 2) | 0
height: UM.Theme.getSize("setting").height
onClicked: addedSettingsModel.setVisible(model.key, false);
onClicked: addedSettingsModel.setVisible(model.key, false)
style: ButtonStyle
{
@ -133,6 +135,8 @@ Item {
}
}
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
// so we bypass that to make a dedicated provider).
UM.SettingPropertyProvider
{
id: provider
@ -143,6 +147,53 @@ Item {
storeIndex: 0
removeUnusedValue: false
}
UM.SettingPropertyProvider
{
id: inheritStackProvider
containerStackId: UM.ActiveTool.properties.getValue("ContainerID")
key: model.key
watchedProperties: [ "limit_to_extruder" ]
}
Connections
{
target: inheritStackProvider
onPropertiesChanged:
{
provider.forcePropertiesChanged();
}
}
Connections
{
target: UM.ActiveTool
onPropertiesChanged:
{
// the values cannot be bound with UM.ActiveTool.properties.getValue() calls,
// so here we connect to the signal and update the those values.
if (typeof UM.ActiveTool.properties.getValue("SelectedObjectId") !== "undefined")
{
const selectedObjectId = UM.ActiveTool.properties.getValue("SelectedObjectId");
if (addedSettingsModel.visibilityHandler.selectedObjectId != selectedObjectId)
{
addedSettingsModel.visibilityHandler.selectedObjectId = selectedObjectId;
}
}
if (typeof UM.ActiveTool.properties.getValue("ContainerID") !== "undefined")
{
const containerId = UM.ActiveTool.properties.getValue("ContainerID");
if (provider.containerStackId != containerId)
{
provider.containerStackId = containerId;
}
if (inheritStackProvider.containerStackId != containerId)
{
inheritStackProvider.containerStackId = containerId;
}
}
}
}
}
}
}

View file

@ -15,6 +15,7 @@ from PyQt5.QtQml import QQmlComponent, QQmlContext
import json
import os
import tempfile
import platform
i18n_catalog = i18nCatalog("cura")
@ -22,7 +23,7 @@ i18n_catalog = i18nCatalog("cura")
class PluginBrowser(QObject, Extension):
def __init__(self, parent = None):
super().__init__(parent)
self.addMenuItem(i18n_catalog.i18n("Browse plugins"), self.browsePlugins)
self.addMenuItem(i18n_catalog.i18nc("@menuitem", "Browse plugins"), self.browsePlugins)
self._api_version = 1
self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version
@ -43,7 +44,14 @@ class PluginBrowser(QObject, Extension):
self._is_downloading = False
self._request_header = [b"User-Agent", str.encode("%s - %s" % (Application.getInstance().getApplicationName(), Application.getInstance().getVersion()))]
self._request_header = [b"User-Agent",
str.encode("%s\%s (%s %s)" % (Application.getInstance().getApplicationName(),
Application.getInstance().getVersion(),
platform.system(),
platform.machine(),
)
)
]
# Installed plugins are really installed after reboot. In order to prevent the user from downloading the
# same file over and over again, we keep track of the upgraded plugins.
@ -246,4 +254,4 @@ class PluginBrowser(QObject, Extension):
self._network_manager = QNetworkAccessManager()
self._network_manager.finished.connect(self._onRequestFinished)
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)

View file

@ -86,7 +86,7 @@ class RemovableDriveOutputDevice(OutputDevice):
job.progress.connect(self._onProgress)
job.finished.connect(self._onFinished)
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message = Message(catalog.i18nc("@info:progress Don't translate the XML tags <filename>!", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message.show()
self.writeStarted.emit(self)
@ -96,10 +96,10 @@ class RemovableDriveOutputDevice(OutputDevice):
job.start()
except PermissionError as e:
Logger.log("e", "Permission denied when trying to write to %s: %s", file_name, str(e))
raise OutputDeviceError.PermissionDeniedError(catalog.i18nc("@info:status", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
raise OutputDeviceError.PermissionDeniedError(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
except OSError as e:
Logger.log("e", "Operating system would not let us write to %s: %s", file_name, str(e))
raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format(file_name, str(e))) from e
## Generate a file name automatically for the specified nodes to be saved
# in.

View file

@ -69,15 +69,26 @@ class SliceInfo(Extension):
else:
data["active_mode"] = "custom"
data["machine_settings_changed_by_user"] = global_container_stack.definitionChanges.getId() != "empty"
definition_changes = global_container_stack.definitionChanges
machine_settings_changed_by_user = False
if definition_changes.getId() != "empty":
# Now a definition_changes container will always be created for a stack,
# so we also need to check if there is any instance in the definition_changes container
if definition_changes.getAllKeys():
machine_settings_changed_by_user = True
data["machine_settings_changed_by_user"] = machine_settings_changed_by_user
data["language"] = Preferences.getInstance().getValue("general/language")
data["os"] = {"type": platform.system(), "version": platform.version()}
data["active_machine"] = {"definition_id": global_container_stack.definition.getId(), "manufacturer": global_container_stack.definition.getMetaData().get("manufacturer","")}
data["extruders"] = []
extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
extruders = sorted(extruders, key = lambda extruder: extruder.getMetaDataEntry("position"))
extruder_count = len(global_container_stack.extruders)
extruders = []
if extruder_count > 1:
extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
extruders = sorted(extruders, key = lambda extruder: extruder.getMetaDataEntry("position"))
if not extruders:
extruders = [global_container_stack]
@ -179,6 +190,9 @@ class SliceInfo(Extension):
data["print_settings"] = print_settings
# Send the name of the output device type that is used.
data["output_to"] = type(output_device).__name__
# Convert data to bytes
binary_data = json.dumps(data).encode("utf-8")

View file

@ -114,7 +114,7 @@ Cura.MachineAction
Column
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
spacing: UM.Theme.getSize("default_margin").height
ScrollView
@ -200,7 +200,7 @@ Cura.MachineAction
}
Column
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
visible: base.selectedPrinter ? true : false
spacing: UM.Theme.getSize("default_margin").height
Label
@ -218,13 +218,13 @@ Cura.MachineAction
columns: 2
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Type")
}
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text:
{
@ -249,25 +249,25 @@ Cura.MachineAction
}
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Firmware version")
}
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text: base.selectedPrinter ? base.selectedPrinter.firmwareVersion : ""
}
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Address")
}
Label
{
width: parent.width * 0.5
width: (parent.width * 0.5) | 0
wrapMode: Text.WordWrap
text: base.selectedPrinter ? base.selectedPrinter.ipAddress : ""
}

View file

@ -9,9 +9,20 @@ Component
Image
{
id: cameraImage
width: sourceSize.width
height: sourceSize.height * width / sourceSize.width
property bool proportionalHeight:
{
if(sourceSize.height == 0 || maximumHeight == 0)
{
return true;
}
return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
}
property real _width: Math.min(maximumWidth, sourceSize.width)
property real _height: Math.min(maximumHeight, sourceSize.height)
width: proportionalHeight ? _width : sourceSize.width * _height / sourceSize.height
height: !proportionalHeight ? _height : sourceSize.height * _width / sourceSize.width
anchors.horizontalCenter: parent.horizontalCenter
onVisibleChanged:
{
if(visible)

View file

@ -179,7 +179,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._compressing_print = False
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "MonitorItem.qml")
printer_type = self._properties.get(b"machine", b"").decode("utf-8")
if printer_type.startswith("9511"):
self._updatePrinterType("ultimaker3_extended")
@ -314,15 +313,16 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
return True
def _stopCamera(self):
self._camera_timer.stop()
if self._image_reply:
try:
self._image_reply.abort()
self._image_reply.downloadProgress.disconnect(self._onStreamDownloadProgress)
except RuntimeError:
pass # It can happen that the wrapped c++ object is already deleted.
self._image_reply = None
self._image_request = None
if self._camera_timer.isActive():
self._camera_timer.stop()
if self._image_reply:
try:
self._image_reply.abort()
self._image_reply.downloadProgress.disconnect(self._onStreamDownloadProgress)
except RuntimeError:
pass # It can happen that the wrapped c++ object is already deleted.
self._image_reply = None
self._image_request = None
def _startCamera(self):
if self._use_stream:

View file

@ -117,7 +117,14 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
if reply.operation() == QNetworkAccessManager.GetOperation:
if "system" in reply_url: # Name returned from printer.
if status_code == 200:
system_info = json.loads(bytes(reply.readAll()).decode("utf-8"))
try:
system_info = json.loads(bytes(reply.readAll()).decode("utf-8"))
except json.JSONDecodeError:
Logger.log("e", "Printer returned invalid JSON.")
return
except UnicodeDecodeError:
Logger.log("e", "Printer returned incorrect UTF-8.")
return
address = reply.url().host()
instance_name = "manual:%s" % address

View file

@ -12,7 +12,9 @@ UM.Dialog
id: base;
width: 500 * Screen.devicePixelRatio;
minimumWidth: 500 * Screen.devicePixelRatio;
height: 100 * Screen.devicePixelRatio;
minimumHeight: 100 * Screen.devicePixelRatio;
visible: true;
modality: Qt.ApplicationModal;

View file

@ -19,6 +19,7 @@ import platform
import glob
import time
import os.path
import serial.tools.list_ports
from UM.Extension import Extension
from PyQt5.QtQml import QQmlComponent, QQmlContext
@ -252,24 +253,13 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
# \param only_list_usb If true, only usb ports are listed
def getSerialPortList(self, only_list_usb = False):
base_list = []
if platform.system() == "Windows":
import winreg # type: ignore @UnresolvedImport
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM")
i = 0
while True:
values = winreg.EnumValue(key, i)
if not only_list_usb or "USBSER" or "VCP" in values[0]:
base_list += [values[1]]
i += 1
except Exception as e:
pass
else:
if only_list_usb:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.usb*") + glob.glob("/dev/tty.wchusb*") + glob.glob("/dev/cu.wchusb*")
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
else:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/tty.wchusb*") + glob.glob("/dev/cu.wchusb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
for port in serial.tools.list_ports.comports():
if not isinstance(port, tuple):
port = (port.device, port.description, port.hwid)
if only_list_usb and not port[2].startswith("USB"):
continue
base_list += [port[0]]
return list(base_list)
_instance = None # type: "USBPrinterOutputDeviceManager"

View file

@ -13,8 +13,8 @@ Cura.MachineAction
{
id: checkupMachineAction
anchors.fill: parent;
property int leftRow: checkupMachineAction.width * 0.40
property int rightRow: checkupMachineAction.width * 0.60
property int leftRow: (checkupMachineAction.width * 0.40) | 0
property int rightRow: (checkupMachineAction.width * 0.60) | 0
property bool heatupHotendStarted: false
property bool heatupBedStarted: false
property bool usbConnected: Cura.USBPrinterManager.connectedPrinterList.rowCount() > 0
@ -166,7 +166,7 @@ Cura.MachineAction
Label
{
id: nozzleTempStatus
width: checkupMachineAction.rightRow * 0.4
width: (checkupMachineAction.rightRow * 0.4) | 0
anchors.top: nozzleTempLabel.top
anchors.left: nozzleTempLabel.right
wrapMode: Text.WordWrap
@ -176,7 +176,7 @@ Cura.MachineAction
Item
{
id: nozzleTempButton
width: checkupMachineAction.rightRow * 0.3
width: (checkupMachineAction.rightRow * 0.3) | 0
height: childrenRect.height
anchors.top: nozzleTempLabel.top
anchors.left: bedTempStatus.right
@ -205,7 +205,7 @@ Cura.MachineAction
anchors.top: nozzleTempLabel.top
anchors.left: nozzleTempButton.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: checkupMachineAction.rightRow * 0.2
width: (checkupMachineAction.rightRow * 0.2) | 0
wrapMode: Text.WordWrap
text: manager.hotendTemperature + "°C"
font.bold: true
@ -227,7 +227,7 @@ Cura.MachineAction
Label
{
id: bedTempStatus
width: checkupMachineAction.rightRow * 0.4
width: (checkupMachineAction.rightRow * 0.4) | 0
anchors.top: bedTempLabel.top
anchors.left: bedTempLabel.right
wrapMode: Text.WordWrap
@ -237,7 +237,7 @@ Cura.MachineAction
Item
{
id: bedTempButton
width: checkupMachineAction.rightRow * 0.3
width: (checkupMachineAction.rightRow * 0.3) | 0
height: childrenRect.height
anchors.top: bedTempLabel.top
anchors.left: bedTempStatus.right
@ -263,7 +263,7 @@ Cura.MachineAction
Label
{
id: bedTemp
width: checkupMachineAction.rightRow * 0.2
width: (checkupMachineAction.rightRow * 0.2) | 0
anchors.top: bedTempLabel.top
anchors.left: bedTempButton.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width

View file

@ -2,7 +2,6 @@
# Uranium is released under the terms of the AGPLv3 or higher.
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer
from cura.MachineAction import MachineAction
from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty
@ -10,8 +9,7 @@ from UM.i18n import i18nCatalog
from UM.Application import Application
catalog = i18nCatalog("cura")
import UM.Settings.InstanceContainer
from cura.CuraApplication import CuraApplication
from cura.Settings.CuraStackBuilder import CuraStackBuilder
## The Ultimaker Original can have a few revisions & upgrades. This action helps with selecting them, so they are added
# as a variant.
@ -38,20 +36,8 @@ class UMOUpgradeSelection(MachineAction):
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = global_container_stack.definitionChanges
if definition_changes_container == ContainerRegistry.getInstance().getEmptyInstanceContainer():
definition_changes_container = self._createDefinitionChangesContainer(global_container_stack)
definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer(
global_container_stack, global_container_stack.getId() + "_settings")
definition_changes_container.setProperty("machine_heated_bed", "value", heated_bed)
self.heatedBedChanged.emit()
def _createDefinitionChangesContainer(self, global_container_stack):
# Create a definition_changes container to store the settings in and add it to the stack
definition_changes_container = UM.Settings.InstanceContainer.InstanceContainer(global_container_stack.getName() + "_settings")
definition = global_container_stack.getBottom()
definition_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes")
definition_changes_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
ContainerRegistry.getInstance().addContainer(definition_changes_container)
global_container_stack.definitionChanges = definition_changes_container
return definition_changes_container

View file

@ -3,9 +3,14 @@
import configparser #To parse the files we need to upgrade and write the new files.
import io #To serialise configparser output to a string.
import os
from urllib.parse import quote_plus
from UM.Resources import Resources
from UM.VersionUpgrade import VersionUpgrade
from cura.CuraApplication import CuraApplication
_removed_settings = { #Settings that were removed in 2.5.
"start_layers_at_same_position",
"sub_div_rad_mult"
@ -20,6 +25,11 @@ _split_settings = { #These settings should be copied to all settings it was spli
#
# All of these methods are essentially stateless.
class VersionUpgrade25to26(VersionUpgrade):
def __init__(self):
super().__init__()
self._current_fdm_printer_count = 2
## Gets the version number from a CFG file in Uranium's 2.5 format.
#
# Since the format may change, this is implemented for the 2.5 format only
@ -103,3 +113,183 @@ class VersionUpgrade25to26(VersionUpgrade):
output = io.StringIO()
parser.write(output)
return [filename], [output.getvalue()]
## Upgrades a machine stack from version 2.5 to 2.6
#
# \param serialised The serialised form of a quality profile.
# \param filename The name of the file to upgrade.
def upgradeMachineStack(self, serialised, filename):
parser = configparser.ConfigParser(interpolation=None)
parser.read_string(serialised)
# NOTE: This is for Custom FDM printers
# In 2.5, Custom FDM printers don't support multiple extruders, but since 2.6 they do.
machine_id = parser["general"]["id"]
quality_container_id = parser["containers"]["2"]
material_container_id = parser["containers"]["3"]
definition_container_id = parser["containers"]["6"]
if definition_container_id == "custom" and not self._checkCustomFdmPrinterHasExtruderStack(machine_id):
# go through all extruders and make sure that this custom FDM printer has 8 extruder stacks.
self._acquireNextUniqueCustomFdmPrinterExtruderStackIdIndex()
for position in range(8):
self._createCustomFdmPrinterExtruderStack(machine_id, position, quality_container_id, material_container_id)
# Update version numbers
parser["general"]["version"] = "3"
parser["metadata"]["setting_version"] = "1"
# Re-serialise the file.
output = io.StringIO()
parser.write(output)
return [filename], [output.getvalue()]
## Acquires the next unique extruder stack index number for the Custom FDM Printer.
def _acquireNextUniqueCustomFdmPrinterExtruderStackIdIndex(self):
extruder_stack_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
file_name_list = os.listdir(extruder_stack_dir)
file_name_list = [os.path.basename(file_name) for file_name in file_name_list]
while True:
self._current_fdm_printer_count += 1
stack_id_exists = False
for position in range(8):
stack_id = "custom_extruder_%s" % (position + 1)
if self._current_fdm_printer_count > 1:
stack_id += " #%s" % self._current_fdm_printer_count
if stack_id in file_name_list:
stack_id_exists = True
break
if not stack_id_exists:
break
return self._current_fdm_printer_count
def _checkCustomFdmPrinterHasExtruderStack(self, machine_id):
# go through all extruders and make sure that this custom FDM printer has extruder stacks.
extruder_stack_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
has_extruders = False
for item in os.listdir(extruder_stack_dir):
file_path = os.path.join(extruder_stack_dir, item)
if not os.path.isfile(file_path):
continue
parser = configparser.ConfigParser()
try:
parser.read([file_path])
except:
# skip, it is not a valid stack file
continue
if "metadata" not in parser:
continue
if "machine" not in parser["metadata"]:
continue
if machine_id != parser["metadata"]["machine"]:
continue
has_extruders = True
break
return has_extruders
def _createCustomFdmPrinterExtruderStack(self, machine_id: str, position: int, quality_id: str, material_id: str):
stack_id = "custom_extruder_%s" % (position + 1)
if self._current_fdm_printer_count > 1:
stack_id += " #%s" % self._current_fdm_printer_count
definition_id = "custom_extruder_%s" % (position + 1)
# create a definition changes container for this stack
definition_changes_parser = self._getCustomFdmPrinterDefinitionChanges(stack_id)
definition_changes_id = definition_changes_parser["general"]["name"]
# create a user settings container
user_settings_parser = self._getCustomFdmPrinterUserSettings(stack_id)
user_settings_id = user_settings_parser["general"]["name"]
parser = configparser.ConfigParser()
parser.add_section("general")
parser["general"]["version"] = str(2)
parser["general"]["name"] = "Extruder %s" % (position + 1)
parser["general"]["id"] = stack_id
parser.add_section("metadata")
parser["metadata"]["type"] = "extruder_train"
parser["metadata"]["machine"] = machine_id
parser["metadata"]["position"] = str(position)
parser.add_section("containers")
parser["containers"]["0"] = user_settings_id
parser["containers"]["1"] = "empty_quality_changes"
parser["containers"]["2"] = quality_id
parser["containers"]["3"] = material_id
parser["containers"]["4"] = "empty_variant"
parser["containers"]["5"] = definition_changes_id
parser["containers"]["6"] = definition_id
definition_changes_output = io.StringIO()
definition_changes_parser.write(definition_changes_output)
definition_changes_filename = quote_plus(definition_changes_id) + ".inst.cfg"
user_settings_output = io.StringIO()
user_settings_parser.write(user_settings_output)
user_settings_filename = quote_plus(user_settings_id) + ".inst.cfg"
extruder_output = io.StringIO()
parser.write(extruder_output)
extruder_filename = quote_plus(stack_id) + ".extruder.cfg"
extruder_stack_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
definition_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
user_settings_dir = Resources.getPath(CuraApplication.ResourceTypes.UserInstanceContainer)
with open(os.path.join(definition_changes_dir, definition_changes_filename), "w") as f:
f.write(definition_changes_output.getvalue())
with open(os.path.join(user_settings_dir, user_settings_filename), "w") as f:
f.write(user_settings_output.getvalue())
with open(os.path.join(extruder_stack_dir, extruder_filename), "w") as f:
f.write(extruder_output.getvalue())
## Creates a definition changes container which doesn't contain anything for the Custom FDM Printers.
# The container ID will be automatically generated according to the given stack name.
def _getCustomFdmPrinterDefinitionChanges(self, stack_id: str):
# In 2.5, there is no definition_changes container for the Custom FDM printer, so it should be safe to use the
# default name unless some one names the printer as something like "Custom FDM Printer_settings".
definition_changes_id = stack_id + "_settings"
parser = configparser.ConfigParser()
parser.add_section("general")
parser["general"]["version"] = str(2)
parser["general"]["name"] = definition_changes_id
parser["general"]["definition"] = "custom"
parser.add_section("metadata")
parser["metadata"]["type"] = "definition_changes"
parser["metadata"]["setting_version"] = str(1)
parser.add_section("values")
return parser
## Creates a user settings container which doesn't contain anything for the Custom FDM Printers.
# The container ID will be automatically generated according to the given stack name.
def _getCustomFdmPrinterUserSettings(self, stack_id: str):
# For the extruder stacks created in the upgrade, also create user_settings containers so the user changes
# will be saved.
user_settings_id = stack_id + "_user"
parser = configparser.ConfigParser()
parser.add_section("general")
parser["general"]["version"] = str(2)
parser["general"]["name"] = user_settings_id
parser["general"]["definition"] = "custom"
parser.add_section("metadata")
parser["metadata"]["extruder"] = stack_id
parser["metadata"]["type"] = "user"
parser["metadata"]["setting_version"] = str(1)
parser.add_section("values")
return parser

View file

@ -19,6 +19,7 @@ def getMetaData():
("user", 2000000): ("user", 2000001, upgrade.upgradeInstanceContainer),
("quality", 2000000): ("quality", 2000001, upgrade.upgradeInstanceContainer),
("definition_changes", 2000000): ("definition_changes", 2000001, upgrade.upgradeInstanceContainer),
("machine_stack", 3000000): ("machine_stack", 3000001, upgrade.upgradeMachineStack),
},
"sources": {
"quality_changes": {
@ -36,6 +37,10 @@ def getMetaData():
"definition_changes": {
"get_version": upgrade.getCfgVersion,
"location": {"./machine_instances"}
},
"machine_stack": {
"get_version": upgrade.getCfgVersion,
"location": {"./machine_instances"}
}
}
}

View file

@ -104,6 +104,11 @@ class VersionUpgrade26to27(VersionUpgrade):
parser["metadata"] = {}
parser["metadata"]["setting_version"] = "2"
#Renamed setting value for g-code flavour.
if "values" in parser and "machine_gcode_flavor" in parser["values"]:
if parser["values"]["machine_gcode_flavor"] == "RepRap (Volumatric)":
parser["values"]["machine_gcode_flavor"] = "RepRap (Volumetric)"
# Re-serialise the file.
output = io.StringIO()
parser.write(output)

View file

@ -12,7 +12,7 @@ def getMetaData():
return {
"version_upgrade": {
# From To Upgrade function
("machine_stack", 3000000): ("machine_stack", 3000002, upgrade.upgradeStack),
("machine_stack", 3000001): ("machine_stack", 3000002, upgrade.upgradeStack),
("extruder_train", 3000000): ("extruder_train", 3000002, upgrade.upgradeStack),
# In 2.6.x, Preferences are saved with "version = 4" and no setting_version.
@ -29,6 +29,7 @@ def getMetaData():
("user", 2000001): ("user", 2000002, upgrade.upgradeOtherContainer),
("quality", 2000001): ("quality", 2000002, upgrade.upgradeOtherContainer),
("definition_changes", 2000001): ("definition_changes", 2000002, upgrade.upgradeOtherContainer),
("variant", 2000000): ("variant", 2000002, upgrade.upgradeOtherContainer)
},
"sources": {
"machine_stack": {
@ -53,7 +54,11 @@ def getMetaData():
},
"definition_changes": {
"get_version": upgrade.getCfgVersion,
"location": {"./machine_instances"}
"location": {"./definition_changes"}
},
"variant": {
"get_version": upgrade.getCfgVersion,
"location": {"./variants"}
}
}
}

View file

@ -229,7 +229,10 @@ class XmlMaterialProfile(InstanceContainer):
product = definition_id
builder.start("machine")
builder.start("machine_identifier", { "manufacturer": definition.getMetaDataEntry("manufacturer", ""), "product": product})
builder.start("machine_identifier", {
"manufacturer": container.getMetaDataEntry("machine_manufacturer", definition.getMetaDataEntry("manufacturer", "Unknown")),
"product": product
})
builder.end("machine_identifier")
for instance in container.findInstances():
@ -540,10 +543,22 @@ class XmlMaterialProfile(InstanceContainer):
definition = definitions[0]
machine_manufacturer = identifier.get("manufacturer", definition.getMetaDataEntry("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
if machine_compatibility:
new_material_id = self.id + "_" + machine_id
new_material = XmlMaterialProfile(new_material_id)
# The child or derived material container may already exist. This can happen when a material in a
# project file and the a material in Cura have the same ID.
# In the case if a derived material already exists, override that material container because if
# the data in the parent material has been changed, the derived ones should be updated too.
found_materials = ContainerRegistry.getInstance().findInstanceContainers(id = new_material_id)
is_new_material = False
if found_materials:
new_material = found_materials[0]
else:
new_material = XmlMaterialProfile(new_material_id)
is_new_material = True
# Update the private directly, as we want to prevent the lookup that is done when using setName
new_material._name = self.getName()
@ -551,12 +566,14 @@ class XmlMaterialProfile(InstanceContainer):
new_material.setDefinition(definition)
# Don't use setMetadata, as that overrides it for all materials with same base file
new_material.getMetaData()["compatible"] = machine_compatibility
new_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
new_material.setCachedValues(cached_machine_setting_properties)
new_material._dirty = False
ContainerRegistry.getInstance().addContainer(new_material)
if is_new_material:
ContainerRegistry.getInstance().addContainer(new_material)
hotends = machine.iterfind("./um:hotend", self.__namespaces)
for hotend in hotends:
@ -588,7 +605,15 @@ class XmlMaterialProfile(InstanceContainer):
new_hotend_id = self.id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")
new_hotend_material = XmlMaterialProfile(new_hotend_id)
# Same as machine compatibility, keep the derived material containers consistent with the parent
# material
found_materials = ContainerRegistry.getInstance().findInstanceContainers(id = new_hotend_id)
is_new_material = False
if found_materials:
new_hotend_material = found_materials[0]
else:
new_hotend_material = XmlMaterialProfile(new_hotend_id)
is_new_material = True
# Update the private directly, as we want to prevent the lookup that is done when using setName
new_hotend_material._name = self.getName()
@ -597,6 +622,7 @@ class XmlMaterialProfile(InstanceContainer):
new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id)
# Don't use setMetadata, as that overrides it for all materials with same base file
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
cached_hotend_setting_properties = cached_machine_setting_properties.copy()
cached_hotend_setting_properties.update(hotend_setting_values)
@ -605,7 +631,8 @@ class XmlMaterialProfile(InstanceContainer):
new_hotend_material._dirty = False
ContainerRegistry.getInstance().addContainer(new_hotend_material)
if is_new_material:
ContainerRegistry.getInstance().addContainer(new_hotend_material)
def _addSettingElement(self, builder, instance):
try:

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "rikky",
"manufacturer": "101Hero",
"category": "Other",
"machine_extruder_trains":
{
"0": "fdmextruder"
@ -28,8 +27,6 @@
"layer_height": { "default_value": 0.2 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[ 0, 0 ],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "3Dator GmbH",
"manufacturer": "3Dator GmbH",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"supports_usb_connection": true,

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "ABAX 3d Technologies",
"manufacturer": "ABAX 3d Technologies",
"category": "Other",
"file_formats": "text/x-gcode"
},
"overrides": {

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "ABAX 3d Technologies",
"manufacturer": "ABAX 3d Technologies",
"category": "Other",
"file_formats": "text/x-gcode"
},
"overrides": {

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "ABAX 3d Technologies",
"manufacturer": "ABAX 3d Technologies",
"category": "Other",
"file_formats": "text/x-gcode"
},
"overrides": {

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "ALYA",
"manufacturer": "ALYA",
"category": "Other",
"file_formats": "text/x-gcode"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "BFB",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "BQ",
"manufacturer": "BQ",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "bq_hephestos_platform.stl",
"platform_offset": [ 0, -82, 0]

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "BQ",
"manufacturer": "BQ",
"category": "Other",
"platform": "bq_hephestos_2_platform.stl",
"platform_offset": [6, 1320, 0 ],
"file_formats": "text/x-gcode"

View file

@ -7,7 +7,6 @@
"visible": true,
"manufacturer": "BQ",
"author": "BQ",
"category": "Other",
"file_formats": "text/x-code",
"platform": "bq_hephestos_platform.stl",
"platform_offset": [ 0, -82, 0]

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "BQ",
"manufacturer": "BQ",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "bq_witbox_platform.stl",
"platform_offset": [ 0, -145, -38]

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "BQ",
"manufacturer": "BQ",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "bq_witbox_platform.stl",
"platform_offset": [0, -145, -38]

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Scheepers",
"manufacturer": "Cartesio bv",
"category": "Other",
"file_formats": "text/x-gcode",
"has_machine_quality": true,
@ -48,8 +47,8 @@
"material_bed_temp_wait": { "default_value": false },
"prime_tower_enable": { "default_value": true },
"prime_tower_wall_thickness": { "resolve": 0.7 },
"prime_tower_position_x": { "default_value": 50 },
"prime_tower_position_y": { "default_value": 150 },
"prime_tower_position_x": { "value": "50" },
"prime_tower_position_y": { "value": "150" },
"prime_blob_enable": { "default_value": false },
"machine_max_feedrate_z": { "default_value": 20 },
"machine_disallowed_areas": { "default_value": [

View file

@ -0,0 +1,95 @@
{
"id": "creality-cr10_beta",
"name": "Creality CR-10 Beta",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Michael Wildermuth",
"manufacturer": "Creality3D",
"file_formats": "text/x-gcode"
},
"overrides": {
"machine_width": {
"default_value": 300
},
"machine_height": {
"default_value": 400
},
"machine_depth": {
"default_value": 300
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"layer_height": {
"default_value": 0.2
},
"layer_height_0": {
"default_value": 0.2
},
"top_bottom_thickness": {
"default_value": 0.6
},
"top_bottom_pattern": {
"default_value": "concentric"
},
"infill_pattern": {
"value": "'triangles'"
},
"retraction_enable": {
"default_value": true
},
"retraction_amount": {
"default_value": 5
},
"retraction_speed": {
"default_value": 40
},
"cool_min_layer_time": {
"default_value": 15
},
"adhesion_type": {
"default_value": "skirt"
},
"skirt_line_count": {
"default_value": 4
},
"skirt_gap": {
"default_value": 5
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute Positioning\nG28 ; home all axes\nG1 Z5 F3000 ; lift\nG1 X20 Y2 F1500 ; avoid binder clips\nG1 Z0.2 F3000 ; get ready to prime\nG92 E0 ; reset extrusion distance\nG1 X120 E10 F600 ; prime nozzle\nG1 X150 F5000 ; quick wipe"
},
"machine_end_gcode": {
"default_value": "G91\nG1 F1800 E-3\nG1 F3000 Z10\nG90\nG28 X0 Y0 ; home x and y axis\nM106 S0 ; turn off cooling fan\nM104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM84 ; disable motors"
},
"machine_heated_bed": {
"default_value": true
},
"gantry_height": {
"default_value": 30
},
"acceleration_enabled": {
"default_value": true
},
"acceleration_print": {
"default_value": 500
},
"acceleration_travel": {
"default_value": 500
},
"jerk_enabled": {
"default_value": true
},
"jerk_print": {
"default_value": 20
},
"jerk_travel": {
"default_value": 20
}
}
}

View file

@ -0,0 +1,23 @@
{
"id": "creality-cr10s4_beta",
"name": "Creality CR-10 S4 Beta",
"version": 2,
"inherits": "creality_cr10_beta",
"metadata": {
"visible": true,
"author": "Michael Wildermuth",
"manufacturer": "Creality3D",
"file_formats": "text/x-gcode"
},
"overrides": {
"machine_width": {
"default_value": 400
},
"machine_height": {
"default_value": 400
},
"machine_depth": {
"default_value": 400
}
}
}

View file

@ -0,0 +1,23 @@
{
"id": "creality-cr10s5_beta",
"name": "Creality CR-10 S5 Beta",
"version": 2,
"inherits": "creality_cr10_beta",
"metadata": {
"visible": true,
"author": "Michael Wildermuth",
"manufacturer": "Creality3D",
"file_formats": "text/x-gcode"
},
"overrides": {
"machine_width": {
"default_value": 500
},
"machine_height": {
"default_value": 500
},
"machine_depth": {
"default_value": 500
}
}
}

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Dagoma",
"manufacturer": "Dagoma",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2.png",
"platform": "discoeasy200.stl",

View file

@ -4,39 +4,38 @@
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Deltaprintr",
"manufacturer": "Deltaprintr",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0],
"platform": ""
},
"visible": true,
"author": "Deltaprintr",
"manufacturer": "Deltaprintr",
"file_formats": "text/x-gcode",
"platform_offset": [0, 0, 0],
"platform": ""
},
"overrides": {
"machine_name": { "default_value": "Delta Go" },
"material_diameter": { "default_value": 1.75 },
"default_material_print_temperature": { "default_value": 210 },
"speed_travel": { "default_value": 150 },
"prime_tower_size": { "default_value": 8.66 },
"infill_sparse_density": { "default_value": 10 },
"speed_wall_x": { "default_value": 30 },
"speed_wall_0": { "default_value": 30 },
"speed_topbottom": { "default_value": 20 },
"layer_height": { "default_value": 0.15 },
"speed_print": { "default_value": 30 },
"machine_heated_bed": { "default_value": false },
"machine_center_is_zero": { "default_value": true },
"machine_height": { "default_value": 154 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 115 },
"machine_width": { "default_value": 115 },
"raft_airgap": { "default_value": 0.15 },
"retraction_hop_enabled": { "value": "True" },
"retraction_amount": { "default_value": 4.1 },
"retraction_speed": { "default_value": 500 },
"retraction_hop": { "value": "0.2" },
"retraction_hop_only_when_collides": { "value": "True" },
"brim_width": { "value": "5" },
"machine_shape": { "default_value": "elliptic"}
}
"machine_name": { "default_value": "Delta Go" },
"material_diameter": { "default_value": 1.75 },
"default_material_print_temperature": { "default_value": 210 },
"speed_travel": { "default_value": 150 },
"prime_tower_size": { "default_value": 8.66 },
"infill_sparse_density": { "default_value": 10 },
"speed_wall_x": { "default_value": 30 },
"speed_wall_0": { "default_value": 30 },
"speed_topbottom": { "default_value": 20 },
"layer_height": { "default_value": 0.15 },
"speed_print": { "default_value": 30 },
"machine_heated_bed": { "default_value": false },
"machine_center_is_zero": { "default_value": true },
"machine_height": { "default_value": 154 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 115 },
"machine_width": { "default_value": 115 },
"raft_airgap": { "default_value": 0.15 },
"retraction_hop_enabled": { "value": "True" },
"retraction_amount": { "default_value": 4.1 },
"retraction_speed": { "default_value": 500 },
"retraction_hop": { "value": "0.2" },
"retraction_hop_only_when_collides": { "value": "True" },
"brim_width": { "value": "5" },
"machine_shape": { "default_value": "elliptic"}
}
}

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "Danny Lu",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "nliaudat",
"manufacturer": "EasyArts (discontinued)",
"category": "Other",
"file_formats": "text/x-gcode"
},
"overrides": {

View file

@ -5,8 +5,8 @@
"metadata":
{
"type": "extruder",
"author": "Ultimaker B.V.",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"manufacturer": "Unknown",
"setting_version": 1,
"visible": false
},

View file

@ -5,9 +5,9 @@
"metadata":
{
"type": "machine",
"author": "Ultimaker B.V.",
"category": "Ultimaker",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"category": "Other",
"manufacturer": "Unknown",
"setting_version": 1,
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g",
"visible": false,
@ -633,7 +633,7 @@
"unit": "mm",
"type": "float",
"default_value": 0.3,
"resolve": "sum(extruderValues('layer_height_0')) / len(extruderValues('layer_height_0'))",
"resolve": "min(extruderValues('layer_height_0'))",
"minimum_value": "0.001",
"minimum_value_warning": "0.1",
"maximum_value_warning": "0.8 * min(extruderValues('machine_nozzle_size'))",
@ -665,7 +665,6 @@
"value": "line_width",
"default_value": 0.4,
"type": "float",
"limit_to_extruder": "wall_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -678,7 +677,7 @@
"minimum_value_warning": "(0.1 + 0.4 * machine_nozzle_size) if outer_inset_first else 0.1 * machine_nozzle_size",
"maximum_value_warning": "2 * machine_nozzle_size",
"default_value": 0.4,
"value": "extruderValue(wall_0_extruder_nr, 'wall_line_width')",
"value": "wall_line_width",
"type": "float",
"limit_to_extruder": "wall_0_extruder_nr",
"settable_per_mesh": true
@ -699,6 +698,21 @@
}
}
},
"roofing_line_width":
{
"label": "Top Surface Skin Line Width",
"description": "Width of a single line of the areas at the top of the print.",
"unit": "mm",
"minimum_value": "0.001",
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
"maximum_value_warning": "2 * machine_nozzle_size",
"default_value": 0.4,
"type": "float",
"value": "skin_line_width",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true,
"enabled": "roofing_layer_count > 0 and top_layers > 0"
},
"skin_line_width":
{
"label": "Top/Bottom Line Width",
@ -833,6 +847,7 @@
"unit": "%",
"default_value": 100.0,
"minimum_value": "0.001",
"maximum_value_warning": "150",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -848,47 +863,29 @@
"type": "category",
"children":
{
"wall_extruder_nr":
"wall_0_extruder_nr":
{
"label": "Wall Extruder",
"description": "The extruder train used for printing the walls. This is used in multi-extrusion.",
"label": "Outer Wall Extruder",
"description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "-1",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1",
"children":
{
"wall_0_extruder_nr":
{
"label": "Outer Wall Extruder",
"description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "wall_extruder_nr",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1"
},
"wall_x_extruder_nr":
{
"label": "Inner Walls Extruder",
"description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "wall_extruder_nr",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1"
}
}
"enabled": "machine_extruder_count > 1"
},
"wall_x_extruder_nr":
{
"label": "Inner Walls Extruder",
"description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1"
},
"wall_thickness":
{
@ -900,7 +897,7 @@
"minimum_value_warning": "line_width",
"maximum_value_warning": "10 * line_width",
"type": "float",
"limit_to_extruder": "wall_extruder_nr",
"limit_to_extruder": "wall_x_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -914,7 +911,7 @@
"maximum_value_warning": "10",
"type": "int",
"value": "1 if magic_spiralize else max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1) if wall_thickness != 0 else 0",
"limit_to_extruder": "wall_extruder_nr",
"limit_to_extruder": "wall_x_extruder_nr",
"settable_per_mesh": true
}
}
@ -932,13 +929,66 @@
"limit_to_extruder": "wall_0_extruder_nr",
"settable_per_mesh": true
},
"roofing_extruder_nr":
{
"label": "Top Surface Skin Extruder",
"description": "The extruder train used for printing the top most skin. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "top_bottom_extruder_nr",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0"
},
"roofing_layer_count":
{
"label": "Top Surface Skin Layers",
"description": "The number of top most skin layers. Usually only one top most layer is sufficient to generate higher quality top surfaces.",
"default_value": 0,
"minimum_value": "0",
"maximum_value_warning": "top_layers - 1",
"type": "int",
"value": "0",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true,
"enabled": "top_layers > 0"
},
"roofing_pattern":
{
"label": "Top Surface Skin Pattern",
"description": "The pattern of the top most layers.",
"type": "enum",
"options":
{
"lines": "Lines",
"concentric": "Concentric",
"zigzag": "Zig Zag"
},
"default_value": "lines",
"value": "top_bottom_pattern",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true,
"enabled": "roofing_layer_count > 0 and top_layers > 0"
},
"roofing_angles":
{
"label": "Top Surface Skin Line Directions",
"description": "A list of integer line directions to use when the top surface skin layers use the lines or zig zag pattern. 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).",
"type": "[int]",
"default_value": "[ ]",
"value": "skin_angles",
"enabled": "roofing_pattern != 'concentric' and roofing_layer_count > 0 and top_layers > 0",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true
},
"top_bottom_extruder_nr":
{
"label": "Top/Bottom Extruder",
"description": "The extruder train used for printing the top and bottom skin. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "-1",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
@ -1098,7 +1148,7 @@
"description": "Compensate the flow for parts of a wall being printed where there is already a wall in place.",
"type": "bool",
"default_value": true,
"limit_to_extruder": "wall_extruder_nr",
"limit_to_extruder": "wall_x_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -1244,7 +1294,6 @@
"description": "The extruder train used for printing infill. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"value": "-1",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
@ -1448,7 +1497,7 @@
"description": "Print the infill before printing the walls. Printing the walls first may lead to more accurate walls, but overhangs print worse. Printing the infill first leads to sturdier walls, but the infill pattern might sometimes show through the surface.",
"type": "bool",
"default_value": true,
"enabled": "infill_sparse_density > 0 and wall_extruder_nr == infill_extruder_nr",
"enabled": "infill_sparse_density > 0 and wall_x_extruder_nr == infill_extruder_nr",
"settable_per_mesh": true
},
"min_infill_area":
@ -1462,6 +1511,44 @@
"limit_to_extruder": "infill_extruder_nr",
"settable_per_mesh": true
},
"skin_preshrink":
{
"label": "Skin Pre-Shrink Distance",
"description": "The distance the skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing top/bottom skin at slanted surfaces in the model.",
"unit": "mm",
"type": "float",
"default_value": 0,
"minimum_value": "0",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true,
"children":
{
"top_skin_preshrink":
{
"label": "Top Skin Pre-Shrink Distance",
"description": "The distance the top skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing top skin at slanted surfaces in the model.",
"unit": "mm",
"type": "float",
"default_value": 0,
"value": "skin_preshrink",
"minimum_value": "0",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"bottom_skin_preshrink":
{
"label": "Bottom Skin Pre-Shrink Distance",
"description": "The distance the bottom skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing bottom skin at slanted surfaces in the model.",
"unit": "mm",
"type": "float",
"default_value": 0,
"value": "skin_preshrink",
"minimum_value": "0",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
}
}
},
"expand_skins_into_infill":
{
"label": "Expand Skins Into Infill",
@ -1754,7 +1841,7 @@
"unit": "mm/s",
"type": "float",
"default_value": 25,
"minimum_value": "0",
"minimum_value": "0.0001",
"minimum_value_warning": "1",
"maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "70",
@ -1770,7 +1857,7 @@
"unit": "mm/s",
"type": "float",
"default_value": 25,
"minimum_value": "0",
"minimum_value": "0.0001",
"maximum_value": "machine_max_feedrate_e",
"minimum_value_warning": "1",
"maximum_value_warning": "70",
@ -1786,7 +1873,7 @@
"unit": "mm/s",
"type": "float",
"default_value": 25,
"minimum_value": "0",
"minimum_value": "0.0001",
"maximum_value": "machine_max_feedrate_e",
"minimum_value_warning": "1",
"maximum_value_warning": "70",
@ -1977,7 +2064,6 @@
"maximum_value_warning": "150",
"default_value": 30,
"value": "speed_print / 2",
"limit_to_extruder": "wall_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -2011,6 +2097,21 @@
}
}
},
"speed_roofing":
{
"label": "Top Surface Skin Speed",
"description": "The speed at which top surface skin layers are printed.",
"unit": "mm/s",
"type": "float",
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150",
"default_value": 25,
"value": "speed_topbottom",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true,
"enabled": "roofing_layer_count > 0 and top_layers > 0"
},
"speed_topbottom":
{
"label": "Top/Bottom Speed",
@ -2025,21 +2126,6 @@
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"speed_ironing":
{
"label": "Ironing Speed",
"description": "The speed at which to pass over the top surface.",
"type": "float",
"unit": "mm/s",
"default_value": 20.0,
"value": "speed_topbottom * 20 / 30",
"minimum_value": "0.001",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "100",
"enabled": "ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"speed_support":
{
"label": "Support Speed",
@ -2315,7 +2401,6 @@
"default_value": 3000,
"value": "acceleration_print",
"enabled": "resolveOrValue('acceleration_enabled')",
"limit_to_extruder": "wall_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -2351,6 +2436,21 @@
}
}
},
"acceleration_roofing":
{
"label": "Top Surface Skin Acceleration",
"description": "The acceleration with which top surface skin layers are printed.",
"unit": "mm/s²",
"type": "float",
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"default_value": 3000,
"value": "acceleration_topbottom",
"enabled": "resolveOrValue('acceleration_enabled') and roofing_layer_count > 0 and top_layers > 0",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true
},
"acceleration_topbottom":
{
"label": "Top/Bottom Acceleration",
@ -2366,21 +2466,6 @@
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"acceleration_ironing":
{
"label": "Ironing Acceleration",
"description": "The acceleration with which ironing is performed.",
"unit": "mm/s²",
"type": "float",
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"default_value": 3000,
"value": "acceleration_topbottom",
"enabled": "resolveOrValue('acceleration_enabled') and ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"acceleration_support":
{
"label": "Support Acceleration",
@ -2606,7 +2691,6 @@
"default_value": 20,
"value": "jerk_print",
"enabled": "resolveOrValue('jerk_enabled')",
"limit_to_extruder": "wall_extruder_nr",
"settable_per_mesh": true,
"children":
{
@ -2640,6 +2724,20 @@
}
}
},
"jerk_roofing":
{
"label": "Top Surface Skin Jerk",
"description": "The maximum instantaneous velocity change with which top surface skin layers are printed.",
"unit": "mm/s",
"type": "float",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"default_value": 20,
"value": "jerk_topbottom",
"enabled": "resolveOrValue('jerk_enabled') and roofing_layer_count > 0 and top_layers > 0",
"limit_to_extruder": "roofing_extruder_nr",
"settable_per_mesh": true
},
"jerk_topbottom":
{
"label": "Top/Bottom Jerk",
@ -2654,20 +2752,6 @@
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"jerk_ironing":
{
"label": "Ironing Jerk",
"description": "The maximum instantaneous velocity change while performing ironing.",
"unit": "mm/s",
"type": "float",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"default_value": 20,
"value": "jerk_topbottom",
"enabled": "resolveOrValue('jerk_enabled') and ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"jerk_support":
{
"label": "Support Jerk",
@ -3269,6 +3353,46 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"support_skip_some_zags": {
"label": "Break Up Support In Chunks",
"description": "Skip some support line connections to make the support structure easier to break away. This setting is applicable to the Zig Zag support infill pattern.",
"type": "bool",
"default_value": false,
"enabled": "support_enable and (support_pattern == 'zigzag')",
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children": {
"support_skip_zag_per_mm": {
"label": "Support Chunk Size",
"description": "Leave out a connection between support lines once every N millimeter to make the support structure easier to break away.",
"type": "float",
"unit": "mm",
"default_value": 20,
"minimum_value": "0",
"minimum_value_warning": "support_line_distance",
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children": {
"support_zag_skip_count": {
"label": "Support Chunk Line Count",
"description": "Skip one in every N connection lines to make the support structure easier to break away.",
"type": "int",
"default_value": 5,
"value": "round(support_skip_zag_per_mm / support_line_distance)",
"minimum_value": "1",
"minimum_value_warning": "3",
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
}
}
}
}
},
"support_infill_rate":
{
"label": "Support Density",
@ -3473,7 +3597,7 @@
"description": "The height of support infill of a given density before switching to half the density.",
"unit": "mm",
"type": "float",
"default_value": 1.5,
"default_value": 1,
"minimum_value": "0.0001",
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
"enabled": "support_enable and support_infill_rate > 0 and gradual_support_infill_steps > 0",
@ -3912,7 +4036,7 @@
"default_value": 20,
"minimum_value": "0",
"maximum_value_warning": "50 / skirt_brim_line_width",
"value": "math.ceil(brim_width / skirt_brim_line_width)",
"value": "math.ceil(brim_width / (skirt_brim_line_width * initial_layer_line_width_factor / 100.0))",
"enabled": "resolveOrValue('adhesion_type') == 'brim'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -3931,6 +4055,30 @@
"settable_per_extruder": true,
"limit_to_extruder": "adhesion_extruder_nr"
},
"z_offset_layer_0":
{
"label": "Initial Layer Z Offset",
"description": "The extruder is offset from the normal height of the first layer by this amount. It can be positive (raised) or negative (lowered). Some filament types adhere to the build plate better if the extruder is raised slightly.",
"unit": "mm",
"type": "float",
"default_value": 0,
"minimum_value_warning": "0",
"maximum_value_warning": "layer_height_0",
"enabled": "resolveOrValue('adhesion_type') != 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"z_offset_taper_layers":
{
"label": "Z Offset Taper Layers",
"description": "When non-zero, the Z offset is reduced to 0 over that many layers. A value of 0 means that the Z offset remains constant for all the layers in the print.",
"type": "int",
"default_value": 0,
"minimum_value": "0",
"enabled": "resolveOrValue('adhesion_type') != 'raft' and z_offset_layer_0 != 0",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"raft_margin":
{
"label": "Raft Extra Margin",
@ -3945,6 +4093,20 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"raft_smoothing":
{
"label": "Raft Smoothing",
"description": "This setting control how much inner corners in the raft outline are rounded. Inward corners are rounded to a semi circle with a radius equal to the value given here. This setting also removes holes in the raft outline which are smaller than such a circle.",
"unit": "mm",
"type": "float",
"default_value": 5,
"minimum_value": "0",
"minimum_value_warning": "raft_interface_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"limit_to_extruder": "adhesion_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"raft_airgap":
{
"label": "Raft Air Gap",
@ -4463,6 +4625,7 @@
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_enable')",
"default_value": 200,
"value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - 1",
"maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width",
"minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')",
"settable_per_mesh": false,
@ -4476,6 +4639,7 @@
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_enable')",
"default_value": 200,
"value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - 1",
"maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')",
"minimum_value": "machine_depth / -2 if machine_center_is_zero else 0",
"settable_per_mesh": false,
@ -4525,7 +4689,7 @@
"unit": "mm³",
"default_value": 0,
"minimum_value": "0",
"maximum_value_warning": "0.5",
"maximum_value_warning": "1",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -4829,6 +4993,14 @@
"description": "experimental!",
"children":
{
"optimize_wall_printing_order":
{
"label": "Optimize Wall Printing Order",
"description": "Optimize the order in which walls are printed so as to reduce the number of retractions and the distance travelled. Most parts will benefit from this being enabled but some may actually take longer so please compare the print time estimates with and without optimization.",
"type": "bool",
"default_value": false,
"settable_per_mesh": true
},
"draft_shield_enabled":
{
"label": "Enable Draft Shield",
@ -5576,6 +5748,50 @@
"enabled": "ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"speed_ironing":
{
"label": "Ironing Speed",
"description": "The speed at which to pass over the top surface.",
"type": "float",
"unit": "mm/s",
"default_value": 20.0,
"value": "speed_topbottom * 20 / 30",
"minimum_value": "0.001",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "100",
"enabled": "ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"acceleration_ironing":
{
"label": "Ironing Acceleration",
"description": "The acceleration with which ironing is performed.",
"unit": "mm/s²",
"type": "float",
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"default_value": 3000,
"value": "acceleration_topbottom",
"enabled": "resolveOrValue('acceleration_enabled') and ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
},
"jerk_ironing":
{
"label": "Ironing Jerk",
"description": "The maximum instantaneous velocity change while performing ironing.",
"unit": "mm/s",
"type": "float",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"default_value": 20,
"value": "jerk_topbottom",
"enabled": "resolveOrValue('jerk_enabled') and ironing_enabled",
"limit_to_extruder": "top_bottom_extruder_nr",
"settable_per_mesh": true
}
}
},

View file

@ -6,7 +6,6 @@
"visible": true,
"author": "Jaime van Kessel & Paul Bussiere",
"manufacturer": "Folger Tech",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "FT-5_build_plate.stl"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Simon Cor",
"manufacturer": "German RepRap",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker.png",
"platform": "grr_neo_platform.stl"
@ -30,12 +29,6 @@
"machine_nozzle_size": {
"default_value": 0.5
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_polygon": {
"default_value": [
[-75, -18],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "BEEVERYCREATIVE",
"manufacturer": "BEEVERYCREATIVE",
"category": "Other",
"platform": "BEEVERYCREATIVE-helloBEEprusa.stl",
"platform_offset": [-226, -75, -196],
"file_formats": "text/x-gcode",

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "IMADE3D",
"manufacturer": "IMADE3D",
"category": "Other",
"platform": "imade3d_jellybox_platform.stl",
"platform_offset": [ 0, -0.3, 0],
"file_formats": "text/x-gcode",

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Adam Rumjahn",
"manufacturer": "Innovo",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "inventor_platform.stl",
"platform_offset": [-180, -0.25, 160]

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "Fracktal",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},

View file

@ -0,0 +1,59 @@
{
"id": "kemiq_q2_beta",
"version": 2,
"name": "Kemiq Q2 Beta",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "KEMIQ",
"manufacturer": "KEMIQ",
"file_formats": "text/x-gcode",
"platform": "kemiq_q2.stl",
"has_machine_quality": true,
"has_materials": true
},
"overrides": {
"machine_name": { "default_value": "Kemiq Q2 Beta" },
"machine_width": {
"default_value": 190
},
"machine_depth": {
"default_value": 200
},
"machine_height": {
"default_value": 273
},
"machine_heated_bed": {
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"gantry_height": {
"default_value": 0
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\nG92 E0\nG1 F200 E3\nG92 E0\nM80 ;Lights On"
},
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84\nM80 ;Lights Off"
}
}
}

View file

@ -0,0 +1,60 @@
{
"id": "kemiq_q2_gama",
"version": 2,
"name": "Kemiq Q2 Gama",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "KEMIQ",
"manufacturer": "KEMIQ",
"file_formats": "text/x-gcode",
"platform": "kemiq_q2.stl",
"has_machine_quality": true,
"has_materials": true
},
"overrides": {
"machine_name": {
"default_value": "Kemiq Q2 Gama"
},
"machine_width": {
"default_value": 190
},
"machine_depth": {
"default_value": 200
},
"machine_height": {
"default_value": 273
},
"machine_heated_bed": {
"default_value": false
},
"machine_center_is_zero": {
"default_value": false
},
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"gantry_height": {
"default_value": 0
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\nG92 E0\nG1 F200 E3\nG92 E0\nM80 ;Lights On"
},
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84\nM80 ;Lights Off"
}
}
}

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Claudio Sampaio (Patola)",
"manufacturer": "Other",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "kossel_platform.stl",
@ -36,12 +35,6 @@
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Chris Petersen",
"manufacturer": "OpenBeam",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "kossel_pro_build_platform.stl",
@ -35,12 +34,6 @@
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "Kupido",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ruben Dulek",
"manufacturer": "Malyan",
"category": "Other",
"file_formats": "application/x3g"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "makeR",
"manufacturer": "makeR",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "makeR_pegasus_platform.stl",
@ -37,12 +36,6 @@
"material_diameter": {
"default_value": 2.85
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_polygon": {
"default_value": [
[-75, -18],

View file

@ -7,11 +7,10 @@
"visible": true,
"author": "makeR",
"manufacturer": "makeR",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "makeR_prusa_tairona_i3_platform.stl",
"platform_offset": [-2,0,0]
"platform_offset": [-2, 0, 0]
},
"overrides": {
@ -37,12 +36,6 @@
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_polygon": {
"default_value": [
[-75, -18],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "NA",
"manufacturer": "NA",
"category": "Other",
"file_formats": "text/x-gcode",
"has_materials": false,
"supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ],
@ -35,12 +34,6 @@
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_with_fans_polygon":
{
"default_value": [
@ -72,10 +65,10 @@
"enabled": true
},
"prime_tower_position_x": {
"default_value": 185
"value": "185"
},
"prime_tower_position_y": {
"default_value": 160
"value": "160"
},
"material_diameter": {
"default_value": 1.75

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "NA",
"manufacturer": "NA",
"category": "Other",
"file_formats": "text/x-gcode",
"has_materials": false,
"supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ],
@ -35,12 +34,6 @@
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_with_fans_polygon":
{
"default_value": [
@ -72,10 +65,10 @@
"enabled": false
},
"prime_tower_position_x": {
"default_value": 185
"value": "185"
},
"prime_tower_position_y": {
"default_value": 160
"value": "160"
},
"material_diameter": {
"default_value": 1.75

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "tvlgiao",
"manufacturer": "3DMaker",
"category": "Other",
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj",
"icon": "icon_ultimaker2.png",
"platform": "makerstarter_platform.stl"
@ -33,12 +32,6 @@
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"gantry_height": {
"default_value": 55
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "MakerBot",
"category": "Other",
"file_formats": "application/x3g",
"platform_offset": [ 0, 0, 0]
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "RBC",
"manufacturer": "Mankati",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "mankati_fullscale_xt_plus_platform.stl"
},
@ -19,8 +18,6 @@
"machine_heated_bed": { "default_value": true },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[ -3, 3 ],

View file

@ -7,7 +7,6 @@
{
"visible": true,
"author": "Bo Herrmannsen",
"category": "Other",
"manufacturer": "Nophead",
"file_formats": "text/x-gcode",
"platform": "mendel90_platform.stl",
@ -62,12 +61,6 @@
"machine_heat_zone_length": {
"default_value": 16
},
"machine_nozzle_heat_up_speed": {
"default_value": 2.0
},
"machine_nozzle_cool_down_speed": {
"default_value": 2.0
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "ORD Solutions",
"category": "Other",
"file_formats": "text/x-gcode",
"machine_extruder_trains":
{

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "fieldOfView",
"manufacturer": "Peopoly",
"category": "Other",
"file_formats": "text/x-gcode",
"has_machine_quality": true,
"has_materials": false

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Chris Pearson",
"manufacturer": "Printrbot",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "printrbot_play.stl"
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Chris Pearson",
"manufacturer": "Printrbot",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": ""
},

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Calvindog717",
"manufacturer": "PrintrBot",
"category": "Other",
"platform": "printrbot_simple_metal_platform.stl",
"platform_offset": [0, -3.45, 0],
"file_formats": "text/x-gcode"
@ -22,8 +21,6 @@
"machine_center_is_zero": { "default_value": false },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[-49, 20],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "samsector",
"manufacturer": "PrintrBot",
"category": "Other",
"platform": "printrbot_simple_metal_upgrade.stl",
"platform_offset": [0, -0.3, 0],
"file_formats": "text/x-gcode"
@ -22,8 +21,6 @@
"machine_center_is_zero": { "default_value": false },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[ 55, -20 ],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Quillford",
"manufacturer": "Prusajr",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "prusai3_platform.stl"
@ -36,12 +35,6 @@
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_polygon": {
"default_value": [
[-75, -18],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Apsu",
"manufacturer": "Prusa Research",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "prusai3_platform.stl",
@ -31,8 +30,6 @@
"retraction_retract_speed": { "default_value": 35 },
"retraction_prime_speed": { "default_value": 35 },
"adhesion_type": { "default_value": "skirt" },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": { "default_value": [[-31,31],[34,31],[34,-40],[-31,-40]] },
"gantry_height": { "default_value": 28 },
"machine_max_feedrate_z": { "default_value": 12 },

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "guigashm",
"manufacturer": "Prusajr",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2.png",
"platform": "prusai3_xl_platform.stl"
@ -36,12 +35,6 @@
"material_diameter": {
"default_value": 1.75
},
"machine_nozzle_heat_up_speed": {
"default_value": 2.0
},
"machine_nozzle_cool_down_speed": {
"default_value": 2.0
},
"machine_head_polygon": {
"default_value": [
[-75, -18],

View file

@ -7,7 +7,6 @@
"visible": true,
"author": "Ultimaker",
"manufacturer": "Punchtec",
"category": "Other",
"file_formats": "text/x-gcode",
"machine_extruder_trains":
{

View file

@ -5,7 +5,6 @@
"inherits": "fdmprinter",
"metadata": {
"author": "Simon Peter (based on RF100.ini by Conrad Electronic SE)",
"category": "Other",
"file_formats": "text/x-gcode",
"manufacturer": "Renkforce",
"visible": true

Some files were not shown because too many files have changed in this diff Show more