mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 11:14:21 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura into layerview_dev
This commit is contained in:
commit
c6790981d6
@ -1,7 +1,9 @@
|
|||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.Scene.Platform import Platform
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
@ -17,6 +19,30 @@ from UM.View.GL.OpenGL import OpenGL
|
|||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
import copy
|
||||||
|
|
||||||
|
|
||||||
|
# Setting for clearance around the prime
|
||||||
|
PRIME_CLEARANCE = 10
|
||||||
|
|
||||||
|
|
||||||
|
def approximatedCircleVertices(r):
|
||||||
|
"""
|
||||||
|
Return vertices from an approximated circle.
|
||||||
|
:param r: radius
|
||||||
|
:return: numpy 2-array with the vertices
|
||||||
|
"""
|
||||||
|
|
||||||
|
return numpy.array([
|
||||||
|
[-r, 0],
|
||||||
|
[-r * 0.707, r * 0.707],
|
||||||
|
[0, r],
|
||||||
|
[r * 0.707, r * 0.707],
|
||||||
|
[r, 0],
|
||||||
|
[r * 0.707, -r * 0.707],
|
||||||
|
[0, -r],
|
||||||
|
[-r * 0.707, -r * 0.707]
|
||||||
|
], numpy.float32)
|
||||||
|
|
||||||
|
|
||||||
## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas.
|
## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas.
|
||||||
@ -41,6 +67,11 @@ class BuildVolume(SceneNode):
|
|||||||
self.setCalculateBoundingBox(False)
|
self.setCalculateBoundingBox(False)
|
||||||
self._volume_aabb = None
|
self._volume_aabb = None
|
||||||
|
|
||||||
|
self._raft_thickness = 0.0
|
||||||
|
self._adhesion_type = None
|
||||||
|
self._raft_mesh = None
|
||||||
|
self._platform = Platform(self)
|
||||||
|
|
||||||
self._active_container_stack = None
|
self._active_container_stack = None
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
|
||||||
self._onGlobalContainerStackChanged()
|
self._onGlobalContainerStackChanged()
|
||||||
@ -72,6 +103,9 @@ class BuildVolume(SceneNode):
|
|||||||
renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
|
renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
|
||||||
if self._disallowed_area_mesh:
|
if self._disallowed_area_mesh:
|
||||||
renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9)
|
renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9)
|
||||||
|
if self._raft_mesh and self._adhesion_type == "raft":
|
||||||
|
renderer.queueNode(self, mesh=self._raft_mesh, transparent=True, backface_cull=True, sort=-9)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
## Recalculates the build volume & disallowed areas.
|
## Recalculates the build volume & disallowed areas.
|
||||||
@ -88,6 +122,7 @@ class BuildVolume(SceneNode):
|
|||||||
|
|
||||||
mb = MeshBuilder()
|
mb = MeshBuilder()
|
||||||
|
|
||||||
|
# Outline 'cube' of the build volume
|
||||||
mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
|
mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
|
||||||
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
|
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
|
||||||
mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
|
mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
|
||||||
@ -112,11 +147,23 @@ class BuildVolume(SceneNode):
|
|||||||
Vector(max_w, min_h - 0.2, max_d),
|
Vector(max_w, min_h - 0.2, max_d),
|
||||||
Vector(min_w, min_h - 0.2, max_d)
|
Vector(min_w, min_h - 0.2, max_d)
|
||||||
)
|
)
|
||||||
|
|
||||||
for n in range(0, 6):
|
for n in range(0, 6):
|
||||||
v = mb.getVertex(n)
|
v = mb.getVertex(n)
|
||||||
mb.setVertexUVCoordinates(n, v[0], v[2])
|
mb.setVertexUVCoordinates(n, v[0], v[2])
|
||||||
self._grid_mesh = mb.build()
|
self._grid_mesh = mb.build()
|
||||||
|
|
||||||
|
# Build raft mesh: a plane on the height of the raft.
|
||||||
|
mb = MeshBuilder()
|
||||||
|
mb.addQuad(
|
||||||
|
Vector(min_w, self._raft_thickness, min_d),
|
||||||
|
Vector(max_w, self._raft_thickness, min_d),
|
||||||
|
Vector(max_w, self._raft_thickness, max_d),
|
||||||
|
Vector(min_w, self._raft_thickness, max_d),
|
||||||
|
color=Color(128, 128, 128, 64)
|
||||||
|
)
|
||||||
|
self._raft_mesh = mb.build()
|
||||||
|
|
||||||
disallowed_area_height = 0.1
|
disallowed_area_height = 0.1
|
||||||
disallowed_area_size = 0
|
disallowed_area_size = 0
|
||||||
if self._disallowed_areas:
|
if self._disallowed_areas:
|
||||||
@ -144,7 +191,9 @@ class BuildVolume(SceneNode):
|
|||||||
else:
|
else:
|
||||||
self._disallowed_area_mesh = None
|
self._disallowed_area_mesh = None
|
||||||
|
|
||||||
self._volume_aabb = AxisAlignedBox(minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h, max_d))
|
self._volume_aabb = AxisAlignedBox(
|
||||||
|
minimum = Vector(min_w, min_h - 1.0, min_d),
|
||||||
|
maximum = Vector(max_w, max_h - self._raft_thickness, max_d))
|
||||||
|
|
||||||
skirt_size = 0.0
|
skirt_size = 0.0
|
||||||
|
|
||||||
@ -157,7 +206,7 @@ class BuildVolume(SceneNode):
|
|||||||
# The +1 and -1 is added as there is always a bit of extra room required to work properly.
|
# The +1 and -1 is added as there is always a bit of extra room required to work properly.
|
||||||
scale_to_max_bounds = AxisAlignedBox(
|
scale_to_max_bounds = AxisAlignedBox(
|
||||||
minimum = Vector(min_w + skirt_size + 1, min_h, min_d + disallowed_area_size - skirt_size + 1),
|
minimum = Vector(min_w + skirt_size + 1, min_h, min_d + disallowed_area_size - skirt_size + 1),
|
||||||
maximum = Vector(max_w - skirt_size - 1, max_h, max_d - disallowed_area_size + skirt_size - 1)
|
maximum = Vector(max_w - skirt_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + skirt_size - 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
|
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
|
||||||
@ -172,6 +221,21 @@ class BuildVolume(SceneNode):
|
|||||||
" \"Print Sequence\" setting to prevent the gantry from colliding"
|
" \"Print Sequence\" setting to prevent the gantry from colliding"
|
||||||
" with printed objects."), lifetime=10).show()
|
" with printed objects."), lifetime=10).show()
|
||||||
|
|
||||||
|
def _updateRaftThickness(self):
|
||||||
|
old_raft_thickness = self._raft_thickness
|
||||||
|
self._adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value")
|
||||||
|
self._raft_thickness = 0.0
|
||||||
|
if self._adhesion_type == "raft":
|
||||||
|
self._raft_thickness = (
|
||||||
|
self._active_container_stack.getProperty("raft_base_thickness", "value") +
|
||||||
|
self._active_container_stack.getProperty("raft_interface_thickness", "value") +
|
||||||
|
self._active_container_stack.getProperty("raft_surface_layers", "value") *
|
||||||
|
self._active_container_stack.getProperty("raft_surface_thickness", "value") +
|
||||||
|
self._active_container_stack.getProperty("raft_airgap", "value"))
|
||||||
|
# Rounding errors do not matter, we check if raft_thickness has changed at all
|
||||||
|
if old_raft_thickness != self._raft_thickness:
|
||||||
|
self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World)
|
||||||
|
|
||||||
def _onGlobalContainerStackChanged(self):
|
def _onGlobalContainerStackChanged(self):
|
||||||
if self._active_container_stack:
|
if self._active_container_stack:
|
||||||
self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
|
self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
|
||||||
@ -190,6 +254,7 @@ class BuildVolume(SceneNode):
|
|||||||
self._depth = self._active_container_stack.getProperty("machine_depth", "value")
|
self._depth = self._active_container_stack.getProperty("machine_depth", "value")
|
||||||
|
|
||||||
self._updateDisallowedAreas()
|
self._updateDisallowedAreas()
|
||||||
|
self._updateRaftThickness()
|
||||||
|
|
||||||
self.rebuild()
|
self.rebuild()
|
||||||
|
|
||||||
@ -197,40 +262,62 @@ class BuildVolume(SceneNode):
|
|||||||
if property_name != "value":
|
if property_name != "value":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
rebuild_me = False
|
||||||
if setting_key == "print_sequence":
|
if setting_key == "print_sequence":
|
||||||
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time":
|
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time":
|
||||||
self._height = self._active_container_stack.getProperty("gantry_height", "value")
|
self._height = self._active_container_stack.getProperty("gantry_height", "value")
|
||||||
self._buildVolumeMessage()
|
self._buildVolumeMessage()
|
||||||
else:
|
else:
|
||||||
self._height = self._active_container_stack.getProperty("machine_height", "value")
|
self._height = self._active_container_stack.getProperty("machine_height", "value")
|
||||||
self.rebuild()
|
rebuild_me = True
|
||||||
|
|
||||||
if setting_key in self._skirt_settings:
|
if setting_key in self._skirt_settings:
|
||||||
self._updateDisallowedAreas()
|
self._updateDisallowedAreas()
|
||||||
|
rebuild_me = True
|
||||||
|
|
||||||
|
if setting_key in self._raft_settings:
|
||||||
|
self._updateRaftThickness()
|
||||||
|
rebuild_me = True
|
||||||
|
|
||||||
|
if rebuild_me:
|
||||||
self.rebuild()
|
self.rebuild()
|
||||||
|
|
||||||
def _updateDisallowedAreas(self):
|
def _updateDisallowedAreas(self):
|
||||||
if not self._active_container_stack:
|
if not self._active_container_stack:
|
||||||
return
|
return
|
||||||
|
|
||||||
disallowed_areas = self._active_container_stack.getProperty("machine_disallowed_areas", "value")
|
disallowed_areas = copy.deepcopy(
|
||||||
|
self._active_container_stack.getProperty("machine_disallowed_areas", "value"))
|
||||||
areas = []
|
areas = []
|
||||||
|
|
||||||
|
# Add extruder prime locations as disallowed areas.
|
||||||
|
# Probably needs some rework after coordinate system change.
|
||||||
|
extruder_manager = ExtruderManager.getInstance()
|
||||||
|
extruders = extruder_manager.getMachineExtruders(self._active_container_stack.getId())
|
||||||
|
machine_width = self._active_container_stack.getProperty("machine_width", "value")
|
||||||
|
machine_depth = self._active_container_stack.getProperty("machine_depth", "value")
|
||||||
|
for single_extruder in extruders:
|
||||||
|
extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value")
|
||||||
|
extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value")
|
||||||
|
# TODO: calculate everything in CuraEngine/Firmware/lower left as origin coordinates.
|
||||||
|
# Here we transform the extruder prime pos (lower left as origin) to Cura coordinates
|
||||||
|
# (center as origin, y from back to front)
|
||||||
|
prime_x = extruder_prime_pos_x - machine_width / 2
|
||||||
|
prime_y = machine_depth / 2 - extruder_prime_pos_y
|
||||||
|
disallowed_areas.append([
|
||||||
|
[prime_x - PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE],
|
||||||
|
[prime_x + PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE],
|
||||||
|
[prime_x + PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE],
|
||||||
|
[prime_x - PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE],
|
||||||
|
])
|
||||||
|
|
||||||
skirt_size = self._getSkirtSize(self._active_container_stack)
|
skirt_size = self._getSkirtSize(self._active_container_stack)
|
||||||
|
|
||||||
if disallowed_areas:
|
if disallowed_areas:
|
||||||
# Extend every area already in the disallowed_areas with the skirt size.
|
# Extend every area already in the disallowed_areas with the skirt size.
|
||||||
for area in disallowed_areas:
|
for area in disallowed_areas:
|
||||||
poly = Polygon(numpy.array(area, numpy.float32))
|
poly = Polygon(numpy.array(area, numpy.float32))
|
||||||
poly = poly.getMinkowskiHull(Polygon(numpy.array([
|
poly = poly.getMinkowskiHull(Polygon(approximatedCircleVertices(skirt_size)))
|
||||||
[-skirt_size, 0],
|
|
||||||
[-skirt_size * 0.707, skirt_size * 0.707],
|
|
||||||
[0, skirt_size],
|
|
||||||
[skirt_size * 0.707, skirt_size * 0.707],
|
|
||||||
[skirt_size, 0],
|
|
||||||
[skirt_size * 0.707, -skirt_size * 0.707],
|
|
||||||
[0, -skirt_size],
|
|
||||||
[-skirt_size * 0.707, -skirt_size * 0.707]
|
|
||||||
], numpy.float32)))
|
|
||||||
|
|
||||||
areas.append(poly)
|
areas.append(poly)
|
||||||
|
|
||||||
@ -269,7 +356,7 @@ class BuildVolume(SceneNode):
|
|||||||
|
|
||||||
self._disallowed_areas = areas
|
self._disallowed_areas = areas
|
||||||
|
|
||||||
## Convenience function to calculate the size of the bed adhesion.
|
## Convenience function to calculate the size of the bed adhesion in directions x, y.
|
||||||
def _getSkirtSize(self, container_stack):
|
def _getSkirtSize(self, container_stack):
|
||||||
skirt_size = 0.0
|
skirt_size = 0.0
|
||||||
|
|
||||||
@ -295,3 +382,4 @@ class BuildVolume(SceneNode):
|
|||||||
return max(min(value, max_value), min_value)
|
return max(min(value, max_value), min_value)
|
||||||
|
|
||||||
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
|
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
|
||||||
|
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
|
||||||
|
@ -157,7 +157,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
|
vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
|
||||||
# Don't use data below 0.
|
# Don't use data below 0.
|
||||||
# TODO; We need a better check for this as this gives poor results for meshes with long edges.
|
# TODO; We need a better check for this as this gives poor results for meshes with long edges.
|
||||||
vertex_data = vertex_data[vertex_data[:,1] >= 0]
|
vertex_data = vertex_data[vertex_data[:,1] >= -0.01]
|
||||||
|
|
||||||
if len(vertex_data) >= 4:
|
if len(vertex_data) >= 4:
|
||||||
# Round the vertex data to 1/10th of a mm, then remove all duplicate vertices
|
# Round the vertex data to 1/10th of a mm, then remove all duplicate vertices
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
from UM.Qt.QtApplication import QtApplication
|
from UM.Qt.QtApplication import QtApplication
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Scene.Camera import Camera
|
from UM.Scene.Camera import Camera
|
||||||
from UM.Scene.Platform import Platform as Scene_Platform
|
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Math.Quaternion import Quaternion
|
from UM.Math.Quaternion import Quaternion
|
||||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||||
@ -126,6 +125,7 @@ class CuraApplication(QtApplication):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._machine_action_manager = MachineActionManager.MachineActionManager()
|
self._machine_action_manager = MachineActionManager.MachineActionManager()
|
||||||
|
self._machine_manager = None # This is initialized on demand.
|
||||||
|
|
||||||
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
|
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
|
||||||
|
|
||||||
@ -143,7 +143,6 @@ class CuraApplication(QtApplication):
|
|||||||
])
|
])
|
||||||
self._physics = None
|
self._physics = None
|
||||||
self._volume = None
|
self._volume = None
|
||||||
self._platform = None
|
|
||||||
self._output_devices = {}
|
self._output_devices = {}
|
||||||
self._print_information = None
|
self._print_information = None
|
||||||
self._previous_active_tool = None
|
self._previous_active_tool = None
|
||||||
@ -195,6 +194,14 @@ class CuraApplication(QtApplication):
|
|||||||
Preferences.getInstance().addPreference("view/center_on_select", True)
|
Preferences.getInstance().addPreference("view/center_on_select", True)
|
||||||
Preferences.getInstance().addPreference("mesh/scale_to_fit", True)
|
Preferences.getInstance().addPreference("mesh/scale_to_fit", True)
|
||||||
Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True)
|
Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True)
|
||||||
|
|
||||||
|
for key in [
|
||||||
|
"dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin
|
||||||
|
"dialog_profile_path",
|
||||||
|
"dialog_material_path"]:
|
||||||
|
|
||||||
|
Preferences.getInstance().addPreference("local_file/%s" % key, "~/")
|
||||||
|
|
||||||
Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode")
|
Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode")
|
||||||
|
|
||||||
Preferences.getInstance().setDefault("general/visible_settings", """
|
Preferences.getInstance().setDefault("general/visible_settings", """
|
||||||
@ -333,10 +340,15 @@ class CuraApplication(QtApplication):
|
|||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(result = QUrl)
|
@pyqtSlot(str, result = QUrl)
|
||||||
def getDefaultPath(self):
|
def getDefaultPath(self, key):
|
||||||
return QUrl.fromLocalFile(os.path.expanduser("~/"))
|
default_path = Preferences.getInstance().getValue("local_file/%s" % key)
|
||||||
|
return QUrl.fromLocalFile(default_path)
|
||||||
|
|
||||||
|
@pyqtSlot(str, str)
|
||||||
|
def setDefaultPath(self, key, default_path):
|
||||||
|
Preferences.getInstance().setValue("local_file/%s" % key, default_path)
|
||||||
|
|
||||||
## Handle loading of all plugin types (and the backend explicitly)
|
## Handle loading of all plugin types (and the backend explicitly)
|
||||||
# \sa PluginRegistery
|
# \sa PluginRegistery
|
||||||
def _loadPlugins(self):
|
def _loadPlugins(self):
|
||||||
@ -376,8 +388,8 @@ class CuraApplication(QtApplication):
|
|||||||
Selection.selectionChanged.connect(self.onSelectionChanged)
|
Selection.selectionChanged.connect(self.onSelectionChanged)
|
||||||
|
|
||||||
root = controller.getScene().getRoot()
|
root = controller.getScene().getRoot()
|
||||||
self._platform = Scene_Platform(root)
|
|
||||||
|
|
||||||
|
# The platform is a child of BuildVolume
|
||||||
self._volume = BuildVolume.BuildVolume(root)
|
self._volume = BuildVolume.BuildVolume(root)
|
||||||
|
|
||||||
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
||||||
@ -399,8 +411,7 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
# Initialise extruder so as to listen to global container stack changes before the first global container stack is set.
|
# Initialise extruder so as to listen to global container stack changes before the first global container stack is set.
|
||||||
cura.Settings.ExtruderManager.getInstance()
|
cura.Settings.ExtruderManager.getInstance()
|
||||||
qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager",
|
qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager)
|
||||||
cura.Settings.MachineManager.createMachineManager)
|
|
||||||
|
|
||||||
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
|
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
|
||||||
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
||||||
@ -419,6 +430,11 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
|
def getMachineManager(self, *args):
|
||||||
|
if self._machine_manager is None:
|
||||||
|
self._machine_manager = cura.Settings.MachineManager.createMachineManager()
|
||||||
|
return self._machine_manager
|
||||||
|
|
||||||
## Get the machine action manager
|
## Get the machine action manager
|
||||||
# We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
# We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
||||||
# It wants to give this function an engine and script engine, but we don't care about that.
|
# It wants to give this function an engine and script engine, but we don't care about that.
|
||||||
@ -559,15 +575,18 @@ class CuraApplication(QtApplication):
|
|||||||
node = Selection.getSelectedObject(0)
|
node = Selection.getSelectedObject(0)
|
||||||
|
|
||||||
if node:
|
if node:
|
||||||
|
group_node = None
|
||||||
if node.getParent():
|
if node.getParent():
|
||||||
group_node = node.getParent()
|
group_node = node.getParent()
|
||||||
if not group_node.callDecoration("isGroup"):
|
op = RemoveSceneNodeOperation(node)
|
||||||
op = RemoveSceneNodeOperation(node)
|
|
||||||
else:
|
|
||||||
while group_node.getParent().callDecoration("isGroup"):
|
|
||||||
group_node = group_node.getParent()
|
|
||||||
op = RemoveSceneNodeOperation(group_node)
|
|
||||||
op.push()
|
op.push()
|
||||||
|
if group_node:
|
||||||
|
if len(group_node.getChildren()) == 1 and group_node.callDecoration("isGroup"):
|
||||||
|
group_node.getChildren()[0].translate(group_node.getPosition())
|
||||||
|
group_node.getChildren()[0].setParent(group_node.getParent())
|
||||||
|
op = RemoveSceneNodeOperation(group_node)
|
||||||
|
op.push()
|
||||||
|
|
||||||
## Create a number of copies of existing object.
|
## Create a number of copies of existing object.
|
||||||
@pyqtSlot("quint64", int)
|
@pyqtSlot("quint64", int)
|
||||||
@ -578,18 +597,16 @@ class CuraApplication(QtApplication):
|
|||||||
node = Selection.getSelectedObject(0)
|
node = Selection.getSelectedObject(0)
|
||||||
|
|
||||||
if node:
|
if node:
|
||||||
|
current_node = node
|
||||||
|
# Find the topmost group
|
||||||
|
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
|
||||||
|
current_node = current_node.getParent()
|
||||||
|
|
||||||
|
new_node = copy.deepcopy(current_node)
|
||||||
|
|
||||||
op = GroupedOperation()
|
op = GroupedOperation()
|
||||||
for _ in range(count):
|
for _ in range(count):
|
||||||
if node.getParent() and node.getParent().callDecoration("isGroup"):
|
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||||
new_node = copy.deepcopy(node.getParent()) #Copy the group node.
|
|
||||||
new_node.callDecoration("recomputeConvexHull")
|
|
||||||
|
|
||||||
op.addOperation(AddSceneNodeOperation(new_node,node.getParent().getParent()))
|
|
||||||
else:
|
|
||||||
new_node = copy.deepcopy(node)
|
|
||||||
new_node.callDecoration("recomputeConvexHull")
|
|
||||||
op.addOperation(AddSceneNodeOperation(new_node, node.getParent()))
|
|
||||||
|
|
||||||
op.push()
|
op.push()
|
||||||
|
|
||||||
## Center object on platform.
|
## Center object on platform.
|
||||||
@ -835,7 +852,11 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
def _reloadMeshFinished(self, job):
|
def _reloadMeshFinished(self, job):
|
||||||
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
|
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
|
||||||
job._node.setMeshData(job.getResult().getMeshData())
|
mesh_data = job.getResult().getMeshData()
|
||||||
|
if mesh_data:
|
||||||
|
job._node.setMeshData(mesh_data)
|
||||||
|
else:
|
||||||
|
Logger.log("w", "Could not find a mesh in reloaded node.")
|
||||||
|
|
||||||
def _openFile(self, file):
|
def _openFile(self, file):
|
||||||
job = ReadMeshJob(os.path.abspath(file))
|
job = ReadMeshJob(os.path.abspath(file))
|
||||||
@ -852,3 +873,6 @@ class CuraApplication(QtApplication):
|
|||||||
@pyqtSlot("QSize")
|
@pyqtSlot("QSize")
|
||||||
def setMinimumWindowSize(self, size):
|
def setMinimumWindowSize(self, size):
|
||||||
self.getMainWindow().setMinimumSize(size)
|
self.getMainWindow().setMinimumSize(size)
|
||||||
|
|
||||||
|
def getBuildVolume(self):
|
||||||
|
return self._volume
|
@ -40,6 +40,7 @@ class PlatformPhysics:
|
|||||||
return
|
return
|
||||||
|
|
||||||
root = self._controller.getScene().getRoot()
|
root = self._controller.getScene().getRoot()
|
||||||
|
|
||||||
for node in BreadthFirstIterator(root):
|
for node in BreadthFirstIterator(root):
|
||||||
if node is root or type(node) is not SceneNode or node.getBoundingBox() is None:
|
if node is root or type(node) is not SceneNode or node.getBoundingBox() is None:
|
||||||
continue
|
continue
|
||||||
@ -47,7 +48,14 @@ class PlatformPhysics:
|
|||||||
bbox = node.getBoundingBox()
|
bbox = node.getBoundingBox()
|
||||||
|
|
||||||
# Ignore intersections with the bottom
|
# Ignore intersections with the bottom
|
||||||
build_volume_bounding_box = self._build_volume.getBoundingBox().set(bottom=-9001)
|
build_volume_bounding_box = self._build_volume.getBoundingBox()
|
||||||
|
if build_volume_bounding_box:
|
||||||
|
# It's over 9000!
|
||||||
|
build_volume_bounding_box = build_volume_bounding_box.set(bottom=-9001)
|
||||||
|
else:
|
||||||
|
# No bounding box. This is triggered when running Cura from command line with a model for the first time
|
||||||
|
# In that situation there is a model, but no machine (and therefore no build volume.
|
||||||
|
return
|
||||||
node._outside_buildarea = False
|
node._outside_buildarea = False
|
||||||
|
|
||||||
# Mark the node as outside the build volume if the bounding box test fails.
|
# Mark the node as outside the build volume if the bounding box test fails.
|
||||||
@ -58,10 +66,7 @@ class PlatformPhysics:
|
|||||||
move_vector = Vector()
|
move_vector = Vector()
|
||||||
if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down
|
if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down
|
||||||
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
|
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
|
||||||
if bbox.bottom > 0:
|
move_vector = move_vector.set(y=-bbox.bottom + z_offset)
|
||||||
move_vector = move_vector.set(y=-bbox.bottom + z_offset)
|
|
||||||
elif bbox.bottom < z_offset:
|
|
||||||
move_vector = move_vector.set(y=(-bbox.bottom) - z_offset)
|
|
||||||
|
|
||||||
# If there is no convex hull for the node, start calculating it and continue.
|
# If there is no convex hull for the node, start calculating it and continue.
|
||||||
if not node.getDecorator(ConvexHullDecorator):
|
if not node.getDecorator(ConvexHullDecorator):
|
||||||
|
@ -7,6 +7,8 @@ from UM.Application import Application
|
|||||||
from UM.Qt.Duration import Duration
|
from UM.Qt.Duration import Duration
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
|
|
||||||
|
import cura.Settings.ExtruderManager
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import os.path
|
import os.path
|
||||||
import unicodedata
|
import unicodedata
|
||||||
@ -44,7 +46,8 @@ class PrintInformation(QObject):
|
|||||||
|
|
||||||
self._current_print_time = Duration(None, self)
|
self._current_print_time = Duration(None, self)
|
||||||
|
|
||||||
self._material_amounts = []
|
self._material_lengths = []
|
||||||
|
self._material_weights = []
|
||||||
|
|
||||||
self._backend = Application.getInstance().getBackend()
|
self._backend = Application.getInstance().getBackend()
|
||||||
if self._backend:
|
if self._backend:
|
||||||
@ -62,11 +65,17 @@ class PrintInformation(QObject):
|
|||||||
def currentPrintTime(self):
|
def currentPrintTime(self):
|
||||||
return self._current_print_time
|
return self._current_print_time
|
||||||
|
|
||||||
materialAmountsChanged = pyqtSignal()
|
materialLengthsChanged = pyqtSignal()
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify = materialAmountsChanged)
|
@pyqtProperty("QVariantList", notify = materialLengthsChanged)
|
||||||
def materialAmounts(self):
|
def materialLengths(self):
|
||||||
return self._material_amounts
|
return self._material_lengths
|
||||||
|
|
||||||
|
materialWeightsChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtProperty("QVariantList", notify = materialWeightsChanged)
|
||||||
|
def materialWeights(self):
|
||||||
|
return self._material_weights
|
||||||
|
|
||||||
def _onPrintDurationMessage(self, total_time, material_amounts):
|
def _onPrintDurationMessage(self, total_time, material_amounts):
|
||||||
self._current_print_time.setDuration(total_time)
|
self._current_print_time.setDuration(total_time)
|
||||||
@ -74,13 +83,28 @@ class PrintInformation(QObject):
|
|||||||
|
|
||||||
# Material amount is sent as an amount of mm^3, so calculate length from that
|
# Material amount is sent as an amount of mm^3, so calculate length from that
|
||||||
r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
|
r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
|
||||||
self._material_amounts = []
|
self._material_lengths = []
|
||||||
for amount in material_amounts:
|
self._material_weights = []
|
||||||
self._material_amounts.append(round((amount / (math.pi * r ** 2)) / 1000, 2))
|
extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId()))
|
||||||
self.materialAmountsChanged.emit()
|
for index, amount in enumerate(material_amounts):
|
||||||
|
## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
|
||||||
|
# list comprehension filtering to solve this for us.
|
||||||
|
if extruder_stacks: # Multi extrusion machine
|
||||||
|
extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0]
|
||||||
|
density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0)
|
||||||
|
else: # Machine with no extruder stacks
|
||||||
|
density = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("properties", {}).get("density", 0)
|
||||||
|
|
||||||
|
self._material_weights.append(float(amount) * float(density))
|
||||||
|
self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2))
|
||||||
|
self.materialLengthsChanged.emit()
|
||||||
|
self.materialWeightsChanged.emit()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def setJobName(self, name):
|
def setJobName(self, name):
|
||||||
|
# Ensure that we don't use entire path but only filename
|
||||||
|
name = os.path.basename(name)
|
||||||
|
|
||||||
# when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
|
# when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
|
||||||
# extension. This cuts the extension off if necessary.
|
# extension. This cuts the extension off if necessary.
|
||||||
name = os.path.splitext(name)[0]
|
name = os.path.splitext(name)[0]
|
||||||
|
@ -12,6 +12,6 @@ class ProfileReader(PluginObject):
|
|||||||
|
|
||||||
## Read profile data from a file and return a filled profile.
|
## Read profile data from a file and return a filled profile.
|
||||||
#
|
#
|
||||||
# \return \type{Profile} The profile that was obtained from the file.
|
# \return \type{Profile|Profile[]} The profile that was obtained from the file or a list of Profiles.
|
||||||
def read(self, file_name):
|
def read(self, file_name):
|
||||||
raise NotImplementedError("Profile reader plug-in was not correctly implemented. The read function was not implemented.")
|
raise NotImplementedError("Profile reader plug-in was not correctly implemented. The read function was not implemented.")
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
|
|
||||||
|
@ -133,32 +133,45 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
||||||
profile_reader = plugin_registry.getPluginObject(plugin_id)
|
profile_reader = plugin_registry.getPluginObject(plugin_id)
|
||||||
try:
|
try:
|
||||||
profile = profile_reader.read(file_name) #Try to open the file with the profile reader.
|
profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader.
|
||||||
except Exception as e:
|
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.
|
#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", file_name, str(e))
|
Logger.log("e", "Failed to import profile from %s: %s", file_name, 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", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))}
|
||||||
if profile: #Success!
|
if profile_or_list: # Success!
|
||||||
profile.setReadOnly(False)
|
name_seed = os.path.splitext(os.path.basename(file_name))[0]
|
||||||
|
if type(profile_or_list) is not list:
|
||||||
new_name = self.createUniqueName("quality", "", os.path.splitext(os.path.basename(file_name))[0],
|
profile = profile_or_list
|
||||||
catalog.i18nc("@label", "Custom profile"))
|
self._configureProfile(profile, name_seed)
|
||||||
profile.setName(new_name)
|
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
|
||||||
profile._id = new_name
|
|
||||||
|
|
||||||
if self._machineHasOwnQualities():
|
|
||||||
profile.setDefinition(self._activeDefinition())
|
|
||||||
if self._machineHasOwnMaterials():
|
|
||||||
profile.addMetaDataEntry("material", self._activeMaterialId())
|
|
||||||
else:
|
else:
|
||||||
profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0])
|
for profile in profile_or_list:
|
||||||
ContainerRegistry.getInstance().addContainer(profile)
|
self._configureProfile(profile, name_seed)
|
||||||
|
|
||||||
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) }
|
if len(profile_or_list) == 1:
|
||||||
|
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
|
||||||
|
else:
|
||||||
|
profile_names = ", ".join([profile.getName() for profile in profile_or_list])
|
||||||
|
return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) }
|
||||||
|
|
||||||
#If it hasn't returned by now, none of the plugins loaded the profile successfully.
|
#If it hasn't returned by now, none of the plugins loaded the profile successfully.
|
||||||
return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
|
return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
|
||||||
|
|
||||||
|
def _configureProfile(self, profile, name_seed):
|
||||||
|
profile.setReadOnly(False)
|
||||||
|
|
||||||
|
new_name = self.createUniqueName("quality", "", name_seed, catalog.i18nc("@label", "Custom profile"))
|
||||||
|
profile.setName(new_name)
|
||||||
|
profile._id = new_name
|
||||||
|
|
||||||
|
if self._machineHasOwnQualities():
|
||||||
|
profile.setDefinition(self._activeDefinition())
|
||||||
|
if self._machineHasOwnMaterials():
|
||||||
|
profile.addMetaDataEntry("material", self._activeMaterialId())
|
||||||
|
else:
|
||||||
|
profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0])
|
||||||
|
ContainerRegistry.getInstance().addContainer(profile)
|
||||||
|
|
||||||
## Gets a list of profile writer plugins
|
## Gets a list of profile writer plugins
|
||||||
# \return List of tuples of (plugin_id, meta_data).
|
# \return List of tuples of (plugin_id, meta_data).
|
||||||
def _getIOPlugins(self, io_type):
|
def _getIOPlugins(self, io_type):
|
||||||
|
@ -35,10 +35,10 @@ class ExtruderManager(QObject):
|
|||||||
@pyqtProperty(str, notify = activeExtruderChanged)
|
@pyqtProperty(str, notify = activeExtruderChanged)
|
||||||
def activeExtruderStackId(self):
|
def activeExtruderStackId(self):
|
||||||
if not UM.Application.getInstance().getGlobalContainerStack():
|
if not UM.Application.getInstance().getGlobalContainerStack():
|
||||||
return None #No active machine, so no active extruder.
|
return None # No active machine, so no active extruder.
|
||||||
try:
|
try:
|
||||||
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)].getId()
|
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
|
||||||
except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
|
except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
## The instance of the singleton pattern.
|
## The instance of the singleton pattern.
|
||||||
@ -74,47 +74,43 @@ class ExtruderManager(QObject):
|
|||||||
def getActiveExtruderStack(self):
|
def getActiveExtruderStack(self):
|
||||||
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
|
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
|
||||||
if global_container_stack:
|
if global_container_stack:
|
||||||
global_definition_container = UM.Application.getInstance().getGlobalContainerStack().getBottom()
|
if global_container_stack.getId() in self._extruder_trains:
|
||||||
if global_definition_container:
|
if str(self._active_extruder_index) in self._extruder_trains[global_container_stack.getId()]:
|
||||||
if global_definition_container.getId() in self._extruder_trains:
|
return self._extruder_trains[global_container_stack.getId()][str(self._active_extruder_index)]
|
||||||
if str(self._active_extruder_index) in self._extruder_trains[global_definition_container.getId()]:
|
|
||||||
return self._extruder_trains[global_definition_container.getId()][str(self._active_extruder_index)]
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
## Adds all extruders of a specific machine definition to the extruder
|
## Adds all extruders of a specific machine definition to the extruder
|
||||||
# manager.
|
# manager.
|
||||||
#
|
#
|
||||||
# \param machine_definition The machine to add the extruders for.
|
# \param machine_definition The machine definition to add the extruders for.
|
||||||
def addMachineExtruders(self, machine_definition):
|
# \param machine_id The machine_id to add the extruders for.
|
||||||
|
def addMachineExtruders(self, machine_definition, machine_id):
|
||||||
changed = False
|
changed = False
|
||||||
machine_id = machine_definition.getId()
|
machine_definition_id = machine_definition.getId()
|
||||||
if machine_id not in self._extruder_trains:
|
if machine_id not in self._extruder_trains:
|
||||||
self._extruder_trains[machine_id] = { }
|
self._extruder_trains[machine_id] = { }
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
||||||
if container_registry:
|
if container_registry:
|
||||||
|
# Add the extruder trains that don't exist yet.
|
||||||
#Add the extruder trains that don't exist yet.
|
for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition_id):
|
||||||
for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()):
|
|
||||||
position = extruder_definition.getMetaDataEntry("position", None)
|
position = extruder_definition.getMetaDataEntry("position", None)
|
||||||
if not position:
|
if not position:
|
||||||
UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
|
UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
|
||||||
if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet.
|
if not container_registry.findContainerStacks(machine = machine_id, position = position): # Doesn't exist yet.
|
||||||
self.createExtruderTrain(extruder_definition, machine_definition, position)
|
self.createExtruderTrain(extruder_definition, machine_definition, position, machine_id)
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
#Gets the extruder trains that we just created as well as any that still existed.
|
# Gets the extruder trains that we just created as well as any that still existed.
|
||||||
extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId())
|
extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_id)
|
||||||
for extruder_train in extruder_trains:
|
for extruder_train in extruder_trains:
|
||||||
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
|
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
|
||||||
|
|
||||||
#Ensure that the extruder train stacks are linked to global stack.
|
# Ensure that the extruder train stacks are linked to global stack.
|
||||||
extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
|
extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
self.extrudersChanged.emit(machine_definition)
|
self.extrudersChanged.emit(machine_id)
|
||||||
|
|
||||||
## Creates a container stack for an extruder train.
|
## Creates a container stack for an extruder train.
|
||||||
#
|
#
|
||||||
@ -124,31 +120,29 @@ class ExtruderManager(QObject):
|
|||||||
#
|
#
|
||||||
# The resulting container stack is added to the registry.
|
# The resulting container stack is added to the registry.
|
||||||
#
|
#
|
||||||
# \param extruder_definition The extruder to create the extruder train
|
# \param extruder_definition The extruder to create the extruder train for.
|
||||||
# for.
|
# \param machine_definition The machine that the extruder train belongs to.
|
||||||
# \param machine_definition The machine that the extruder train belongs
|
# \param position The position of this extruder train in the extruder slots of the machine.
|
||||||
# to.
|
# \param machine_id The id of the "global" stack this extruder is linked to.
|
||||||
# \param position The position of this extruder train in the extruder
|
def createExtruderTrain(self, extruder_definition, machine_definition, position, machine_id):
|
||||||
# slots of the machine.
|
# Cache some things.
|
||||||
def createExtruderTrain(self, extruder_definition, machine_definition, position):
|
|
||||||
#Cache some things.
|
|
||||||
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
container_registry = UM.Settings.ContainerRegistry.getInstance()
|
||||||
machine_id = machine_definition.getId()
|
machine_definition_id = machine_definition.getId()
|
||||||
|
|
||||||
#Create a container stack for this extruder.
|
# Create a container stack for this extruder.
|
||||||
extruder_stack_id = container_registry.uniqueName(extruder_definition.getId())
|
extruder_stack_id = container_registry.uniqueName(extruder_definition.getId())
|
||||||
container_stack = UM.Settings.ContainerStack(extruder_stack_id)
|
container_stack = UM.Settings.ContainerStack(extruder_stack_id)
|
||||||
container_stack.setName(extruder_definition.getName()) #Take over the display name to display the stack with.
|
container_stack.setName(extruder_definition.getName()) # Take over the display name to display the stack with.
|
||||||
container_stack.addMetaDataEntry("type", "extruder_train")
|
container_stack.addMetaDataEntry("type", "extruder_train")
|
||||||
container_stack.addMetaDataEntry("machine", machine_definition.getId())
|
container_stack.addMetaDataEntry("machine", machine_id)
|
||||||
container_stack.addMetaDataEntry("position", position)
|
container_stack.addMetaDataEntry("position", position)
|
||||||
container_stack.addContainer(extruder_definition)
|
container_stack.addContainer(extruder_definition)
|
||||||
|
|
||||||
#Find the variant to use for this extruder.
|
# Find the variant to use for this extruder.
|
||||||
variant = container_registry.getEmptyInstanceContainer()
|
variant = container_registry.findInstanceContainers(id = "empty_variant")[0]
|
||||||
if machine_definition.getMetaDataEntry("has_variants"):
|
if machine_definition.getMetaDataEntry("has_variants"):
|
||||||
#First add any variant. Later, overwrite with preference if the preference is valid.
|
# First add any variant. Later, overwrite with preference if the preference is valid.
|
||||||
variants = container_registry.findInstanceContainers(definition = machine_id, type = "variant")
|
variants = container_registry.findInstanceContainers(definition = machine_definition_id, type = "variant")
|
||||||
if len(variants) >= 1:
|
if len(variants) >= 1:
|
||||||
variant = variants[0]
|
variant = variants[0]
|
||||||
preferred_variant_id = machine_definition.getMetaDataEntry("preferred_variant")
|
preferred_variant_id = machine_definition.getMetaDataEntry("preferred_variant")
|
||||||
@ -158,17 +152,17 @@ class ExtruderManager(QObject):
|
|||||||
variant = preferred_variants[0]
|
variant = preferred_variants[0]
|
||||||
else:
|
else:
|
||||||
UM.Logger.log("w", "The preferred variant \"%s\" of machine %s doesn't exist or is not a variant profile.", preferred_variant_id, machine_id)
|
UM.Logger.log("w", "The preferred variant \"%s\" of machine %s doesn't exist or is not a variant profile.", preferred_variant_id, machine_id)
|
||||||
#And leave it at the default variant.
|
# And leave it at the default variant.
|
||||||
container_stack.addContainer(variant)
|
container_stack.addContainer(variant)
|
||||||
|
|
||||||
#Find a material to use for this variant.
|
# Find a material to use for this variant.
|
||||||
material = container_registry.getEmptyInstanceContainer()
|
material = container_registry.findInstanceContainers(id = "empty_material")[0]
|
||||||
if machine_definition.getMetaDataEntry("has_materials"):
|
if machine_definition.getMetaDataEntry("has_materials"):
|
||||||
#First add any material. Later, overwrite with preference if the preference is valid.
|
# First add any material. Later, overwrite with preference if the preference is valid.
|
||||||
if machine_definition.getMetaDataEntry("has_variant_materials", default = "False") == "True":
|
if machine_definition.getMetaDataEntry("has_variant_materials", default = "False") == "True":
|
||||||
materials = container_registry.findInstanceContainers(type = "material", definition = machine_id, variant = variant.getId())
|
materials = container_registry.findInstanceContainers(type = "material", definition = machine_definition_id, variant = variant.getId())
|
||||||
else:
|
else:
|
||||||
materials = container_registry.findInstanceContainers(type = "material", definition = machine_id)
|
materials = container_registry.findInstanceContainers(type = "material", definition = machine_definition_id)
|
||||||
if len(materials) >= 1:
|
if len(materials) >= 1:
|
||||||
material = materials[0]
|
material = materials[0]
|
||||||
preferred_material_id = machine_definition.getMetaDataEntry("preferred_material")
|
preferred_material_id = machine_definition.getMetaDataEntry("preferred_material")
|
||||||
@ -187,32 +181,41 @@ class ExtruderManager(QObject):
|
|||||||
material = preferred_materials[0]
|
material = preferred_materials[0]
|
||||||
else:
|
else:
|
||||||
UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
|
UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
|
||||||
#And leave it at the default material.
|
# And leave it at the default material.
|
||||||
container_stack.addContainer(material)
|
container_stack.addContainer(material)
|
||||||
|
|
||||||
#Find a quality to use for this extruder.
|
# Find a quality to use for this extruder.
|
||||||
quality = container_registry.getEmptyInstanceContainer()
|
quality = container_registry.getEmptyInstanceContainer()
|
||||||
|
|
||||||
#First add any quality. Later, overwrite with preference if the preference is valid.
|
search_criteria = { "type": "quality" }
|
||||||
qualities = container_registry.findInstanceContainers(type = "quality")
|
if machine_definition.getMetaDataEntry("has_machine_quality"):
|
||||||
if len(qualities) >= 1:
|
search_criteria["definition"] = machine_definition.id
|
||||||
quality = qualities[0]
|
if machine_definition.getMetaDataEntry("has_materials") and material:
|
||||||
preferred_quality_id = machine_definition.getMetaDataEntry("preferred_quality")
|
search_criteria["material"] = material.id
|
||||||
if preferred_quality_id:
|
else:
|
||||||
preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id, type = "quality")
|
search_criteria["definition"] = "fdmprinter"
|
||||||
if len(preferred_quality) >= 1:
|
|
||||||
quality = preferred_quality[0]
|
preferred_quality = machine_definition.getMetaDataEntry("preferred_quality")
|
||||||
else:
|
if preferred_quality:
|
||||||
UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality_id, machine_id)
|
search_criteria["id"] = preferred_quality
|
||||||
#And leave it at the default quality.
|
|
||||||
|
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
|
||||||
|
if not containers and preferred_quality:
|
||||||
|
UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality, machine_id)
|
||||||
|
search_criteria.pop("id", None)
|
||||||
|
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
|
||||||
|
if containers:
|
||||||
|
quality = containers[0]
|
||||||
|
|
||||||
container_stack.addContainer(quality)
|
container_stack.addContainer(quality)
|
||||||
|
|
||||||
user_profile = container_registry.findInstanceContainers(id = extruder_stack_id + "_current_settings")
|
user_profile = container_registry.findInstanceContainers(type = "user", extruder = extruder_stack_id)
|
||||||
if user_profile: #There was already a user profile, loaded from settings.
|
if user_profile: # There was already a user profile, loaded from settings.
|
||||||
user_profile = user_profile[0]
|
user_profile = user_profile[0]
|
||||||
else:
|
else:
|
||||||
user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") #Add an empty user profile.
|
user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") # Add an empty user profile.
|
||||||
user_profile.addMetaDataEntry("type", "user")
|
user_profile.addMetaDataEntry("type", "user")
|
||||||
|
user_profile.addMetaDataEntry("extruder", extruder_stack_id)
|
||||||
user_profile.setDefinition(machine_definition)
|
user_profile.setDefinition(machine_definition)
|
||||||
container_registry.addContainer(user_profile)
|
container_registry.addContainer(user_profile)
|
||||||
container_stack.addContainer(user_profile)
|
container_stack.addContainer(user_profile)
|
||||||
@ -221,7 +224,17 @@ class ExtruderManager(QObject):
|
|||||||
|
|
||||||
container_registry.addContainer(container_stack)
|
container_registry.addContainer(container_stack)
|
||||||
|
|
||||||
## Generates extruders for a specific machine.
|
## Removes the container stack and user profile for the extruders for a specific machine.
|
||||||
|
#
|
||||||
|
# \param machine_id The machine to remove the extruders for.
|
||||||
|
def removeMachineExtruders(self, machine_id):
|
||||||
|
for extruder in self.getMachineExtruders(machine_id):
|
||||||
|
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", extruder = extruder.getId())
|
||||||
|
for container in containers:
|
||||||
|
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
|
||||||
|
UM.Settings.ContainerRegistry.getInstance().removeContainer(extruder.getId())
|
||||||
|
|
||||||
|
## Returns extruders for a specific machine.
|
||||||
#
|
#
|
||||||
# \param machine_id The machine to get the extruders of.
|
# \param machine_id The machine to get the extruders of.
|
||||||
def getMachineExtruders(self, machine_id):
|
def getMachineExtruders(self, machine_id):
|
||||||
@ -239,4 +252,4 @@ class ExtruderManager(QObject):
|
|||||||
def _addCurrentMachineExtruders(self):
|
def _addCurrentMachineExtruders(self):
|
||||||
global_stack = UM.Application.getInstance().getGlobalContainerStack()
|
global_stack = UM.Application.getInstance().getGlobalContainerStack()
|
||||||
if global_stack and global_stack.getBottom():
|
if global_stack and global_stack.getBottom():
|
||||||
self.addMachineExtruders(global_stack.getBottom())
|
self.addMachineExtruders(global_stack.getBottom(), global_stack.getId())
|
||||||
|
@ -115,7 +115,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
manager = ExtruderManager.getInstance()
|
manager = ExtruderManager.getInstance()
|
||||||
for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()):
|
for extruder in manager.getMachineExtruders(global_container_stack.getId()):
|
||||||
extruder_name = extruder.getName()
|
extruder_name = extruder.getName()
|
||||||
material = extruder.findContainer({ "type": "material" })
|
material = extruder.findContainer({ "type": "material" })
|
||||||
if material:
|
if material:
|
||||||
|
@ -126,6 +126,9 @@ class MachineManager(QObject):
|
|||||||
self._auto_change_material_hotend_flood_time = time.time()
|
self._auto_change_material_hotend_flood_time = time.time()
|
||||||
self._auto_change_material_hotend_flood_last_choice = button
|
self._auto_change_material_hotend_flood_last_choice = button
|
||||||
|
|
||||||
|
if button == QMessageBox.No:
|
||||||
|
return
|
||||||
|
|
||||||
Logger.log("d", "Setting hotend variant of hotend %d to %s" % (index, hotend_id))
|
Logger.log("d", "Setting hotend variant of hotend %d to %s" % (index, hotend_id))
|
||||||
|
|
||||||
extruder_manager = ExtruderManager.getInstance()
|
extruder_manager = ExtruderManager.getInstance()
|
||||||
@ -174,6 +177,9 @@ class MachineManager(QObject):
|
|||||||
self._auto_change_material_hotend_flood_time = time.time()
|
self._auto_change_material_hotend_flood_time = time.time()
|
||||||
self._auto_change_material_hotend_flood_last_choice = button
|
self._auto_change_material_hotend_flood_last_choice = button
|
||||||
|
|
||||||
|
if button == QMessageBox.No:
|
||||||
|
return
|
||||||
|
|
||||||
Logger.log("d", "Setting material of hotend %d to %s" % (index, material_id))
|
Logger.log("d", "Setting material of hotend %d to %s" % (index, material_id))
|
||||||
|
|
||||||
extruder_manager = ExtruderManager.getInstance()
|
extruder_manager = ExtruderManager.getInstance()
|
||||||
@ -227,7 +233,7 @@ class MachineManager(QObject):
|
|||||||
self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
|
self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
|
||||||
self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
|
self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
|
||||||
self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack)
|
self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack)
|
||||||
|
self.globalValidationChanged.emit()
|
||||||
material = self._global_container_stack.findContainer({"type": "material"})
|
material = self._global_container_stack.findContainer({"type": "material"})
|
||||||
material.nameChanged.connect(self._onMaterialNameChanged)
|
material.nameChanged.connect(self._onMaterialNameChanged)
|
||||||
|
|
||||||
@ -239,7 +245,6 @@ class MachineManager(QObject):
|
|||||||
if self._active_container_stack and self._active_container_stack != self._global_container_stack:
|
if self._active_container_stack and self._active_container_stack != self._global_container_stack:
|
||||||
self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
|
self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
|
||||||
self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
|
self._active_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
|
||||||
|
|
||||||
self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
|
self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
|
||||||
if self._active_container_stack:
|
if self._active_container_stack:
|
||||||
self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
|
self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
|
||||||
@ -292,7 +297,7 @@ class MachineManager(QObject):
|
|||||||
new_global_stack.addContainer(quality_instance_container)
|
new_global_stack.addContainer(quality_instance_container)
|
||||||
new_global_stack.addContainer(current_settings_instance_container)
|
new_global_stack.addContainer(current_settings_instance_container)
|
||||||
|
|
||||||
ExtruderManager.getInstance().addMachineExtruders(definition)
|
ExtruderManager.getInstance().addMachineExtruders(definition, new_global_stack.getId())
|
||||||
|
|
||||||
Application.getInstance().setGlobalContainerStack(new_global_stack)
|
Application.getInstance().setGlobalContainerStack(new_global_stack)
|
||||||
|
|
||||||
@ -494,6 +499,7 @@ class MachineManager(QObject):
|
|||||||
self.activeQualityChanged.emit()
|
self.activeQualityChanged.emit()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
|
@pyqtSlot()
|
||||||
def updateQualityContainerFromUserContainer(self, quality_id = None):
|
def updateQualityContainerFromUserContainer(self, quality_id = None):
|
||||||
if not self._active_container_stack:
|
if not self._active_container_stack:
|
||||||
return
|
return
|
||||||
@ -635,8 +641,12 @@ class MachineManager(QObject):
|
|||||||
# If the machine that is being removed is the currently active machine, set another machine as the active machine.
|
# If the machine that is being removed is the currently active machine, set another machine as the active machine.
|
||||||
activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
|
activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
|
||||||
|
|
||||||
current_settings_id = machine_id + "_current_settings"
|
stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
|
||||||
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id)
|
if not stacks:
|
||||||
|
return
|
||||||
|
ExtruderManager.getInstance().removeMachineExtruders(stacks[0].getBottom().getId())
|
||||||
|
|
||||||
|
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
|
||||||
for container in containers:
|
for container in containers:
|
||||||
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
|
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
|
||||||
UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id)
|
UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id)
|
||||||
@ -688,7 +698,7 @@ class MachineManager(QObject):
|
|||||||
return containers[0].getBottom().getId()
|
return containers[0].getBottom().getId()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def createMachineManager(engine, script_engine):
|
def createMachineManager(engine=None, script_engine=None):
|
||||||
return MachineManager()
|
return MachineManager()
|
||||||
|
|
||||||
def _updateVariantContainer(self, definition):
|
def _updateVariantContainer(self, definition):
|
||||||
@ -778,13 +788,10 @@ class MachineManager(QObject):
|
|||||||
return self._empty_quality_container
|
return self._empty_quality_container
|
||||||
|
|
||||||
def _onMachineNameChanged(self):
|
def _onMachineNameChanged(self):
|
||||||
print("machine name changed")
|
|
||||||
self.globalContainerChanged.emit()
|
self.globalContainerChanged.emit()
|
||||||
|
|
||||||
def _onMaterialNameChanged(self):
|
def _onMaterialNameChanged(self):
|
||||||
print("material name changed")
|
|
||||||
self.activeMaterialChanged.emit()
|
self.activeMaterialChanged.emit()
|
||||||
|
|
||||||
def _onQualityNameChanged(self):
|
def _onQualityNameChanged(self):
|
||||||
print("quality name changed")
|
|
||||||
self.activeQualityChanged.emit()
|
self.activeQualityChanged.emit()
|
||||||
|
@ -111,6 +111,8 @@ class ThreeMFReader(MeshReader):
|
|||||||
if len(objects) > 1:
|
if len(objects) > 1:
|
||||||
group_decorator = GroupDecorator()
|
group_decorator = GroupDecorator()
|
||||||
result.addDecorator(group_decorator)
|
result.addDecorator(group_decorator)
|
||||||
|
elif len(objects) == 1:
|
||||||
|
result = result.getChildren()[0] # Only one object found, return that.
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Logger.log("e", "exception occured in 3mf reader: %s", e)
|
Logger.log("e", "exception occured in 3mf reader: %s", e)
|
||||||
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
[2.1.3]
|
||||||
|
|
||||||
|
*Material Profiles
|
||||||
|
New material profiles for CPE+, PC, Nylon and TPU for the Ultimaker 2+ family.
|
||||||
|
|
||||||
[2.1.2]
|
[2.1.2]
|
||||||
|
|
||||||
Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings.
|
Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 200 customizable settings.
|
||||||
|
|
||||||
*Select Multiple Objects
|
*Select Multiple Objects
|
||||||
You now have the freedom to select and manipulate multiple objects at the same time.
|
You now have the freedom to select and manipulate multiple objects at the same time.
|
||||||
@ -27,22 +32,61 @@ An optimized 64-bit Windows Cura version is now available. This allows you to lo
|
|||||||
Cura allows you to set a number of lines/layers instead of millimeters. The engine automatically calculates the right settings.
|
Cura allows you to set a number of lines/layers instead of millimeters. The engine automatically calculates the right settings.
|
||||||
|
|
||||||
*Per-Object Settings
|
*Per-Object Settings
|
||||||
You can now override individual settings for different objects in advanced mode.
|
Per-object settings allow you to override individual profile settings per object.
|
||||||
|
|
||||||
*Fuzzy Skin
|
*Engine Features
|
||||||
Prints the outer walls with a jittering motion to give your object a diffused finish.
|
|
||||||
|
|
||||||
*Wire Printing
|
*Line Width
|
||||||
The object is printed with a mid-air / net-like structure, following the mesh surface. The build plate will move up and down during diagonal segments. Though not visible in layer view, you can view the result in other software, such as Repetier Host or http://chilipeppr.com/tinyg.
|
Line width settings added per feature: Global, Walls, Top/Bottom, Infill, Skirt, Support.
|
||||||
|
|
||||||
* Conical Support
|
*Pattern Settings
|
||||||
An experimental filament, cost-reduction feature, for support.
|
Pattern settings improved per feature: Top/Bottom, Infill, Support.
|
||||||
|
|
||||||
|
*Shell
|
||||||
|
|
||||||
|
*Alternate Skin Rotation
|
||||||
|
Helps to combat the pillowing problem on top layers.
|
||||||
|
|
||||||
|
*Alternate Extra Wall
|
||||||
|
For better infill adhesion.
|
||||||
|
|
||||||
|
*Horizontal Expansion
|
||||||
|
Allows to compensate model x,y-size to get a 1:1 result.
|
||||||
|
|
||||||
|
*Travel
|
||||||
|
|
||||||
|
*Avoid Printed Parts
|
||||||
|
When moving to the next part to print, avoid collisions between the nozzle and other parts which are already printed.
|
||||||
|
|
||||||
|
*Support
|
||||||
|
|
||||||
|
*Stair Step Height
|
||||||
|
Sets the balance between sturdy and hard to remove support. By setting steps of the stair-like bottom of the support resting on the model.
|
||||||
|
|
||||||
|
*ZigZag
|
||||||
|
A new, infill type that’s easily breakable, introduced specially for support.
|
||||||
|
|
||||||
|
*Support Roofs
|
||||||
|
A new sub-feature to reduce scars the support leaves on overhangs.
|
||||||
|
|
||||||
*Support Towers
|
*Support Towers
|
||||||
Specialized support for tiny overhang areas.
|
Specialized support for tiny overhang areas.
|
||||||
|
|
||||||
*ZigZag infill
|
*Special Modes
|
||||||
A new, infill type that’s easily breakable, introduced specially for support.
|
|
||||||
|
|
||||||
* Avoid Printed Parts
|
*Surface Mode
|
||||||
While combing, the print head moves around printed parts, avoiding collisions with the nozzle and a part that’s already printed.
|
This mode will print the surface of the mesh instead of the enclosed volume. This used to be called ‘Only follow mesh surface’. In addition to the ‘surface mode’ and ‘normal’, a ‘both’ mode has now been added. This ensures all closed volumes are printed as normal and all loose geometry as single walls.
|
||||||
|
|
||||||
|
*Experimental Features
|
||||||
|
|
||||||
|
*Conical Support
|
||||||
|
An experimental filament, cost-reduction feature, for support.
|
||||||
|
|
||||||
|
*Draft Shield
|
||||||
|
Prints a protective wall at a set distance around the object that prevents air from hitting the print, reducing warping.
|
||||||
|
|
||||||
|
*Fuzzy Skin
|
||||||
|
Prints the outer walls with a jittering motion to give your object a diffuse finish.
|
||||||
|
|
||||||
|
*Wire Printing
|
||||||
|
The object is printed with a mid-air / net-like structure, following the mesh surface. The build plate will move up and down during diagonal segments. Though not visible in layer view, you can view the result in other software, such as Repetier Host or http://chilipeppr.com/tinyg.
|
||||||
|
@ -22,6 +22,7 @@ from . import StartSliceJob
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from time import time
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ class CuraEngineBackend(Backend):
|
|||||||
self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness.
|
self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness.
|
||||||
self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.
|
self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.
|
||||||
|
|
||||||
|
self._backend_log_max_lines = 200 # Maximal count of lines to buffer
|
||||||
self._error_message = None #Pop-up message that shows errors.
|
self._error_message = None #Pop-up message that shows errors.
|
||||||
|
|
||||||
self.backendQuit.connect(self._onBackendQuit)
|
self.backendQuit.connect(self._onBackendQuit)
|
||||||
@ -100,6 +102,8 @@ class CuraEngineBackend(Backend):
|
|||||||
Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
||||||
Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||||
|
|
||||||
|
self._slice_start_time = None
|
||||||
|
|
||||||
## Called when closing the application.
|
## Called when closing the application.
|
||||||
#
|
#
|
||||||
# This function should terminate the engine process.
|
# This function should terminate the engine process.
|
||||||
@ -128,6 +132,7 @@ class CuraEngineBackend(Backend):
|
|||||||
|
|
||||||
## Perform a slice of the scene.
|
## Perform a slice of the scene.
|
||||||
def slice(self):
|
def slice(self):
|
||||||
|
self._slice_start_time = time()
|
||||||
if not self._enabled or not self._global_container_stack: #We shouldn't be slicing.
|
if not self._enabled or not self._global_container_stack: #We shouldn't be slicing.
|
||||||
# try again in a short time
|
# try again in a short time
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
@ -217,6 +222,7 @@ class CuraEngineBackend(Backend):
|
|||||||
|
|
||||||
# Preparation completed, send it to the backend.
|
# Preparation completed, send it to the backend.
|
||||||
self._socket.sendMessage(job.getSliceMessage())
|
self._socket.sendMessage(job.getSliceMessage())
|
||||||
|
Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time )
|
||||||
|
|
||||||
## Listener for when the scene has changed.
|
## Listener for when the scene has changed.
|
||||||
#
|
#
|
||||||
@ -286,7 +292,7 @@ class CuraEngineBackend(Backend):
|
|||||||
self.processingProgress.emit(1.0)
|
self.processingProgress.emit(1.0)
|
||||||
|
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
|
Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time )
|
||||||
if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()):
|
if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()):
|
||||||
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data)
|
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data)
|
||||||
self._process_layers_job.start()
|
self._process_layers_job.start()
|
||||||
|
@ -9,6 +9,7 @@ from UM.Mesh.MeshData import MeshData
|
|||||||
|
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.Logger import Logger
|
||||||
|
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ from cura import LayerDataDecorator
|
|||||||
from cura import LayerPolygon
|
from cura import LayerPolygon
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
from time import time
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ class ProcessSlicedLayersJob(Job):
|
|||||||
if len(self._layers) == 0:
|
if len(self._layers) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
start_time = time()
|
||||||
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
||||||
self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1)
|
self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1)
|
||||||
self._progress.show()
|
self._progress.show()
|
||||||
@ -155,7 +157,10 @@ class ProcessSlicedLayersJob(Job):
|
|||||||
new_node.addDecorator(decorator)
|
new_node.addDecorator(decorator)
|
||||||
|
|
||||||
new_node.setMeshData(mesh)
|
new_node.setMeshData(mesh)
|
||||||
new_node.setParent(self._scene.getRoot()) # Note: After this we can no longer abort!
|
# Set build volume as parent, the build volume can move as a result of raft settings.
|
||||||
|
# It makes sense to set the build volume as parent: the print is actually printed on it.
|
||||||
|
new_node_parent = Application.getInstance().getBuildVolume()
|
||||||
|
new_node.setParent(new_node_parent) # Note: After this we can no longer abort!
|
||||||
|
|
||||||
settings = Application.getInstance().getGlobalContainerStack()
|
settings = Application.getInstance().getGlobalContainerStack()
|
||||||
if not settings.getProperty("machine_center_is_zero", "value"):
|
if not settings.getProperty("machine_center_is_zero", "value"):
|
||||||
@ -174,6 +179,8 @@ class ProcessSlicedLayersJob(Job):
|
|||||||
# Clear the unparsed layers. This saves us a bunch of memory if the Job does not get destroyed.
|
# Clear the unparsed layers. This saves us a bunch of memory if the Job does not get destroyed.
|
||||||
self._layers = None
|
self._layers = None
|
||||||
|
|
||||||
|
Logger.log("d", "Processing layers took %s seconds", time() - start_time)
|
||||||
|
|
||||||
def _onActiveViewChanged(self):
|
def _onActiveViewChanged(self):
|
||||||
if self.isRunning():
|
if self.isRunning():
|
||||||
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
||||||
|
@ -129,7 +129,7 @@ class StartSliceJob(Job):
|
|||||||
|
|
||||||
self._buildGlobalSettingsMessage(stack)
|
self._buildGlobalSettingsMessage(stack)
|
||||||
|
|
||||||
for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()):
|
for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getId()):
|
||||||
self._buildExtruderMessage(extruder_stack)
|
self._buildExtruderMessage(extruder_stack)
|
||||||
|
|
||||||
for group in object_groups:
|
for group in object_groups:
|
||||||
@ -174,10 +174,17 @@ class StartSliceJob(Job):
|
|||||||
def _buildExtruderMessage(self, stack):
|
def _buildExtruderMessage(self, stack):
|
||||||
message = self._slice_message.addRepeatedMessage("extruders")
|
message = self._slice_message.addRepeatedMessage("extruders")
|
||||||
message.id = int(stack.getMetaDataEntry("position"))
|
message.id = int(stack.getMetaDataEntry("position"))
|
||||||
|
|
||||||
|
material_instance_container = stack.findContainer({"type": "material"})
|
||||||
|
|
||||||
for key in stack.getAllKeys():
|
for key in stack.getAllKeys():
|
||||||
setting = message.getMessage("settings").addRepeatedMessage("settings")
|
setting = message.getMessage("settings").addRepeatedMessage("settings")
|
||||||
setting.name = key
|
setting.name = key
|
||||||
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
|
if key == "material_guid" and material_instance_container:
|
||||||
|
# Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it.
|
||||||
|
setting.value = str(material_instance_container.getMetaDataEntry("GUID", "")).encode("utf-8")
|
||||||
|
else:
|
||||||
|
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
## Sends all global settings to the engine.
|
## Sends all global settings to the engine.
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from UM.Application import Application #To get the machine manager to create the new profile in.
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
|
from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
|
||||||
from cura.ProfileReader import ProfileReader
|
from cura.ProfileReader import ProfileReader
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
import os
|
|
||||||
import re #Regular expressions for parsing escape characters in the settings.
|
import re #Regular expressions for parsing escape characters in the settings.
|
||||||
|
import json
|
||||||
|
|
||||||
from UM.Application import Application #To get the machine manager to create the new profile in.
|
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
@ -22,7 +21,7 @@ class GCodeProfileReader(ProfileReader):
|
|||||||
# It can only read settings with the same version as the version it was
|
# It can only read settings with the same version as the version it was
|
||||||
# written with. If the file format is changed in a way that breaks reverse
|
# written with. If the file format is changed in a way that breaks reverse
|
||||||
# compatibility, increment this version number!
|
# compatibility, increment this version number!
|
||||||
version = 2
|
version = 3
|
||||||
|
|
||||||
## Dictionary that defines how characters are escaped when embedded in
|
## Dictionary that defines how characters are escaped when embedded in
|
||||||
# g-code.
|
# g-code.
|
||||||
@ -66,21 +65,37 @@ class GCodeProfileReader(ProfileReader):
|
|||||||
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
|
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Un-escape the serialized profile.
|
serialized = unescapeGcodeComment(serialized)
|
||||||
pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys()))
|
|
||||||
|
|
||||||
# Perform the replacement with a regular expression.
|
|
||||||
serialized = pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], serialized)
|
|
||||||
Logger.log("i", "Serialized the following from %s: %s" %(file_name, repr(serialized)))
|
Logger.log("i", "Serialized the following from %s: %s" %(file_name, repr(serialized)))
|
||||||
|
|
||||||
# Create an empty profile - the id and name will be changed by the ContainerRegistry
|
json_data = json.loads(serialized)
|
||||||
profile = InstanceContainer("")
|
|
||||||
try:
|
|
||||||
profile.deserialize(serialized)
|
|
||||||
except Exception as e: # Not a valid g-code file.
|
|
||||||
Logger.log("e", "Unable to serialise the profile: %s", str(e))
|
|
||||||
return None
|
|
||||||
|
|
||||||
profile.addMetaDataEntry("type", "quality")
|
profile_strings = [json_data["global_quality"]]
|
||||||
|
profile_strings.extend(json_data.get("extruder_quality", []))
|
||||||
|
|
||||||
return profile
|
return [readQualityProfileFromString(profile_string) for profile_string in profile_strings]
|
||||||
|
|
||||||
|
## Unescape a string which has been escaped for use in a gcode comment.
|
||||||
|
#
|
||||||
|
# \param string The string to unescape.
|
||||||
|
# \return \type{str} The unscaped string.
|
||||||
|
def unescapeGcodeComment(string):
|
||||||
|
# Un-escape the serialized profile.
|
||||||
|
pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys()))
|
||||||
|
|
||||||
|
# Perform the replacement with a regular expression.
|
||||||
|
return pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], string)
|
||||||
|
|
||||||
|
## Read in a profile from a serialized string.
|
||||||
|
#
|
||||||
|
# \param profile_string The profile data in serialized form.
|
||||||
|
# \return \type{Profile} the resulting Profile object or None if it could not be read.
|
||||||
|
def readQualityProfileFromString(profile_string):
|
||||||
|
# Create an empty profile - the id and name will be changed by the ContainerRegistry
|
||||||
|
profile = InstanceContainer("")
|
||||||
|
try:
|
||||||
|
profile.deserialize(profile_string)
|
||||||
|
except Exception as e: # Not a valid g-code file.
|
||||||
|
Logger.log("e", "Unable to serialise the profile: %s", str(e))
|
||||||
|
return None
|
||||||
|
return profile
|
||||||
|
@ -4,8 +4,13 @@
|
|||||||
from UM.Mesh.MeshWriter import MeshWriter
|
from UM.Mesh.MeshWriter import MeshWriter
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer #To create a complete setting profile to store in the g-code.
|
import UM.Settings.ContainerRegistry
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
|
|
||||||
import re #For escaping characters in the settings.
|
import re #For escaping characters in the settings.
|
||||||
|
import json
|
||||||
|
|
||||||
## Writes g-code to a file.
|
## Writes g-code to a file.
|
||||||
#
|
#
|
||||||
@ -23,7 +28,7 @@ class GCodeWriter(MeshWriter):
|
|||||||
# It can only read settings with the same version as the version it was
|
# It can only read settings with the same version as the version it was
|
||||||
# written with. If the file format is changed in a way that breaks reverse
|
# written with. If the file format is changed in a way that breaks reverse
|
||||||
# compatibility, increment this version number!
|
# compatibility, increment this version number!
|
||||||
version = 2
|
version = 3
|
||||||
|
|
||||||
## Dictionary that defines how characters are escaped when embedded in
|
## Dictionary that defines how characters are escaped when embedded in
|
||||||
# g-code.
|
# g-code.
|
||||||
@ -64,25 +69,49 @@ class GCodeWriter(MeshWriter):
|
|||||||
#
|
#
|
||||||
# \param settings A container stack to serialise.
|
# \param settings A container stack to serialise.
|
||||||
# \return A serialised string of the settings.
|
# \return A serialised string of the settings.
|
||||||
def _serialiseSettings(self, settings):
|
def _serialiseSettings(self, stack):
|
||||||
prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
||||||
prefix_length = len(prefix)
|
prefix_length = len(prefix)
|
||||||
|
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
container_with_profile = stack.findContainer({"type": "quality"})
|
||||||
container_with_profile = global_stack.findContainer({"type": "quality"})
|
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||||
serialized = container_with_profile.serialize()
|
|
||||||
|
# Duplicate the current quality profile and update it with any user settings.
|
||||||
|
flat_quality_id = machine_manager.duplicateContainer(container_with_profile.getId())
|
||||||
|
flat_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = flat_quality_id)[0]
|
||||||
|
user_settings = stack.getTop()
|
||||||
|
for key in user_settings.getAllKeys():
|
||||||
|
flat_quality.setProperty(key, "value", user_settings.getProperty(key, "value"))
|
||||||
|
|
||||||
|
serialized = flat_quality.serialize()
|
||||||
|
|
||||||
|
data = {"global_quality": serialized}
|
||||||
|
|
||||||
|
manager = ExtruderManager.getInstance()
|
||||||
|
for extruder in manager.getMachineExtruders(stack.getId()):
|
||||||
|
extruder_quality = extruder.findContainer({"type": "quality"})
|
||||||
|
|
||||||
|
flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId())
|
||||||
|
flat_extruder_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=flat_extruder_quality_id)[0]
|
||||||
|
extruder_user_settings = extruder.getTop()
|
||||||
|
for key in extruder_user_settings.getAllKeys():
|
||||||
|
flat_extruder_quality.setProperty(key, "value", extruder_user_settings.getProperty(key, "value"))
|
||||||
|
|
||||||
|
extruder_serialized = flat_extruder_quality.serialize()
|
||||||
|
data.setdefault("extruder_quality", []).append(extruder_serialized)
|
||||||
|
|
||||||
|
json_string = json.dumps(data)
|
||||||
|
|
||||||
# Escape characters that have a special meaning in g-code comments.
|
# Escape characters that have a special meaning in g-code comments.
|
||||||
pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
|
pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
|
||||||
|
|
||||||
# Perform the replacement with a regular expression.
|
# Perform the replacement with a regular expression.
|
||||||
serialized = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], serialized)
|
escaped_string = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], json_string)
|
||||||
|
|
||||||
# Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
|
# Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
# Lines have 80 characters, so the payload of each line is 80 - prefix.
|
# Lines have 80 characters, so the payload of each line is 80 - prefix.
|
||||||
for pos in range(0, len(serialized), 80 - prefix_length):
|
for pos in range(0, len(escaped_string), 80 - prefix_length):
|
||||||
result += prefix + serialized[pos : pos + 80 - prefix_length] + "\n"
|
result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n"
|
||||||
serialized = result
|
return result
|
||||||
|
|
||||||
return serialized
|
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
from UM.Tool import Tool
|
from UM.Tool import Tool
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||||
|
|
||||||
|
|
||||||
## This tool allows the user to add & change settings per node in the scene.
|
## This tool allows the user to add & change settings per node in the scene.
|
||||||
# The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
|
# The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
|
||||||
class PerObjectSettingsTool(Tool):
|
class PerObjectSettingsTool(Tool):
|
||||||
@ -69,6 +71,11 @@ class PerObjectSettingsTool(Tool):
|
|||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
if global_container_stack:
|
if global_container_stack:
|
||||||
self._multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
|
self._multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
|
||||||
|
if not self._multi_extrusion:
|
||||||
|
# Ensure that all extruder data is reset
|
||||||
|
root_node = Application.getInstance().getController().getScene().getRoot()
|
||||||
|
for node in DepthFirstIterator(root_node):
|
||||||
|
node.callDecoration("setActiveExtruder", global_container_stack.getId())
|
||||||
self._updateEnabled()
|
self._updateEnabled()
|
||||||
|
|
||||||
def _updateEnabled(self):
|
def _updateEnabled(self):
|
||||||
|
@ -59,7 +59,7 @@ class SliceInfo(Extension):
|
|||||||
material_radius = 0.5 * global_container_stack.getProperty("material_diameter", "value")
|
material_radius = 0.5 * global_container_stack.getProperty("material_diameter", "value")
|
||||||
|
|
||||||
# TODO: Send material per extruder instead of mashing it on a pile
|
# TODO: Send material per extruder instead of mashing it on a pile
|
||||||
material_used = math.pi * material_radius * material_radius * sum(print_information.materialAmounts) #Volume of all materials used
|
material_used = math.pi * material_radius * material_radius * sum(print_information.materialLengths) #Volume of all materials used
|
||||||
|
|
||||||
# Get model information (bounding boxes, hashes and transformation matrix)
|
# Get model information (bounding boxes, hashes and transformation matrix)
|
||||||
models_info = []
|
models_info = []
|
||||||
@ -93,7 +93,6 @@ class SliceInfo(Extension):
|
|||||||
"printtime": print_information.currentPrintTime.getDisplayString(),
|
"printtime": print_information.currentPrintTime.getDisplayString(),
|
||||||
"filament": material_used,
|
"filament": material_used,
|
||||||
"language": Preferences.getInstance().getValue("general/language"),
|
"language": Preferences.getInstance().getValue("general/language"),
|
||||||
"materials_profiles ": {}
|
|
||||||
}
|
}
|
||||||
for container in global_container_stack.getContainers():
|
for container in global_container_stack.getContainers():
|
||||||
container_id = container.getId()
|
container_id = container.getId()
|
||||||
|
@ -8,14 +8,12 @@ import time
|
|||||||
import queue
|
import queue
|
||||||
import re
|
import re
|
||||||
import functools
|
import functools
|
||||||
import os.path
|
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
||||||
|
from UM.Message import Message
|
||||||
|
|
||||||
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
|
||||||
from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal
|
from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
@ -137,7 +135,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
# \param gcode_list List with gcode (strings).
|
# \param gcode_list List with gcode (strings).
|
||||||
def printGCode(self, gcode_list):
|
def printGCode(self, gcode_list):
|
||||||
if self._progress or self._connection_state != ConnectionState.connected:
|
if self._progress or self._connection_state != ConnectionState.connected:
|
||||||
self._error_message = Message(i18n_catalog.i18nc("@info:status", "Printer is busy or not connected. Unable to start a new job."))
|
self._error_message = Message(catalog.i18nc("@info:status", "Printer is busy or not connected. Unable to start a new job."))
|
||||||
self._error_message.show()
|
self._error_message.show()
|
||||||
Logger.log("d", "Printer is busy or not connected, aborting print")
|
Logger.log("d", "Printer is busy or not connected, aborting print")
|
||||||
self.writeError.emit(self)
|
self.writeError.emit(self)
|
||||||
@ -504,6 +502,13 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
# It will be normalized (based on max_progress) to range 0 - 100
|
# It will be normalized (based on max_progress) to range 0 - 100
|
||||||
def setProgress(self, progress, max_progress = 100):
|
def setProgress(self, progress, max_progress = 100):
|
||||||
self._progress = (progress / max_progress) * 100 # Convert to scale of 0-100
|
self._progress = (progress / max_progress) * 100 # Convert to scale of 0-100
|
||||||
|
if self._progress == 100:
|
||||||
|
# Printing is done, reset progress
|
||||||
|
self._gcode_position = 0
|
||||||
|
self.setProgress(0)
|
||||||
|
self._is_printing = False
|
||||||
|
self._is_paused = False
|
||||||
|
self._updateJobState("ready")
|
||||||
self.progressChanged.emit()
|
self.progressChanged.emit()
|
||||||
|
|
||||||
## Cancel the current print. Printer connection wil continue to listen.
|
## Cancel the current print. Printer connection wil continue to listen.
|
||||||
|
@ -197,7 +197,6 @@ Cura.MachineAction
|
|||||||
Button
|
Button
|
||||||
{
|
{
|
||||||
text: checkupMachineAction.heatupHotendStarted ? catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating")
|
text: checkupMachineAction.heatupHotendStarted ? catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating")
|
||||||
//
|
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
if (checkupMachineAction.heatupHotendStarted)
|
if (checkupMachineAction.heatupHotendStarted)
|
||||||
|
@ -42,7 +42,7 @@ Cura.MachineAction
|
|||||||
anchors.top: pageDescription.bottom
|
anchors.top: pageDescription.bottom
|
||||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
text: catalog.i18nc("@label", "Self-built heated bed")
|
text: catalog.i18nc("@label", "Heated bed (official kit or self-built)")
|
||||||
checked: manager.hasHeatedBed
|
checked: manager.hasHeatedBed
|
||||||
onClicked: manager.hasHeatedBed ? manager.removeHeatedBed() : manager.addHeatedBed()
|
onClicked: manager.hasHeatedBed ? manager.removeHeatedBed() : manager.addHeatedBed()
|
||||||
}
|
}
|
||||||
|
@ -47,11 +47,11 @@ class MachineInstance:
|
|||||||
raise UM.VersionUpgrade.InvalidVersionException("The version of this machine instance is wrong. It must be 1.")
|
raise UM.VersionUpgrade.InvalidVersionException("The version of this machine instance is wrong. It must be 1.")
|
||||||
|
|
||||||
self._type_name = config.get("general", "type")
|
self._type_name = config.get("general", "type")
|
||||||
self._variant_name = config.get("general", "variant", fallback = "empty")
|
self._variant_name = config.get("general", "variant", fallback = "empty_variant")
|
||||||
self._name = config.get("general", "name", fallback = "")
|
self._name = config.get("general", "name", fallback = "")
|
||||||
self._key = config.get("general", "key", fallback = None)
|
self._key = config.get("general", "key", fallback = None)
|
||||||
self._active_profile_name = config.get("general", "active_profile", fallback = "empty")
|
self._active_profile_name = config.get("general", "active_profile", fallback = "empty_quality")
|
||||||
self._active_material_name = config.get("general", "material", fallback = "empty")
|
self._active_material_name = config.get("general", "material", fallback = "empty_material")
|
||||||
|
|
||||||
self._machine_setting_overrides = {}
|
self._machine_setting_overrides = {}
|
||||||
for key, value in config["machine_settings"].items():
|
for key, value in config["machine_settings"].items():
|
||||||
|
@ -18,7 +18,11 @@ _printer_translations = {
|
|||||||
_profile_translations = {
|
_profile_translations = {
|
||||||
"PLA": "generic_pla",
|
"PLA": "generic_pla",
|
||||||
"ABS": "generic_abs",
|
"ABS": "generic_abs",
|
||||||
"CPE": "generic_cpe"
|
"CPE": "generic_cpe",
|
||||||
|
"Low Quality": "low",
|
||||||
|
"Normal Quality": "normal",
|
||||||
|
"High Quality": "high",
|
||||||
|
"Ulti Quality": "high" #This one doesn't have an equivalent. Map it to high.
|
||||||
}
|
}
|
||||||
|
|
||||||
## How to translate setting names from the old version to the new.
|
## How to translate setting names from the old version to the new.
|
||||||
|
@ -145,6 +145,28 @@
|
|||||||
"settable_per_meshgroup": false,
|
"settable_per_meshgroup": false,
|
||||||
"settable_globally": false
|
"settable_globally": false
|
||||||
},
|
},
|
||||||
|
"extruder_prime_pos_z":
|
||||||
|
{
|
||||||
|
"label": "Extruder Prime Z Position",
|
||||||
|
"description": "The Z coordinate of the position where the nozzle primes at the start of printing.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 0,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value": "machine_height",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"platform_adhesion":
|
||||||
|
{
|
||||||
|
"label": "Platform Adhesion",
|
||||||
|
"type": "category",
|
||||||
|
"icon": "category_adhesion",
|
||||||
|
"description": "Adhesion",
|
||||||
|
"children":
|
||||||
|
{
|
||||||
"extruder_prime_pos_x":
|
"extruder_prime_pos_x":
|
||||||
{
|
{
|
||||||
"label": "Extruder Prime X Position",
|
"label": "Extruder Prime X Position",
|
||||||
@ -152,10 +174,11 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"default_value": 0,
|
"default_value": 0,
|
||||||
"minimum_value_warning": "-1000",
|
"minimum_value_warning": "machine_nozzle_offset_x",
|
||||||
"maximum_value_warning": "1000",
|
"maximum_value": "machine_width",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true,
|
||||||
|
"enabled": false
|
||||||
},
|
},
|
||||||
"extruder_prime_pos_y":
|
"extruder_prime_pos_y":
|
||||||
{
|
{
|
||||||
@ -164,22 +187,11 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"default_value": 0,
|
"default_value": 0,
|
||||||
"minimum_value_warning": "-1000",
|
"minimum_value_warning": "machine_nozzle_offset_y",
|
||||||
"maximum_value_warning": "1000",
|
"maximum_value_warning": "machine_depth",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true,
|
||||||
},
|
"enabled": false
|
||||||
"extruder_prime_pos_z":
|
|
||||||
{
|
|
||||||
"label": "Extruder Prime Z Position",
|
|
||||||
"description": "The Z coordinate of the position where the nozzle primes at the start of printing.",
|
|
||||||
"type": "float",
|
|
||||||
"unit": "mm",
|
|
||||||
"default_value": 0,
|
|
||||||
"minimum_value_warning": "-1000",
|
|
||||||
"maximum_value_warning": "1000",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,14 @@
|
|||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
|
"material_guid":
|
||||||
|
{
|
||||||
|
"label": "Material GUID",
|
||||||
|
"description": "GUID of the material. This is set automatically. ",
|
||||||
|
"default_value": "",
|
||||||
|
"type": "str",
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
"material_bed_temp_wait":
|
"material_bed_temp_wait":
|
||||||
{
|
{
|
||||||
"label": "Wait for bed heatup",
|
"label": "Wait for bed heatup",
|
||||||
@ -326,30 +334,6 @@
|
|||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
"extruder_prime_pos_x":
|
|
||||||
{
|
|
||||||
"label": "Extruder Prime X Position",
|
|
||||||
"description": "The X coordinate of the position where the nozzle primes at the start of printing.",
|
|
||||||
"type": "float",
|
|
||||||
"unit": "mm",
|
|
||||||
"default_value": 0,
|
|
||||||
"minimum_value_warning": "-1000",
|
|
||||||
"maximum_value_warning": "1000",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
},
|
|
||||||
"extruder_prime_pos_y":
|
|
||||||
{
|
|
||||||
"label": "Extruder Prime Y Position",
|
|
||||||
"description": "The Y coordinate of the position where the nozzle primes at the start of printing.",
|
|
||||||
"type": "float",
|
|
||||||
"unit": "mm",
|
|
||||||
"default_value": 0,
|
|
||||||
"minimum_value_warning": "-1000",
|
|
||||||
"maximum_value_warning": "1000",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
},
|
|
||||||
"extruder_prime_pos_z":
|
"extruder_prime_pos_z":
|
||||||
{
|
{
|
||||||
"label": "Extruder Prime Z Position",
|
"label": "Extruder Prime Z Position",
|
||||||
@ -357,8 +341,8 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"default_value": 0,
|
"default_value": 0,
|
||||||
"minimum_value_warning": "-1000",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "1000",
|
"maximum_value": "machine_height",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
@ -370,6 +354,136 @@
|
|||||||
"default_value": false,
|
"default_value": false,
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_x": {
|
||||||
|
"label": "Maximum Speed X",
|
||||||
|
"description": "The maximum speed for the motor of the X-direction.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 500,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_y": {
|
||||||
|
"label": "Maximum Speed Y",
|
||||||
|
"description": "The maximum speed for the motor of the Y-direction.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 500,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_z": {
|
||||||
|
"label": "Maximum Speed Z",
|
||||||
|
"description": "The maximum speed for the motor of the Z-direction.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 5,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_e": {
|
||||||
|
"label": "Maximum Feedrate",
|
||||||
|
"description": "The maximum speed of the filament.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 25,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_x": {
|
||||||
|
"label": "Maximum Acceleration X",
|
||||||
|
"description": "Maximum acceleration for the motor of the X-direction",
|
||||||
|
"unit": "mm/s²",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 9000,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_y": {
|
||||||
|
"label": "Maximum Acceleration Y",
|
||||||
|
"description": "Maximum acceleration for the motor of the Y-direction.",
|
||||||
|
"unit": "mm/s²",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 9000,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_z": {
|
||||||
|
"label": "Maximum Acceleration Z",
|
||||||
|
"description": "Maximum acceleration for the motor of the Z-direction.",
|
||||||
|
"unit": "mm/s²",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_e": {
|
||||||
|
"label": "Maximum Filament Acceleration",
|
||||||
|
"description": "Maximum acceleration for the motor of the filament.",
|
||||||
|
"unit": "mm/s²",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 10000,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_acceleration": {
|
||||||
|
"label": "Default Acceleration",
|
||||||
|
"description": "The default acceleration of print head movement.",
|
||||||
|
"unit": "mm/s²",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 4000,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_jerk_xy": {
|
||||||
|
"label": "Default X-Y Jerk",
|
||||||
|
"description": "Default jerk for movement in the horizontal plane.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 20.0,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_jerk_z": {
|
||||||
|
"label": "Default Z Jerk",
|
||||||
|
"description": "Default jerk for the motor of the Z-direction.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 0.4,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_max_jerk_e": {
|
||||||
|
"label": "Default Filament Jerk",
|
||||||
|
"description": "Default jerk for the motor of the filament.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 5.0,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_minimum_feedrate": {
|
||||||
|
"label": "Minimum Feedrate",
|
||||||
|
"description": "The minimal movement speed of the print head.",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 0.0,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -592,7 +706,7 @@
|
|||||||
"default_value": 0.8,
|
"default_value": 0.8,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"minimum_value_warning": "0.6",
|
"minimum_value_warning": "0.6",
|
||||||
"maximum_value_warning": "machine_height",
|
"maximum_value": "machine_height",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"settable_per_mesh": true,
|
"settable_per_mesh": true,
|
||||||
"children":
|
"children":
|
||||||
@ -604,7 +718,7 @@
|
|||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"default_value": 0.8,
|
"default_value": 0.8,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "machine_height",
|
"maximum_value": "machine_height",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": "top_bottom_thickness",
|
"value": "top_bottom_thickness",
|
||||||
"settable_per_mesh": true,
|
"settable_per_mesh": true,
|
||||||
@ -632,7 +746,7 @@
|
|||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"value": "top_bottom_thickness",
|
"value": "top_bottom_thickness",
|
||||||
"maximum_value_warning": "machine_height",
|
"maximum_value": "machine_height",
|
||||||
"settable_per_mesh": true,
|
"settable_per_mesh": true,
|
||||||
"children":
|
"children":
|
||||||
{
|
{
|
||||||
@ -774,7 +888,7 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 2,
|
"default_value": 2,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else (3 if infill_pattern == \"cubic\" else 1)))",
|
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" or infill_pattern == \"cubic\" else (4 if infill_pattern == \"tetrahedral\" else 1)))",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -782,14 +896,15 @@
|
|||||||
"infill_pattern":
|
"infill_pattern":
|
||||||
{
|
{
|
||||||
"label": "Infill Pattern",
|
"label": "Infill Pattern",
|
||||||
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, cubic, triangle and concentric patterns are fully printed every layer.",
|
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, cubic, tetrahedral and concentric patterns are fully printed every layer. Cubic and tetrahedral infill change with every layer to provide a more equal distribution of strength over each direction.",
|
||||||
"type": "enum",
|
"type": "enum",
|
||||||
"options":
|
"options":
|
||||||
{
|
{
|
||||||
"grid": "Grid",
|
"grid": "Grid",
|
||||||
"lines": "Lines",
|
"lines": "Lines",
|
||||||
"cubic": "Cubic",
|
|
||||||
"triangles": "Triangles",
|
"triangles": "Triangles",
|
||||||
|
"cubic": "Cubic",
|
||||||
|
"tetrahedral": "Tetrahedral",
|
||||||
"concentric": "Concentric",
|
"concentric": "Concentric",
|
||||||
"zigzag": "Zig Zag"
|
"zigzag": "Zig Zag"
|
||||||
},
|
},
|
||||||
@ -877,6 +992,29 @@
|
|||||||
"value": "layer_height",
|
"value": "layer_height",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
|
"gradual_infill_steps":
|
||||||
|
{
|
||||||
|
"label": "Gradual Infill Steps",
|
||||||
|
"description": "Number of times to reduce the infill density by half when getting further below top surfaces. Areas which are closer to top surfaces get a higher density, up to the Infill Density.",
|
||||||
|
"default_value": 0,
|
||||||
|
"type": "int",
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value_warning": "4",
|
||||||
|
"maximum_value": "20 - math.log(infill_line_distance) / math.log(2)",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"gradual_infill_step_height":
|
||||||
|
{
|
||||||
|
"label": "Gradual Infill Step Height",
|
||||||
|
"description": "The height of infill of a given density before switching to half the density.",
|
||||||
|
"unit": "mm",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 5.0,
|
||||||
|
"minimum_value": "0.0001",
|
||||||
|
"maximum_value_warning": "100",
|
||||||
|
"enabled": "gradual_infill_steps > 0",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
"infill_before_walls":
|
"infill_before_walls":
|
||||||
{
|
{
|
||||||
"label": "Infill Before Walls",
|
"label": "Infill Before Walls",
|
||||||
@ -1304,7 +1442,7 @@
|
|||||||
"maximum_value_warning": "150",
|
"maximum_value_warning": "150",
|
||||||
"default_value": 60,
|
"default_value": 60,
|
||||||
"value": "speed_print",
|
"value": "speed_print",
|
||||||
"enabled": "support_roof_enable",
|
"enabled": "support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children":
|
"children":
|
||||||
@ -1506,7 +1644,7 @@
|
|||||||
"maximum_value_warning": "10000",
|
"maximum_value_warning": "10000",
|
||||||
"default_value": 3000,
|
"default_value": 3000,
|
||||||
"value": "acceleration_print",
|
"value": "acceleration_print",
|
||||||
"enabled": "acceleration_enabled and support_roof_enable",
|
"enabled": "acceleration_enabled and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children": {
|
"children": {
|
||||||
@ -1534,7 +1672,7 @@
|
|||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "100",
|
"minimum_value_warning": "100",
|
||||||
"maximum_value_warning": "10000",
|
"maximum_value_warning": "10000",
|
||||||
"enabled": "acceleration_enabled and support_roof_enable",
|
"enabled": "acceleration_enabled and support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
}
|
}
|
||||||
@ -1608,7 +1746,7 @@
|
|||||||
"jerk_print": {
|
"jerk_print": {
|
||||||
"label": "Print Jerk",
|
"label": "Print Jerk",
|
||||||
"description": "The maximum instantaneous velocity change of the print head.",
|
"description": "The maximum instantaneous velocity change of the print head.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1620,7 +1758,7 @@
|
|||||||
"jerk_infill": {
|
"jerk_infill": {
|
||||||
"label": "Infill Jerk",
|
"label": "Infill Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which infill is printed.",
|
"description": "The maximum instantaneous velocity change with which infill is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1633,7 +1771,7 @@
|
|||||||
"jerk_wall": {
|
"jerk_wall": {
|
||||||
"label": "Wall Jerk",
|
"label": "Wall Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the walls are printed.",
|
"description": "The maximum instantaneous velocity change with which the walls are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1646,7 +1784,7 @@
|
|||||||
"jerk_wall_0": {
|
"jerk_wall_0": {
|
||||||
"label": "Outer Wall Jerk",
|
"label": "Outer Wall Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the outermost walls are printed.",
|
"description": "The maximum instantaneous velocity change with which the outermost walls are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1659,7 +1797,7 @@
|
|||||||
"jerk_wall_x": {
|
"jerk_wall_x": {
|
||||||
"label": "Inner Wall Jerk",
|
"label": "Inner Wall Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which all inner walls are printed.",
|
"description": "The maximum instantaneous velocity change with which all inner walls are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1674,7 +1812,7 @@
|
|||||||
"jerk_topbottom": {
|
"jerk_topbottom": {
|
||||||
"label": "Top/Bottom Jerk",
|
"label": "Top/Bottom Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which top/bottom layers are printed.",
|
"description": "The maximum instantaneous velocity change with which top/bottom layers are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1687,21 +1825,21 @@
|
|||||||
"jerk_support": {
|
"jerk_support": {
|
||||||
"label": "Support Jerk",
|
"label": "Support Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the support structure is printed.",
|
"description": "The maximum instantaneous velocity change with which the support structure is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
"maximum_value_warning": "50",
|
"maximum_value_warning": "50",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "jerk_print",
|
"value": "jerk_print",
|
||||||
"enabled": "jerk_enabled and support_roof_enable",
|
"enabled": "jerk_enabled and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children": {
|
"children": {
|
||||||
"jerk_support_infill": {
|
"jerk_support_infill": {
|
||||||
"label": "Support Infill Jerk",
|
"label": "Support Infill Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the infill of support is printed.",
|
"description": "The maximum instantaneous velocity change with which the infill of support is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "jerk_support",
|
"value": "jerk_support",
|
||||||
@ -1715,14 +1853,14 @@
|
|||||||
"jerk_support_roof": {
|
"jerk_support_roof": {
|
||||||
"label": "Support Roof Jerk",
|
"label": "Support Roof Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the roofs of support are printed.",
|
"description": "The maximum instantaneous velocity change with which the roofs of support are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "jerk_support",
|
"value": "jerk_support",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
"maximum_value_warning": "50",
|
"maximum_value_warning": "50",
|
||||||
"enabled": "jerk_enabled and support_roof_enable",
|
"enabled": "jerk_enabled and support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
}
|
}
|
||||||
@ -1731,7 +1869,7 @@
|
|||||||
"jerk_prime_tower": {
|
"jerk_prime_tower": {
|
||||||
"label": "Prime Tower Jerk",
|
"label": "Prime Tower Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the prime tower is printed.",
|
"description": "The maximum instantaneous velocity change with which the prime tower is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
"minimum_value_warning": "5",
|
"minimum_value_warning": "5",
|
||||||
@ -1746,7 +1884,7 @@
|
|||||||
"jerk_travel": {
|
"jerk_travel": {
|
||||||
"label": "Travel Jerk",
|
"label": "Travel Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which travel moves are made.",
|
"description": "The maximum instantaneous velocity change with which travel moves are made.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 30,
|
"default_value": 30,
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
@ -1759,7 +1897,7 @@
|
|||||||
"jerk_layer_0": {
|
"jerk_layer_0": {
|
||||||
"label": "Initial Layer Jerk",
|
"label": "Initial Layer Jerk",
|
||||||
"description": "The print maximum instantaneous velocity change for the initial layer.",
|
"description": "The print maximum instantaneous velocity change for the initial layer.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "jerk_print",
|
"value": "jerk_print",
|
||||||
@ -1772,7 +1910,7 @@
|
|||||||
"jerk_skirt": {
|
"jerk_skirt": {
|
||||||
"label": "Skirt Jerk",
|
"label": "Skirt Jerk",
|
||||||
"description": "The maximum instantaneous velocity change with which the skirt and brim are printed.",
|
"description": "The maximum instantaneous velocity change with which the skirt and brim are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
@ -2211,7 +2349,7 @@
|
|||||||
"default_value": 1,
|
"default_value": 1,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "10",
|
"maximum_value_warning": "10",
|
||||||
"enabled": "support_roof_enable",
|
"enabled": "support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
"support_roof_density":
|
"support_roof_density":
|
||||||
@ -2223,7 +2361,7 @@
|
|||||||
"default_value": 100,
|
"default_value": 100,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "100",
|
"maximum_value_warning": "100",
|
||||||
"enabled":"support_roof_enable",
|
"enabled":"support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children":
|
"children":
|
||||||
@ -2237,7 +2375,7 @@
|
|||||||
"default_value": 0.4,
|
"default_value": 0.4,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))",
|
"value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))",
|
||||||
"enabled": "support_roof_enable",
|
"enabled": "support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
}
|
}
|
||||||
@ -2257,7 +2395,7 @@
|
|||||||
"zigzag": "Zig Zag"
|
"zigzag": "Zig Zag"
|
||||||
},
|
},
|
||||||
"default_value": "concentric",
|
"default_value": "concentric",
|
||||||
"enabled": "support_roof_enable",
|
"enabled": "support_roof_enable and support_enable",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
@ -2317,6 +2455,32 @@
|
|||||||
"description": "Adhesion",
|
"description": "Adhesion",
|
||||||
"children":
|
"children":
|
||||||
{
|
{
|
||||||
|
"extruder_prime_pos_x":
|
||||||
|
{
|
||||||
|
"label": "Extruder Prime X Position",
|
||||||
|
"description": "The X coordinate of the position where the nozzle primes at the start of printing.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 0,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value_warning": "machine_width",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true,
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"extruder_prime_pos_y":
|
||||||
|
{
|
||||||
|
"label": "Extruder Prime Y Position",
|
||||||
|
"description": "The Y coordinate of the position where the nozzle primes at the start of printing.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 0,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value_warning": "machine_depth",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true,
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
"adhesion_type":
|
"adhesion_type":
|
||||||
{
|
{
|
||||||
"label": "Platform Adhesion Type",
|
"label": "Platform Adhesion Type",
|
||||||
@ -2701,7 +2865,7 @@
|
|||||||
"raft_jerk": {
|
"raft_jerk": {
|
||||||
"label": "Raft Print Jerk",
|
"label": "Raft Print Jerk",
|
||||||
"description": "The jerk with which the raft is printed.",
|
"description": "The jerk with which the raft is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"minimum_value": "0.1",
|
"minimum_value": "0.1",
|
||||||
@ -2714,7 +2878,7 @@
|
|||||||
"raft_surface_jerk": {
|
"raft_surface_jerk": {
|
||||||
"label": "Raft Top Print Jerk",
|
"label": "Raft Top Print Jerk",
|
||||||
"description": "The jerk with which the top raft layers are printed.",
|
"description": "The jerk with which the top raft layers are printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "raft_jerk",
|
"value": "raft_jerk",
|
||||||
@ -2727,7 +2891,7 @@
|
|||||||
"raft_interface_jerk": {
|
"raft_interface_jerk": {
|
||||||
"label": "Raft Middle Print Jerk",
|
"label": "Raft Middle Print Jerk",
|
||||||
"description": "The jerk with which the middle raft layer is printed.",
|
"description": "The jerk with which the middle raft layer is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "raft_jerk",
|
"value": "raft_jerk",
|
||||||
@ -2740,7 +2904,7 @@
|
|||||||
"raft_base_jerk": {
|
"raft_base_jerk": {
|
||||||
"label": "Raft Base Print Jerk",
|
"label": "Raft Base Print Jerk",
|
||||||
"description": "The jerk with which the base raft layer is printed.",
|
"description": "The jerk with which the base raft layer is printed.",
|
||||||
"unit": "mm/s³",
|
"unit": "mm/s",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 20,
|
"default_value": 20,
|
||||||
"value": "raft_jerk",
|
"value": "raft_jerk",
|
||||||
|
@ -87,6 +87,21 @@
|
|||||||
"material_bed_temperature": {
|
"material_bed_temperature": {
|
||||||
"enabled": "False"
|
"enabled": "False"
|
||||||
},
|
},
|
||||||
|
"machine_max_feedrate_x": {
|
||||||
|
"default_value": 300
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_y": {
|
||||||
|
"default_value": 300
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_z": {
|
||||||
|
"default_value": 40
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_e": {
|
||||||
|
"default_value": 45
|
||||||
|
},
|
||||||
|
"machine_acceleration": {
|
||||||
|
"default_value": 3000
|
||||||
|
},
|
||||||
"material_diameter": {
|
"material_diameter": {
|
||||||
"enabled": "False"
|
"enabled": "False"
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
"overrides": {
|
"overrides": {
|
||||||
"machine_heated_bed": {
|
"machine_heated_bed": {
|
||||||
"default_value": true
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_z": {
|
||||||
|
"default_value": 30
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,18 @@ UM.MainWindow
|
|||||||
Component.onCompleted:
|
Component.onCompleted:
|
||||||
{
|
{
|
||||||
Printer.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
Printer.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
||||||
|
|
||||||
|
// Workaround silly issues with QML Action's shortcut property.
|
||||||
|
//
|
||||||
|
// Currently, there is no way to define shortcuts as "Application Shortcut".
|
||||||
|
// This means that all Actions are "Window Shortcuts". The code for this
|
||||||
|
// implements a rather naive check that just checks if any of the action's parents
|
||||||
|
// are a window. Since the "Actions" object is a singleton it has no parent by
|
||||||
|
// default. If we set its parent to something contained in this window, the
|
||||||
|
// shortcut will activate properly because one of its parents is a window.
|
||||||
|
//
|
||||||
|
// This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property.
|
||||||
|
Cura.Actions.parent = backgroundItem
|
||||||
}
|
}
|
||||||
|
|
||||||
Item
|
Item
|
||||||
@ -309,23 +321,7 @@ UM.MainWindow
|
|||||||
sourceSize.height: height;
|
sourceSize.height: height;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button
|
|
||||||
{
|
|
||||||
id: viewModeButton
|
|
||||||
|
|
||||||
anchors
|
|
||||||
{
|
|
||||||
top: toolbar.bottom;
|
|
||||||
topMargin: UM.Theme.getSize("window_margin").height;
|
|
||||||
left: parent.left;
|
|
||||||
}
|
|
||||||
text: catalog.i18nc("@action:button","View Mode");
|
|
||||||
iconSource: UM.Theme.getIcon("viewmode");
|
|
||||||
|
|
||||||
style: UM.Theme.styles.tool_button;
|
|
||||||
tooltip: '';
|
|
||||||
menu: ViewMenu { }
|
|
||||||
}
|
|
||||||
|
|
||||||
Toolbar
|
Toolbar
|
||||||
{
|
{
|
||||||
@ -355,6 +351,24 @@ UM.MainWindow
|
|||||||
width: UM.Theme.getSize("sidebar").width;
|
width: UM.Theme.getSize("sidebar").width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
id: viewModeButton
|
||||||
|
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: toolbar.bottom;
|
||||||
|
topMargin: UM.Theme.getSize("window_margin").height;
|
||||||
|
left: parent.left;
|
||||||
|
}
|
||||||
|
text: catalog.i18nc("@action:button","View Mode");
|
||||||
|
iconSource: UM.Theme.getIcon("viewmode");
|
||||||
|
|
||||||
|
style: UM.Theme.styles.tool_button;
|
||||||
|
tooltip: '';
|
||||||
|
menu: ViewMenu { }
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
id: viewportOverlay
|
id: viewportOverlay
|
||||||
@ -506,6 +520,17 @@ UM.MainWindow
|
|||||||
onTriggered: preferences.getCurrentItem().showProfileNameDialog()
|
onTriggered: preferences.getCurrentItem().showProfileNameDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlurSettings is a way to force the focus away from any of the setting items.
|
||||||
|
// We need to do this in order to keep the bindings intact.
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Cura.MachineManager
|
||||||
|
onBlurSettings:
|
||||||
|
{
|
||||||
|
contentItem.focus = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Menu
|
Menu
|
||||||
{
|
{
|
||||||
id: objectContextMenu;
|
id: objectContextMenu;
|
||||||
@ -615,7 +640,7 @@ UM.MainWindow
|
|||||||
//TODO: Support multiple file selection, workaround bug in KDE file dialog
|
//TODO: Support multiple file selection, workaround bug in KDE file dialog
|
||||||
//selectMultiple: true
|
//selectMultiple: true
|
||||||
nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
|
nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
|
||||||
folder: Printer.getDefaultPath()
|
folder: CuraApplication.getDefaultPath("dialog_load_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
//Because several implementations of the file dialog only update the folder
|
//Because several implementations of the file dialog only update the folder
|
||||||
@ -623,6 +648,7 @@ UM.MainWindow
|
|||||||
var f = folder;
|
var f = folder;
|
||||||
folder = f;
|
folder = f;
|
||||||
|
|
||||||
|
CuraApplication.setDefaultPath("dialog_load_path", folder);
|
||||||
UM.MeshFileHandler.readLocalFile(fileUrl)
|
UM.MeshFileHandler.readLocalFile(fileUrl)
|
||||||
var meshName = backgroundItem.getMeshName(fileUrl.toString())
|
var meshName = backgroundItem.getMeshName(fileUrl.toString())
|
||||||
backgroundItem.hasMesh(decodeURIComponent(meshName))
|
backgroundItem.hasMesh(decodeURIComponent(meshName))
|
||||||
|
@ -24,7 +24,8 @@ Rectangle {
|
|||||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||||
|
|
||||||
property variant printDuration: PrintInformation.currentPrintTime
|
property variant printDuration: PrintInformation.currentPrintTime
|
||||||
property variant printMaterialAmounts: PrintInformation.materialAmounts
|
property variant printMaterialLengths: PrintInformation.materialLengths
|
||||||
|
property variant printMaterialWeights: PrintInformation.materialWeights
|
||||||
|
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@ -195,9 +196,9 @@ Rectangle {
|
|||||||
text:
|
text:
|
||||||
{
|
{
|
||||||
var amounts = [];
|
var amounts = [];
|
||||||
if(base.printMaterialAmounts) {
|
if(base.printMaterialLengths) {
|
||||||
for(var index = 0; index < base.printMaterialAmounts.length; index++) {
|
for(var index = 0; index < base.printMaterialLengths.length; index++) {
|
||||||
amounts.push(base.printMaterialAmounts[index].toFixed(2));
|
amounts.push(base.printMaterialLengths[index].toFixed(2));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
amounts = ["0.00"];
|
amounts = ["0.00"];
|
||||||
|
@ -74,6 +74,7 @@ UM.ManagementPage
|
|||||||
Flow
|
Flow
|
||||||
{
|
{
|
||||||
id: machineActions
|
id: machineActions
|
||||||
|
visible: currentItem && currentItem.id == Cura.MachineManager.activeMachineId
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: machineName.bottom
|
anchors.top: machineName.bottom
|
||||||
|
@ -200,7 +200,7 @@ UM.ManagementPage
|
|||||||
title: catalog.i18nc("@title:window", "Import Material");
|
title: catalog.i18nc("@title:window", "Import Material");
|
||||||
selectExisting: true;
|
selectExisting: true;
|
||||||
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
|
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
|
||||||
folder: CuraApplication.getDefaultPath()
|
folder: CuraApplication.getDefaultPath("dialog_material_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
var result = Cura.ContainerManager.importContainer(fileUrl)
|
var result = Cura.ContainerManager.importContainer(fileUrl)
|
||||||
@ -221,6 +221,7 @@ UM.ManagementPage
|
|||||||
messageDialog.icon = StandardIcon.Critical
|
messageDialog.icon = StandardIcon.Critical
|
||||||
}
|
}
|
||||||
messageDialog.open()
|
messageDialog.open()
|
||||||
|
CuraApplication.setDefaultPath("dialog_material_path", folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +231,7 @@ UM.ManagementPage
|
|||||||
title: catalog.i18nc("@title:window", "Export Material");
|
title: catalog.i18nc("@title:window", "Export Material");
|
||||||
selectExisting: false;
|
selectExisting: false;
|
||||||
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
|
nameFilters: Cura.ContainerManager.getContainerNameFilters("material")
|
||||||
folder: CuraApplication.getDefaultPath()
|
folder: CuraApplication.getDefaultPath("dialog_material_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
if(base.currentItem.metadata.base_file)
|
if(base.currentItem.metadata.base_file)
|
||||||
@ -255,6 +256,7 @@ UM.ManagementPage
|
|||||||
messageDialog.text = catalog.i18nc("@info:status", "Successfully exported material to <filename>%1</filename>").arg(fileUrl)
|
messageDialog.text = catalog.i18nc("@info:status", "Successfully exported material to <filename>%1</filename>").arg(fileUrl)
|
||||||
messageDialog.open()
|
messageDialog.open()
|
||||||
}
|
}
|
||||||
|
CuraApplication.setDefaultPath("dialog_material_path", folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ UM.ManagementPage
|
|||||||
title: catalog.i18nc("@title:window", "Import Profile");
|
title: catalog.i18nc("@title:window", "Import Profile");
|
||||||
selectExisting: true;
|
selectExisting: true;
|
||||||
nameFilters: base.model.getFileNameFilters("profile_reader")
|
nameFilters: base.model.getFileNameFilters("profile_reader")
|
||||||
folder: base.model.getDefaultPath()
|
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
var result = base.model.importProfile(fileUrl)
|
var result = base.model.importProfile(fileUrl)
|
||||||
@ -309,6 +309,7 @@ UM.ManagementPage
|
|||||||
messageDialog.icon = StandardIcon.Critical
|
messageDialog.icon = StandardIcon.Critical
|
||||||
}
|
}
|
||||||
messageDialog.open()
|
messageDialog.open()
|
||||||
|
CuraApplication.setDefaultPath("dialog_profile_path", folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +319,7 @@ UM.ManagementPage
|
|||||||
title: catalog.i18nc("@title:window", "Export Profile");
|
title: catalog.i18nc("@title:window", "Export Profile");
|
||||||
selectExisting: false;
|
selectExisting: false;
|
||||||
nameFilters: base.model.getFileNameFilters("profile_writer")
|
nameFilters: base.model.getFileNameFilters("profile_writer")
|
||||||
folder: base.model.getDefaultPath()
|
folder: CuraApplication.getDefaultPath("dialog_profile_path")
|
||||||
onAccepted:
|
onAccepted:
|
||||||
{
|
{
|
||||||
var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter)
|
var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter)
|
||||||
@ -329,6 +330,7 @@ UM.ManagementPage
|
|||||||
messageDialog.open()
|
messageDialog.open()
|
||||||
}
|
}
|
||||||
// else pop-up Message thing from python code
|
// else pop-up Message thing from python code
|
||||||
|
CuraApplication.setDefaultPath("dialog_profile_path", folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,8 +215,9 @@ Item {
|
|||||||
// This ensures that the value in any of the deeper containers need not be removed, which is
|
// This ensures that the value in any of the deeper containers need not be removed, which is
|
||||||
// needed for the reset button (which deletes the top value) to correctly go back to profile
|
// needed for the reset button (which deletes the top value) to correctly go back to profile
|
||||||
// defaults.
|
// defaults.
|
||||||
propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry))
|
|
||||||
propertyProvider.setPropertyValue("state", "InstanceState.Calculated")
|
propertyProvider.setPropertyValue("state", "InstanceState.Calculated")
|
||||||
|
propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,14 +248,5 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections
|
|
||||||
{
|
|
||||||
target: Cura.MachineManager
|
|
||||||
onBlurSettings:
|
|
||||||
{
|
|
||||||
revertButton.focus = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UM.I18nCatalog { id: catalog; name: "cura" }
|
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ Item
|
|||||||
}
|
}
|
||||||
Label{
|
Label{
|
||||||
id: infillLabel
|
id: infillLabel
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
anchors.top: infillIconLining.bottom
|
anchors.top: infillIconLining.bottom
|
||||||
anchors.horizontalCenter: infillIconLining.horizontalCenter
|
anchors.horizontalCenter: infillIconLining.horizontalCenter
|
||||||
color: infillListView.activeIndex == index ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_border")
|
color: infillListView.activeIndex == index ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_border")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user