mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-06 21:44:01 -06:00
Merge branch 'master' into quarter_cubic_infill
This commit is contained in:
commit
2c7c29dc71
224 changed files with 93289 additions and 70955 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
4
Jenkinsfile
vendored
|
@ -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".
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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"])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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])
|
||||
|
|
65
cura/Settings/PerObjectContainerStack.py
Normal file
65
cura/Settings/PerObjectContainerStack.py
Normal 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()
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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 : ""
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 ],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "ALYA",
|
||||
"manufacturer": "ALYA",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "BFB",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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": [
|
||||
|
|
95
resources/definitions/creality_cr10_beta.def.json
Normal file
95
resources/definitions/creality_cr10_beta.def.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
23
resources/definitions/creality_cr10s4_beta.def.json
Normal file
23
resources/definitions/creality_cr10s4_beta.def.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
23
resources/definitions/creality_cr10s5_beta.def.json
Normal file
23
resources/definitions/creality_cr10s5_beta.def.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Dagoma",
|
||||
"manufacturer": "Dagoma",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "discoeasy200.stl",
|
||||
|
|
|
@ -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"}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Danny Lu",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "nliaudat",
|
||||
"manufacturer": "EasyArts (discontinued)",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
"metadata":
|
||||
{
|
||||
"type": "extruder",
|
||||
"author": "Ultimaker B.V.",
|
||||
"manufacturer": "Ultimaker",
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Unknown",
|
||||
"setting_version": 1,
|
||||
"visible": false
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Fracktal",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
|
59
resources/definitions/kemiq_q2_beta.def.json
Normal file
59
resources/definitions/kemiq_q2_beta.def.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
60
resources/definitions/kemiq_q2_gama.def.json
Normal file
60
resources/definitions/kemiq_q2_gama.def.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)"
|
||||
},
|
||||
|
|
|
@ -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)"
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Kupido",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ruben Dulek",
|
||||
"manufacturer": "Malyan",
|
||||
"category": "Other",
|
||||
"file_formats": "application/x3g"
|
||||
},
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "MakerBot",
|
||||
"category": "Other",
|
||||
"file_formats": "application/x3g",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
|
|
@ -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 ],
|
||||
|
|
|
@ -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)"
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "ORD Solutions",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "fieldOfView",
|
||||
"manufacturer": "Peopoly",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_machine_quality": true,
|
||||
"has_materials": false
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Chris Pearson",
|
||||
"manufacturer": "Printrbot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "printrbot_play.stl"
|
||||
},
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Chris Pearson",
|
||||
"manufacturer": "Printrbot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": ""
|
||||
},
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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 ],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Punchtec",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue