mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-06 05:23:58 -06:00
Merge branch 'master' of github.com:Ultimaker/Cura into CURA-7122_Include_description_in_search_field
This commit is contained in:
commit
134d79608f
38 changed files with 559 additions and 216 deletions
|
@ -1,5 +1,6 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Job import Job
|
||||
|
@ -94,6 +95,7 @@ class ArrangeObjectsJob(Job):
|
|||
|
||||
status_message.setProgress((idx + 1) / len(nodes_arr) * 100)
|
||||
Job.yieldThread()
|
||||
QCoreApplication.processEvents()
|
||||
|
||||
grouped_operation.push()
|
||||
|
||||
|
|
|
@ -92,6 +92,8 @@ class BuildVolume(SceneNode):
|
|||
self._adhesion_type = None # type: Any
|
||||
self._platform = Platform(self)
|
||||
|
||||
self._edge_disallowed_size = None
|
||||
|
||||
self._build_volume_message = Message(catalog.i18nc("@info:status",
|
||||
"The build volume height has been reduced due to the value of the"
|
||||
" \"Print Sequence\" setting to prevent the gantry from colliding"
|
||||
|
@ -106,8 +108,6 @@ class BuildVolume(SceneNode):
|
|||
|
||||
self._application.globalContainerStackChanged.connect(self._onStackChanged)
|
||||
|
||||
self._onStackChanged()
|
||||
|
||||
self._engine_ready = False
|
||||
self._application.engineCreatedSignal.connect(self._onEngineCreated)
|
||||
|
||||
|
@ -118,7 +118,7 @@ class BuildVolume(SceneNode):
|
|||
self._scene_objects = set() # type: Set[SceneNode]
|
||||
|
||||
self._scene_change_timer = QTimer()
|
||||
self._scene_change_timer.setInterval(100)
|
||||
self._scene_change_timer.setInterval(200)
|
||||
self._scene_change_timer.setSingleShot(True)
|
||||
self._scene_change_timer.timeout.connect(self._onSceneChangeTimerFinished)
|
||||
|
||||
|
@ -747,6 +747,7 @@ class BuildVolume(SceneNode):
|
|||
self._error_areas = []
|
||||
|
||||
used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
|
||||
self._edge_disallowed_size = None # Force a recalculation
|
||||
disallowed_border_size = self.getEdgeDisallowedSize()
|
||||
|
||||
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) # Normal machine disallowed areas can always be added.
|
||||
|
@ -1124,6 +1125,9 @@ class BuildVolume(SceneNode):
|
|||
if not self._global_container_stack or not self._global_container_stack.extruderList:
|
||||
return 0
|
||||
|
||||
if self._edge_disallowed_size is not None:
|
||||
return self._edge_disallowed_size
|
||||
|
||||
container_stack = self._global_container_stack
|
||||
used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
|
||||
|
||||
|
@ -1139,8 +1143,8 @@ class BuildVolume(SceneNode):
|
|||
# Now combine our different pieces of data to get the final border size.
|
||||
# Support expansion is added to the bed adhesion, since the bed adhesion goes around support.
|
||||
# Support expansion is added to farthest shield distance, since the shields go around support.
|
||||
border_size = max(move_from_wall_radius, support_expansion + farthest_shield_distance, support_expansion + bed_adhesion_size)
|
||||
return border_size
|
||||
self._edge_disallowed_size = max(move_from_wall_radius, support_expansion + farthest_shield_distance, support_expansion + bed_adhesion_size)
|
||||
return self._edge_disallowed_size
|
||||
|
||||
def _clamp(self, value, min_value, max_value):
|
||||
return max(min(value, max_value), min_value)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2020 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import time
|
||||
|
@ -14,6 +14,7 @@ from UM.Settings.Validator import ValidatorState
|
|||
|
||||
import cura.CuraApplication
|
||||
|
||||
|
||||
class MachineErrorChecker(QObject):
|
||||
"""This class performs setting error checks for the currently active machine.
|
||||
|
||||
|
@ -50,6 +51,8 @@ class MachineErrorChecker(QObject):
|
|||
self._error_check_timer.setInterval(100)
|
||||
self._error_check_timer.setSingleShot(True)
|
||||
|
||||
self._keys_to_check = set() # type: Set[str]
|
||||
|
||||
def initialize(self) -> None:
|
||||
self._error_check_timer.timeout.connect(self._rescheduleCheck)
|
||||
|
||||
|
@ -103,6 +106,7 @@ class MachineErrorChecker(QObject):
|
|||
|
||||
if property_name != "value":
|
||||
return
|
||||
self._keys_to_check.add(key)
|
||||
self.startErrorCheck()
|
||||
|
||||
def startErrorCheck(self, *args: Any) -> None:
|
||||
|
@ -140,7 +144,10 @@ class MachineErrorChecker(QObject):
|
|||
# Populate the (stack, key) tuples to check
|
||||
self._stacks_and_keys_to_check = deque()
|
||||
for stack in global_stack.extruderList:
|
||||
for key in stack.getAllKeys():
|
||||
if not self._keys_to_check:
|
||||
self._keys_to_check = stack.getAllKeys()
|
||||
|
||||
for key in self._keys_to_check:
|
||||
self._stacks_and_keys_to_check.append((stack, key))
|
||||
|
||||
self._application.callLater(self._checkStack)
|
||||
|
@ -181,18 +188,25 @@ class MachineErrorChecker(QObject):
|
|||
validator = validator_type(key)
|
||||
validation_state = validator(stack)
|
||||
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError, ValidatorState.Invalid):
|
||||
# Finish
|
||||
self._setResult(True)
|
||||
# Since we don't know if any of the settings we didn't check is has an error value, store the list for the
|
||||
# next check.
|
||||
keys_to_recheck = {setting_key for stack, setting_key in self._stacks_and_keys_to_check}
|
||||
keys_to_recheck.add(key)
|
||||
self._setResult(True, keys_to_recheck = keys_to_recheck)
|
||||
return
|
||||
|
||||
# Schedule the check for the next key
|
||||
self._application.callLater(self._checkStack)
|
||||
|
||||
def _setResult(self, result: bool) -> None:
|
||||
def _setResult(self, result: bool, keys_to_recheck = None) -> None:
|
||||
if result != self._has_errors:
|
||||
self._has_errors = result
|
||||
self.hasErrorUpdated.emit()
|
||||
self._machine_manager.stacksValidationChanged.emit()
|
||||
if keys_to_recheck is None:
|
||||
self._keys_to_check = set()
|
||||
else:
|
||||
self._keys_to_check = keys_to_recheck
|
||||
self._need_to_check = False
|
||||
self._check_in_progress = False
|
||||
self.needToWaitForResultChanged.emit()
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
import copy
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Message import Message
|
||||
|
@ -93,8 +95,9 @@ class MultiplyObjectsJob(Job):
|
|||
nodes.append(new_node)
|
||||
current_progress += 1
|
||||
status_message.setProgress((current_progress / total_progress) * 100)
|
||||
QCoreApplication.processEvents()
|
||||
Job.yieldThread()
|
||||
|
||||
QCoreApplication.processEvents()
|
||||
Job.yieldThread()
|
||||
|
||||
if nodes:
|
||||
|
|
|
@ -54,7 +54,7 @@ class PickingPass(RenderPass):
|
|||
# Fill up the batch with objects that can be sliced. `
|
||||
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
|
||||
if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
|
||||
batch.addItem(node.getWorldTransformation(), node.getMeshData())
|
||||
batch.addItem(node.getWorldTransformation(copy = False), node.getMeshData())
|
||||
|
||||
self.bind()
|
||||
batch.render(self._scene.getActiveCamera())
|
||||
|
|
|
@ -114,12 +114,12 @@ class PreviewPass(RenderPass):
|
|||
1.0]
|
||||
uniforms["diffuse_color"] = prettier_color(diffuse_color)
|
||||
uniforms["diffuse_color_2"] = diffuse_color2
|
||||
batch_support_mesh.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms)
|
||||
batch_support_mesh.addItem(node.getWorldTransformation(copy = False), node.getMeshData(), uniforms = uniforms)
|
||||
else:
|
||||
# Normal scene node
|
||||
uniforms = {}
|
||||
uniforms["diffuse_color"] = prettier_color(cast(CuraSceneNode, node).getDiffuseColor())
|
||||
batch.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms)
|
||||
batch.addItem(node.getWorldTransformation(copy = False), node.getMeshData(), uniforms = uniforms)
|
||||
|
||||
self.bind()
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||
CuraApplication.getInstance().getController().toolOperationStarted.connect(self._onChanged)
|
||||
CuraApplication.getInstance().getController().toolOperationStopped.connect(self._onChanged)
|
||||
|
||||
self._root = Application.getInstance().getController().getScene().getRoot()
|
||||
|
||||
self._onGlobalStackChanged()
|
||||
|
||||
def createRecomputeConvexHullTimer(self) -> None:
|
||||
|
@ -198,23 +200,16 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||
CuraApplication.getInstance().callLater(self.recomputeConvexHullDelayed)
|
||||
|
||||
def recomputeConvexHull(self) -> None:
|
||||
controller = Application.getInstance().getController()
|
||||
root = controller.getScene().getRoot()
|
||||
if self._node is None or controller.isToolOperationActive() or not self.__isDescendant(root, self._node):
|
||||
# If the tool operation is still active, we need to compute the convex hull later after the controller is
|
||||
# no longer active.
|
||||
if controller.isToolOperationActive():
|
||||
self.recomputeConvexHullDelayed()
|
||||
return
|
||||
|
||||
if self._node is None or not self.__isDescendant(self._root, self._node):
|
||||
if self._convex_hull_node:
|
||||
# Convex hull node still exists, but the node is removed or no longer in the scene.
|
||||
self._convex_hull_node.setParent(None)
|
||||
self._convex_hull_node = None
|
||||
return
|
||||
|
||||
if self._convex_hull_node:
|
||||
self._convex_hull_node.setParent(None)
|
||||
hull_node = ConvexHullNode.ConvexHullNode(self._node, self.getPrintingArea(), self._raft_thickness, root)
|
||||
hull_node = ConvexHullNode.ConvexHullNode(self._node, self.getPrintingArea(), self._raft_thickness, self._root)
|
||||
self._convex_hull_node = hull_node
|
||||
|
||||
def _onSettingValueChanged(self, key: str, property_name: str) -> None:
|
||||
|
@ -273,7 +268,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||
if mesh is None:
|
||||
return Polygon([]) # Node has no mesh data, so just return an empty Polygon.
|
||||
|
||||
world_transform = self._node.getWorldTransformation()
|
||||
world_transform = self._node.getWorldTransformation(copy= False)
|
||||
|
||||
# Check the cache
|
||||
if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform:
|
||||
|
|
|
@ -57,13 +57,20 @@ class ConvexHullNode(SceneNode):
|
|||
self._hull = hull
|
||||
if self._hull:
|
||||
hull_mesh_builder = MeshBuilder()
|
||||
if self._thickness == 0:
|
||||
if hull_mesh_builder.addConvexPolygon(
|
||||
self._hull.getPoints()[::], # bottom layer is reversed
|
||||
self._mesh_height, color = self._color):
|
||||
|
||||
if hull_mesh_builder.addConvexPolygonExtrusion(
|
||||
self._hull.getPoints()[::-1], # bottom layer is reversed
|
||||
self._mesh_height - thickness, self._mesh_height, color = self._color):
|
||||
hull_mesh = hull_mesh_builder.build()
|
||||
self.setMeshData(hull_mesh)
|
||||
else:
|
||||
if hull_mesh_builder.addConvexPolygonExtrusion(
|
||||
self._hull.getPoints()[::-1], # bottom layer is reversed
|
||||
self._mesh_height - thickness, self._mesh_height, color = self._color):
|
||||
|
||||
hull_mesh = hull_mesh_builder.build()
|
||||
self.setMeshData(hull_mesh)
|
||||
hull_mesh = hull_mesh_builder.build()
|
||||
self.setMeshData(hull_mesh)
|
||||
|
||||
def getHull(self):
|
||||
return self._hull
|
||||
|
@ -79,15 +86,15 @@ class ConvexHullNode(SceneNode):
|
|||
ConvexHullNode.shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
|
||||
ConvexHullNode.shader.setUniformValue("u_diffuseColor", self._color)
|
||||
ConvexHullNode.shader.setUniformValue("u_opacity", 0.6)
|
||||
|
||||
if self.getParent():
|
||||
if self.getMeshData() and isinstance(self._node, SceneNode) and self._node.callDecoration("getBuildPlateNumber") == Application.getInstance().getMultiBuildPlateModel().activeBuildPlate:
|
||||
# The object itself (+ adhesion in one-at-a-time mode)
|
||||
renderer.queueNode(self, transparent = True, shader = ConvexHullNode.shader, backface_cull = True, sort = -8)
|
||||
if self._convex_hull_head_mesh:
|
||||
# The full head. Rendered as a hint to the user: If this area overlaps another object A; this object
|
||||
# cannot be printed after A, because the head would hit A while printing the current object
|
||||
renderer.queueNode(self, shader = ConvexHullNode.shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
|
||||
batch = renderer.getNamedBatch("convex_hull_node")
|
||||
if not batch:
|
||||
batch = renderer.createRenderBatch(transparent = True, shader = ConvexHullNode.shader, backface_cull = True, sort = -8)
|
||||
renderer.addRenderBatch(batch, name = "convex_hull_node")
|
||||
batch.addItem(self.getWorldTransformation(copy = False), self.getMeshData())
|
||||
if self._convex_hull_head_mesh:
|
||||
# The full head. Rendered as a hint to the user: If this area overlaps another object A; this object
|
||||
# cannot be printed after A, because the head would hit A while printing the current object
|
||||
renderer.queueNode(self, shader = ConvexHullNode.shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -97,7 +104,3 @@ class ConvexHullNode(SceneNode):
|
|||
convex_hull_head_builder = MeshBuilder()
|
||||
convex_hull_head_builder.addConvexPolygon(convex_hull_head.getPoints(), self._mesh_height - self._thickness)
|
||||
self._convex_hull_head_mesh = convex_hull_head_builder.build()
|
||||
|
||||
if not node:
|
||||
return
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ class CuraSceneNode(SceneNode):
|
|||
|
||||
self._aabb = None
|
||||
if self._mesh_data:
|
||||
self._aabb = self._mesh_data.getExtents(self.getWorldTransformation())
|
||||
self._aabb = self._mesh_data.getExtents(self.getWorldTransformation(copy = False))
|
||||
else: # If there is no mesh_data, use a bounding box that encompasses the local (0,0,0)
|
||||
position = self.getWorldPosition()
|
||||
self._aabb = AxisAlignedBox(minimum = position, maximum = position)
|
||||
|
@ -139,7 +139,7 @@ class CuraSceneNode(SceneNode):
|
|||
"""Taken from SceneNode, but replaced SceneNode with CuraSceneNode"""
|
||||
|
||||
copy = CuraSceneNode(no_setting_override = True) # Setting override will be added later
|
||||
copy.setTransformation(self.getLocalTransformation())
|
||||
copy.setTransformation(self.getLocalTransformation(copy= False))
|
||||
copy.setMeshData(self._mesh_data)
|
||||
copy.setVisible(cast(bool, deepcopy(self._visible, memo)))
|
||||
copy._selectable = cast(bool, deepcopy(self._selectable, memo))
|
||||
|
|
|
@ -204,49 +204,50 @@ class ExtruderManager(QObject):
|
|||
# If no extruders are registered in the extruder manager yet, return an empty array
|
||||
if len(self.extruderIds) == 0:
|
||||
return []
|
||||
number_active_extruders = len([extruder for extruder in self.getActiveExtruderStacks() if extruder.isEnabled])
|
||||
|
||||
# Get the extruders of all printable meshes in the scene
|
||||
meshes = [node for node in DepthFirstIterator(scene_root) if isinstance(node, SceneNode) and node.isSelectable()] #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
|
||||
nodes = [node for node in DepthFirstIterator(scene_root) if node.isSelectable() and not node.callDecoration("isAntiOverhangMesh") and not node.callDecoration("isSupportMesh")] #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
|
||||
|
||||
# Exclude anti-overhang meshes
|
||||
mesh_list = []
|
||||
for mesh in meshes:
|
||||
stack = mesh.callDecoration("getStack")
|
||||
if stack is not None and (stack.getProperty("anti_overhang_mesh", "value") or stack.getProperty("support_mesh", "value")):
|
||||
continue
|
||||
mesh_list.append(mesh)
|
||||
|
||||
for mesh in mesh_list:
|
||||
extruder_stack_id = mesh.callDecoration("getActiveExtruder")
|
||||
for node in nodes:
|
||||
extruder_stack_id = node.callDecoration("getActiveExtruder")
|
||||
if not extruder_stack_id:
|
||||
# No per-object settings for this node
|
||||
extruder_stack_id = self.extruderIds["0"]
|
||||
used_extruder_stack_ids.add(extruder_stack_id)
|
||||
|
||||
if len(used_extruder_stack_ids) == number_active_extruders:
|
||||
# We're already done. Stop looking.
|
||||
# Especially with a lot of models on the buildplate, this will speed up things rather dramatically.
|
||||
break
|
||||
|
||||
# Get whether any of them use support.
|
||||
stack_to_use = mesh.callDecoration("getStack") # if there is a per-mesh stack, we use it
|
||||
stack_to_use = node.callDecoration("getStack") # if there is a per-mesh stack, we use it
|
||||
if not stack_to_use:
|
||||
# if there is no per-mesh stack, we use the build extruder for this mesh
|
||||
stack_to_use = container_registry.findContainerStacks(id = extruder_stack_id)[0]
|
||||
|
||||
support_enabled |= stack_to_use.getProperty("support_enable", "value")
|
||||
support_bottom_enabled |= stack_to_use.getProperty("support_bottom_enable", "value")
|
||||
support_roof_enabled |= stack_to_use.getProperty("support_roof_enable", "value")
|
||||
if not support_enabled:
|
||||
support_enabled |= stack_to_use.getProperty("support_enable", "value")
|
||||
if not support_bottom_enabled:
|
||||
support_bottom_enabled |= stack_to_use.getProperty("support_bottom_enable", "value")
|
||||
if not support_roof_enabled:
|
||||
support_roof_enabled |= stack_to_use.getProperty("support_roof_enable", "value")
|
||||
|
||||
# Check limit to extruders
|
||||
limit_to_extruder_feature_list = ["wall_0_extruder_nr",
|
||||
"wall_x_extruder_nr",
|
||||
"roofing_extruder_nr",
|
||||
"top_bottom_extruder_nr",
|
||||
"infill_extruder_nr",
|
||||
]
|
||||
for extruder_nr_feature_name in limit_to_extruder_feature_list:
|
||||
extruder_nr = int(global_stack.getProperty(extruder_nr_feature_name, "value"))
|
||||
if extruder_nr == -1:
|
||||
continue
|
||||
if str(extruder_nr) not in self.extruderIds:
|
||||
extruder_nr = int(self._application.getMachineManager().defaultExtruderPosition)
|
||||
used_extruder_stack_ids.add(self.extruderIds[str(extruder_nr)])
|
||||
# Check limit to extruders
|
||||
limit_to_extruder_feature_list = ["wall_0_extruder_nr",
|
||||
"wall_x_extruder_nr",
|
||||
"roofing_extruder_nr",
|
||||
"top_bottom_extruder_nr",
|
||||
"infill_extruder_nr",
|
||||
]
|
||||
for extruder_nr_feature_name in limit_to_extruder_feature_list:
|
||||
extruder_nr = int(global_stack.getProperty(extruder_nr_feature_name, "value"))
|
||||
if extruder_nr == -1:
|
||||
continue
|
||||
if str(extruder_nr) not in self.extruderIds:
|
||||
extruder_nr = int(self._application.getMachineManager().defaultExtruderPosition)
|
||||
used_extruder_stack_ids.add(self.extruderIds[str(extruder_nr)])
|
||||
|
||||
# Check support extruders
|
||||
if support_enabled:
|
||||
|
|
|
@ -35,7 +35,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
"""
|
||||
_non_thumbnail_visible_settings = {"anti_overhang_mesh", "infill_mesh", "cutting_mesh", "support_mesh"}
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, *, force_update = True):
|
||||
super().__init__()
|
||||
self._stack = PerObjectContainerStack(container_id = "per_object_stack_" + str(id(self)))
|
||||
self._stack.setDirty(False) # This stack does not need to be saved.
|
||||
|
@ -46,6 +46,10 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
|
||||
self._is_non_printing_mesh = False
|
||||
self._is_non_thumbnail_visible_mesh = False
|
||||
self._is_support_mesh = False
|
||||
self._is_cutting_mesh = False
|
||||
self._is_infill_mesh = False
|
||||
self._is_anti_overhang_mesh = False
|
||||
|
||||
self._stack.propertyChanged.connect(self._onSettingChanged)
|
||||
|
||||
|
@ -53,13 +57,14 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack)
|
||||
self.activeExtruderChanged.connect(self._updateNextStack)
|
||||
self._updateNextStack()
|
||||
if force_update:
|
||||
self._updateNextStack()
|
||||
|
||||
def _generateUniqueName(self):
|
||||
return "SettingOverrideInstanceContainer-%s" % uuid.uuid1()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
deep_copy = SettingOverrideDecorator()
|
||||
deep_copy = SettingOverrideDecorator(force_update = False)
|
||||
"""Create a fresh decorator object"""
|
||||
|
||||
instance_container = copy.deepcopy(self._stack.getContainer(0), memo)
|
||||
|
@ -74,11 +79,6 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
# Properly set the right extruder on the copy
|
||||
deep_copy.setActiveExtruder(self._extruder_stack)
|
||||
|
||||
# use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh"
|
||||
# has not been updated yet.
|
||||
deep_copy._is_non_printing_mesh = self._evaluateIsNonPrintingMesh()
|
||||
deep_copy._is_non_thumbnail_visible_mesh = self._evaluateIsNonThumbnailVisibleMesh()
|
||||
|
||||
return deep_copy
|
||||
|
||||
def getActiveExtruder(self):
|
||||
|
@ -104,7 +104,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
"""
|
||||
|
||||
# for support_meshes, always use the support_extruder
|
||||
if self.getStack().getProperty("support_mesh", "value"):
|
||||
if self._is_support_mesh:
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
return str(global_container_stack.getProperty("support_extruder_nr", "value"))
|
||||
|
@ -114,6 +114,30 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
container_stack = containers[0]
|
||||
return container_stack.getMetaDataEntry("position", default=None)
|
||||
|
||||
def isCuttingMesh(self):
|
||||
return self._is_cutting_mesh
|
||||
|
||||
def isSupportMesh(self):
|
||||
return self._is_support_mesh
|
||||
|
||||
def isInfillMesh(self):
|
||||
return self._is_infill_mesh
|
||||
|
||||
def isAntiOverhangMesh(self):
|
||||
return self._is_anti_overhang_mesh
|
||||
|
||||
def _evaluateAntiOverhangMesh(self):
|
||||
return bool(self._stack.userChanges.getProperty("anti_overhang_mesh", "value"))
|
||||
|
||||
def _evaluateIsCuttingMesh(self):
|
||||
return bool(self._stack.userChanges.getProperty("cutting_mesh", "value"))
|
||||
|
||||
def _evaluateIsSupportMesh(self):
|
||||
return bool(self._stack.userChanges.getProperty("support_mesh", "value"))
|
||||
|
||||
def _evaluateInfillMesh(self):
|
||||
return bool(self._stack.userChanges.getProperty("infill_mesh", "value"))
|
||||
|
||||
def isNonPrintingMesh(self):
|
||||
return self._is_non_printing_mesh
|
||||
|
||||
|
@ -132,6 +156,16 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||
# Trigger slice/need slicing if the value has changed.
|
||||
self._is_non_printing_mesh = self._evaluateIsNonPrintingMesh()
|
||||
self._is_non_thumbnail_visible_mesh = self._evaluateIsNonThumbnailVisibleMesh()
|
||||
|
||||
if setting_key == "anti_overhang_mesh":
|
||||
self._is_anti_overhang_mesh = self._evaluateAntiOverhangMesh()
|
||||
elif setting_key == "support_mesh":
|
||||
self._is_support_mesh = self._evaluateIsSupportMesh()
|
||||
elif setting_key == "cutting_mesh":
|
||||
self._is_cutting_mesh = self._evaluateIsCuttingMesh()
|
||||
elif setting_key == "infill_mesh":
|
||||
self._is_infill_mesh = self._evaluateInfillMesh()
|
||||
|
||||
Application.getInstance().getBackend().needsSlicing()
|
||||
Application.getInstance().getBackend().tickle()
|
||||
|
||||
|
|
|
@ -98,7 +98,8 @@ class ObjectsModel(ListModel):
|
|||
|
||||
return True
|
||||
|
||||
def _renameNodes(self, node_info_dict: Dict[str, _NodeInfo]) -> List[SceneNode]:
|
||||
@staticmethod
|
||||
def _renameNodes(node_info_dict: Dict[str, _NodeInfo]) -> List[SceneNode]:
|
||||
# Go through all names and find out the names for all nodes that need to be renamed.
|
||||
all_nodes = [] # type: List[SceneNode]
|
||||
for name, node_info in node_info_dict.items():
|
||||
|
@ -118,9 +119,7 @@ class ObjectsModel(ListModel):
|
|||
else:
|
||||
new_group_name = "{0}#{1}".format(name, current_index)
|
||||
|
||||
old_name = node.getName()
|
||||
node.setName(new_group_name)
|
||||
Logger.log("d", "Node [%s] renamed to [%s]", old_name, new_group_name)
|
||||
all_nodes.append(node)
|
||||
return all_nodes
|
||||
|
||||
|
@ -186,11 +185,18 @@ class ObjectsModel(ListModel):
|
|||
if per_object_stack:
|
||||
per_object_settings_count = per_object_stack.getTop().getNumInstances()
|
||||
|
||||
for mesh_type in ["anti_overhang_mesh", "infill_mesh", "cutting_mesh", "support_mesh"]:
|
||||
if per_object_stack.getProperty(mesh_type, "value"):
|
||||
node_mesh_type = mesh_type
|
||||
per_object_settings_count -= 1 # do not count this mesh type setting
|
||||
break
|
||||
if node.callDecoration("isAntiOverhangMesh"):
|
||||
node_mesh_type = "anti_overhang_mesh"
|
||||
per_object_settings_count -= 1 # do not count this mesh type setting
|
||||
elif node.callDecoration("isSupportMesh"):
|
||||
node_mesh_type = "support_mesh"
|
||||
per_object_settings_count -= 1 # do not count this mesh type setting
|
||||
elif node.callDecoration("isCuttingMesh"):
|
||||
node_mesh_type = "cutting_mesh"
|
||||
per_object_settings_count -= 1 # do not count this mesh type setting
|
||||
elif node.callDecoration("isInfillMesh"):
|
||||
node_mesh_type = "infill_mesh"
|
||||
per_object_settings_count -= 1 # do not count this mesh type setting
|
||||
|
||||
if per_object_settings_count > 0:
|
||||
if node_mesh_type == "support_mesh":
|
||||
|
|
|
@ -29,7 +29,7 @@ class XRayPass(RenderPass):
|
|||
batch = RenderBatch(self._shader, type = RenderBatch.RenderType.NoType, backface_cull = False, blend_mode = RenderBatch.BlendMode.Additive)
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if isinstance(node, CuraSceneNode) and node.getMeshData() and node.isVisible():
|
||||
batch.addItem(node.getWorldTransformation(), node.getMeshData())
|
||||
batch.addItem(node.getWorldTransformation(copy = False), node.getMeshData())
|
||||
|
||||
self.bind()
|
||||
|
||||
|
|
|
@ -8,12 +8,14 @@ import time
|
|||
from typing import Any, cast, Dict, List, Optional, Set
|
||||
import re
|
||||
import Arcus #For typing.
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Logger import Logger
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Settings.ContainerStack import ContainerStack #For typing.
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.Interfaces import ContainerInterface
|
||||
from UM.Settings.SettingDefinition import SettingDefinition
|
||||
from UM.Settings.SettingRelation import SettingRelation #For typing.
|
||||
|
||||
|
@ -352,8 +354,7 @@ class StartSliceJob(Job):
|
|||
|
||||
result = {}
|
||||
for key in stack.getAllKeys():
|
||||
value = stack.getProperty(key, "value")
|
||||
result[key] = value
|
||||
result[key] = stack.getProperty(key, "value")
|
||||
Job.yieldThread()
|
||||
|
||||
result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings.
|
||||
|
@ -373,9 +374,11 @@ class StartSliceJob(Job):
|
|||
self._all_extruders_settings = {
|
||||
"-1": self._buildReplacementTokens(global_stack)
|
||||
}
|
||||
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
|
||||
for extruder_stack in ExtruderManager.getInstance().getActiveExtruderStacks():
|
||||
extruder_nr = extruder_stack.getProperty("extruder_nr", "value")
|
||||
self._all_extruders_settings[str(extruder_nr)] = self._buildReplacementTokens(extruder_stack)
|
||||
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
|
||||
|
||||
def _expandGcodeTokens(self, value: str, default_extruder_nr: int = -1) -> str:
|
||||
"""Replace setting tokens in a piece of g-code.
|
||||
|
@ -420,10 +423,15 @@ class StartSliceJob(Job):
|
|||
settings["machine_extruder_start_code"] = self._expandGcodeTokens(settings["machine_extruder_start_code"], extruder_nr)
|
||||
settings["machine_extruder_end_code"] = self._expandGcodeTokens(settings["machine_extruder_end_code"], extruder_nr)
|
||||
|
||||
global_definition = cast(ContainerInterface, cast(ContainerStack, stack.getNextStack()).getBottom())
|
||||
own_definition = cast(ContainerInterface, stack.getBottom())
|
||||
|
||||
for key, value in settings.items():
|
||||
# Do not send settings that are not settable_per_extruder.
|
||||
if not stack.getProperty(key, "settable_per_extruder"):
|
||||
continue
|
||||
# Since these can only be set in definition files, we only have to ask there.
|
||||
if not global_definition.getProperty(key, "settable_per_extruder") and \
|
||||
not own_definition.getProperty(key, "settable_per_extruder"):
|
||||
continue
|
||||
setting = message.getMessage("settings").addRepeatedMessage("settings")
|
||||
setting.name = key
|
||||
setting.value = str(value).encode("utf-8")
|
||||
|
@ -454,11 +462,10 @@ class StartSliceJob(Job):
|
|||
print_temperature_settings = ["material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"]
|
||||
pattern = r"\{(%s)(,\s?\w+)?\}" % "|".join(print_temperature_settings) # match {setting} as well as {setting, extruder_nr}
|
||||
settings["material_print_temp_prepend"] = re.search(pattern, start_gcode) == None
|
||||
|
||||
# Replace the setting tokens in start and end g-code.
|
||||
# Use values from the first used extruder by default so we get the expected temperatures
|
||||
initial_extruder_stack = CuraApplication.getInstance().getExtruderManager().getUsedExtruderStacks()[0]
|
||||
initial_extruder_nr = initial_extruder_stack.getProperty("extruder_nr", "value")
|
||||
|
||||
initial_extruder_nr = CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()
|
||||
settings["machine_start_gcode"] = self._expandGcodeTokens(settings["machine_start_gcode"], initial_extruder_nr)
|
||||
settings["machine_end_gcode"] = self._expandGcodeTokens(settings["machine_end_gcode"], initial_extruder_nr)
|
||||
|
||||
|
|
|
@ -141,52 +141,46 @@ class Script:
|
|||
All other keyword parameters are put in the result in g-code's format.
|
||||
For instance, if you put ``G=1`` in the parameters, it will output
|
||||
``G1``. If you put ``G=1, X=100`` in the parameters, it will output
|
||||
``G1 X100``. The parameters G and M will always be put first. The
|
||||
parameters T and S will be put second (or first if there is no G or M).
|
||||
The rest of the parameters will be put in arbitrary order.
|
||||
``G1 X100``. The parameters will be added in order G M T S F X Y Z E.
|
||||
Any other parameters will be added in arbitrary order.
|
||||
|
||||
:param line: The original g-code line that must be modified. If not
|
||||
provided, an entirely new g-code line will be produced.
|
||||
:return: A line of g-code with the desired parameters filled in.
|
||||
"""
|
||||
|
||||
#Strip the comment.
|
||||
comment = ""
|
||||
# Strip the comment.
|
||||
if ";" in line:
|
||||
comment = line[line.find(";"):]
|
||||
line = line[:line.find(";")] #Strip the comment.
|
||||
line = line[:line.find(";")]
|
||||
else:
|
||||
comment = ""
|
||||
|
||||
#Parse the original g-code line.
|
||||
# Parse the original g-code line and add them to kwargs.
|
||||
for part in line.split(" "):
|
||||
if part == "":
|
||||
continue
|
||||
parameter = part[0]
|
||||
if parameter not in kwargs:
|
||||
value = part[1:]
|
||||
kwargs[parameter] = value
|
||||
|
||||
# Start writing the new g-code line.
|
||||
line_parts = list()
|
||||
# First add these parameters in order
|
||||
for parameter in ["G", "M", "T", "S", "F", "X", "Y", "Z", "E"]:
|
||||
if parameter in kwargs:
|
||||
continue #Skip this one. The user-provided parameter overwrites the one in the line.
|
||||
value = part[1:]
|
||||
kwargs[parameter] = value
|
||||
value = kwargs.pop(parameter) # get the corresponding value and remove the parameter from kwargs
|
||||
line_parts.append(parameter + str(value))
|
||||
# Then add the rest of the parameters
|
||||
for parameter, value in kwargs.items():
|
||||
line_parts.append(parameter + str(value))
|
||||
|
||||
#Write the new g-code line.
|
||||
result = ""
|
||||
priority_parameters = ["G", "M", "T", "S", "F", "X", "Y", "Z", "E"] #First some parameters that get priority. In order of priority!
|
||||
for priority_key in priority_parameters:
|
||||
if priority_key in kwargs:
|
||||
if result != "":
|
||||
result += " "
|
||||
result += priority_key + str(kwargs[priority_key])
|
||||
del kwargs[priority_key]
|
||||
for key, value in kwargs.items():
|
||||
if result != "":
|
||||
result += " "
|
||||
result += key + str(value)
|
||||
|
||||
#Put the comment back in.
|
||||
# If there was a comment, put it at the end.
|
||||
if comment != "":
|
||||
if result != "":
|
||||
result += " "
|
||||
result += ";" + comment
|
||||
line_parts.append(comment)
|
||||
|
||||
return result
|
||||
# Add spaces and return the new line
|
||||
return " ".join(line_parts)
|
||||
|
||||
def execute(self, data: List[str]) -> List[str]:
|
||||
"""This is called when the script is executed.
|
||||
|
|
|
@ -199,7 +199,7 @@ class SliceInfo(QObject, Extension):
|
|||
"maximum": {"x": bounding_box.maximum.x,
|
||||
"y": bounding_box.maximum.y,
|
||||
"z": bounding_box.maximum.z}}
|
||||
model["transformation"] = {"data": str(node.getWorldTransformation().getData()).replace("\n", "")}
|
||||
model["transformation"] = {"data": str(node.getWorldTransformation(copy = False).getData()).replace("\n", "")}
|
||||
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||
model["extruder"] = 0 if extruder_position is None else int(extruder_position)
|
||||
|
||||
|
|
|
@ -64,17 +64,23 @@ class SolidView(View):
|
|||
self._old_layer_bindings = None
|
||||
|
||||
self._next_xray_checking_time = time.time()
|
||||
self._xray_checking_update_time = 1.0 # seconds
|
||||
self._xray_checking_update_time = 30.0 # seconds
|
||||
self._xray_warning_cooldown = 60 * 10 # reshow Model error message every 10 minutes
|
||||
self._xray_warning_message = Message(
|
||||
catalog.i18nc("@info:status", "Your model is not manifold. The highlighted areas indicate either missing or extraneous surfaces."),
|
||||
lifetime = 60 * 5, # leave message for 5 minutes
|
||||
title = catalog.i18nc("@info:title", "Model errors"),
|
||||
option_text = catalog.i18nc("@info:option_text", "Do not show this message again"),
|
||||
option_state = False
|
||||
)
|
||||
self._xray_warning_message.optionToggled.connect(self._onDontAskMeAgain)
|
||||
application.getPreferences().addPreference(self._show_xray_warning_preference, True)
|
||||
|
||||
application.engineCreatedSignal.connect(self._onGlobalContainerChanged)
|
||||
|
||||
def _onDontAskMeAgain(self, checked: bool) -> None:
|
||||
Application.getInstance().getPreferences().setValue(self._show_xray_warning_preference, not checked)
|
||||
|
||||
def _onGlobalContainerChanged(self) -> None:
|
||||
if self._global_stack:
|
||||
try:
|
||||
|
@ -103,7 +109,9 @@ class SolidView(View):
|
|||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
self._support_angle = support_angle_stack.getProperty("support_angle", "value")
|
||||
angle = support_angle_stack.getProperty("support_angle", "value")
|
||||
if angle is not None:
|
||||
self._support_angle = angle
|
||||
|
||||
def _checkSetup(self):
|
||||
if not self._extruders_model:
|
||||
|
@ -115,6 +123,7 @@ class SolidView(View):
|
|||
if not self._enabled_shader:
|
||||
self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
|
||||
self._enabled_shader.setUniformValue("u_overhangColor", Color(*self._theme.getColor("model_overhang").getRgb()))
|
||||
self._enabled_shader.setUniformValue("u_renderError", 0.0)
|
||||
|
||||
if not self._disabled_shader:
|
||||
self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
|
||||
|
@ -140,6 +149,7 @@ class SolidView(View):
|
|||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
||||
self._old_layer_bindings = None
|
||||
self._old_composite_shader = None
|
||||
self._enabled_shader.setUniformValue("u_renderError", 0.0) # We don't want any error markers!.
|
||||
self._xray_warning_message.hide()
|
||||
else:
|
||||
if not self._xray_shader:
|
||||
|
@ -157,7 +167,7 @@ class SolidView(View):
|
|||
# Currently the RenderPass constructor requires a size > 0
|
||||
# This should be fixed in RenderPass's constructor.
|
||||
self._xray_pass = XRayPass.XRayPass(1, 1)
|
||||
|
||||
self._enabled_shader.setUniformValue("u_renderError", 1.0) # We don't want any error markers!.
|
||||
renderer.addRenderPass(self._xray_pass)
|
||||
|
||||
if not self._composite_pass:
|
||||
|
@ -178,77 +188,77 @@ class SolidView(View):
|
|||
if global_container_stack:
|
||||
if Application.getInstance().getPreferences().getValue("view/show_overhang"):
|
||||
# Make sure the overhang angle is valid before passing it to the shader
|
||||
if self._support_angle is not None and self._support_angle >= 0 and self._support_angle <= 90:
|
||||
if self._support_angle >= 0 and self._support_angle <= 90:
|
||||
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - self._support_angle)))
|
||||
else:
|
||||
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang.
|
||||
else:
|
||||
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))
|
||||
|
||||
disabled_batch = renderer.createRenderBatch(shader = self._disabled_shader)
|
||||
normal_object_batch = renderer.createRenderBatch(shader = self._enabled_shader)
|
||||
renderer.addRenderBatch(disabled_batch)
|
||||
renderer.addRenderBatch(normal_object_batch)
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"):
|
||||
uniforms = {}
|
||||
shade_factor = 1.0
|
||||
if node.render(renderer):
|
||||
continue
|
||||
|
||||
per_mesh_stack = node.callDecoration("getStack")
|
||||
if node.getMeshData() and node.isVisible():
|
||||
uniforms = {}
|
||||
shade_factor = 1.0
|
||||
|
||||
extruder_index = node.callDecoration("getActiveExtruderPosition")
|
||||
if extruder_index is None:
|
||||
extruder_index = "0"
|
||||
extruder_index = int(extruder_index)
|
||||
per_mesh_stack = node.callDecoration("getStack")
|
||||
|
||||
# Use the support extruder instead of the active extruder if this is a support_mesh
|
||||
if per_mesh_stack:
|
||||
if per_mesh_stack.getProperty("support_mesh", "value"):
|
||||
extruder_index = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr"))
|
||||
extruder_index = node.callDecoration("getActiveExtruderPosition")
|
||||
if extruder_index is None:
|
||||
extruder_index = "0"
|
||||
extruder_index = int(extruder_index)
|
||||
|
||||
try:
|
||||
material_color = self._extruders_model.getItem(extruder_index)["color"]
|
||||
except KeyError:
|
||||
material_color = self._extruders_model.defaultColors[0]
|
||||
try:
|
||||
material_color = self._extruders_model.getItem(extruder_index)["color"]
|
||||
except KeyError:
|
||||
material_color = self._extruders_model.defaultColors[0]
|
||||
|
||||
if extruder_index != ExtruderManager.getInstance().activeExtruderIndex:
|
||||
# Shade objects that are printed with the non-active extruder 25% darker
|
||||
shade_factor = 0.6
|
||||
if extruder_index != ExtruderManager.getInstance().activeExtruderIndex:
|
||||
# Shade objects that are printed with the non-active extruder 25% darker
|
||||
shade_factor = 0.6
|
||||
|
||||
try:
|
||||
# Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
|
||||
# an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
|
||||
uniforms["diffuse_color"] = [
|
||||
shade_factor * int(material_color[1:3], 16) / 255,
|
||||
shade_factor * int(material_color[3:5], 16) / 255,
|
||||
shade_factor * int(material_color[5:7], 16) / 255,
|
||||
1.0
|
||||
]
|
||||
try:
|
||||
# Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
|
||||
# an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
|
||||
uniforms["diffuse_color"] = [
|
||||
shade_factor * int(material_color[1:3], 16) / 255,
|
||||
shade_factor * int(material_color[3:5], 16) / 255,
|
||||
shade_factor * int(material_color[5:7], 16) / 255,
|
||||
1.0
|
||||
]
|
||||
|
||||
# Color the currently selected face-id. (Disable for now.)
|
||||
#face = Selection.getHoverFace()
|
||||
uniforms["hover_face"] = -1 #if not face or node != face[0] else face[1]
|
||||
except ValueError:
|
||||
pass
|
||||
# Color the currently selected face-id. (Disable for now.)
|
||||
#face = Selection.getHoverFace()
|
||||
uniforms["hover_face"] = -1 #if not face or node != face[0] else face[1]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if node.callDecoration("isNonPrintingMesh"):
|
||||
if per_mesh_stack and (per_mesh_stack.getProperty("infill_mesh", "value") or per_mesh_stack.getProperty("cutting_mesh", "value")):
|
||||
renderer.queueNode(node, shader = self._non_printing_shader, uniforms = uniforms, transparent = True)
|
||||
else:
|
||||
renderer.queueNode(node, shader = self._non_printing_shader, transparent = True)
|
||||
elif getattr(node, "_outside_buildarea", False):
|
||||
renderer.queueNode(node, shader = self._disabled_shader)
|
||||
elif per_mesh_stack and per_mesh_stack.getProperty("support_mesh", "value"):
|
||||
# Render support meshes with a vertical stripe that is darker
|
||||
shade_factor = 0.6
|
||||
uniforms["diffuse_color_2"] = [
|
||||
uniforms["diffuse_color"][0] * shade_factor,
|
||||
uniforms["diffuse_color"][1] * shade_factor,
|
||||
uniforms["diffuse_color"][2] * shade_factor,
|
||||
1.0
|
||||
]
|
||||
renderer.queueNode(node, shader = self._support_mesh_shader, uniforms = uniforms)
|
||||
if node.callDecoration("isNonPrintingMesh"):
|
||||
if per_mesh_stack and (node.callDecoration("isInfillMesh") or node.callDecoration("isCuttingMesh")):
|
||||
renderer.queueNode(node, shader = self._non_printing_shader, uniforms = uniforms, transparent = True)
|
||||
else:
|
||||
renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
|
||||
if node.callDecoration("isGroup") and Selection.isSelected(node):
|
||||
renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = RenderBatch.RenderMode.LineLoop)
|
||||
renderer.queueNode(node, shader = self._non_printing_shader, transparent = True)
|
||||
elif getattr(node, "_outside_buildarea", False):
|
||||
disabled_batch.addItem(node.getWorldTransformation(copy = False), node.getMeshData())
|
||||
elif per_mesh_stack and node.callDecoration("isSupportMesh"):
|
||||
# Render support meshes with a vertical stripe that is darker
|
||||
shade_factor = 0.6
|
||||
uniforms["diffuse_color_2"] = [
|
||||
uniforms["diffuse_color"][0] * shade_factor,
|
||||
uniforms["diffuse_color"][1] * shade_factor,
|
||||
uniforms["diffuse_color"][2] * shade_factor,
|
||||
1.0
|
||||
]
|
||||
renderer.queueNode(node, shader = self._support_mesh_shader, uniforms = uniforms)
|
||||
else:
|
||||
normal_object_batch.addItem(node.getWorldTransformation(copy=False), node.getMeshData(), uniforms=uniforms)
|
||||
if node.callDecoration("isGroup") and Selection.isSelected(node):
|
||||
renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = RenderBatch.RenderMode.LineLoop)
|
||||
|
||||
def endRendering(self):
|
||||
# check whether the xray overlay is showing badness
|
||||
|
|
58
resources/definitions/beamup_l.def.json
Normal file
58
resources/definitions/beamup_l.def.json
Normal file
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "BeamUp L",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "BeamUp",
|
||||
"manufacturer": "BeamUp",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "beamup_l.3mf",
|
||||
"platform_offset": [0, -2.5, -2.5],
|
||||
"has_machine_quality": true,
|
||||
"has_materials": true,
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "beamup_l_extruder_0"
|
||||
}
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": {
|
||||
"default_value": "BeamUp L"
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 320
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 320
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 300
|
||||
},
|
||||
"machine_heated_bed": {
|
||||
"default_value": false
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default_value": false
|
||||
},
|
||||
"machine_nozzle_heat_up_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"machine_nozzle_cool_down_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"gantry_height": {
|
||||
"value": "0"
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default_value": "RepRap (Marlin/Sprinter)"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G28 ; home\nG29 ; level\nM80 ; led\nG1 Z15.0 F6000\nT0\nG92 E0.0000\nG1 E-1.4500 F1800\nG1 X50 Y0 Z0.300 F6000\nM300 S3000 P300\nG1 E1.0000 F1800\nG92 E0.0000\nG1 X250 Y0 E15 F662"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "G28 ; home\nM104 S0 ; turn off\n M140 S0 ; turn off\nM84 ; disable motors\nM107 ; fan off"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6290,7 +6290,7 @@
|
|||
"slicing_tolerance":
|
||||
{
|
||||
"label": "Slicing Tolerance",
|
||||
"description": "How to slice layers with diagonal surfaces. The areas of a layer can be generated based on where the middle of the layer intersects the surface (Middle). Alternatively each layer can have the areas which fall inside of the volume throughout the height of the layer (Exclusive) or a layer has the areas which fall inside anywhere within the layer (Inclusive). Exclusive retains the most details, Inclusive makes for the best fit and Middle takes the least time to process.",
|
||||
"description": "Vertical tolerance in the sliced layers. The contours of a layer are normally generated by taking cross sections through the middle of each layer's thickness (Middle). Alternatively each layer can have the areas which fall inside of the volume throughout the entire thickness of the layer (Exclusive) or a layer has the areas which fall inside anywhere within the layer (Inclusive). Inclusive retains the most details, Exclusive makes for the best fit and Middle stays closest to the original surface.",
|
||||
"type": "enum",
|
||||
"options":
|
||||
{
|
||||
|
|
|
@ -81,9 +81,6 @@
|
|||
|
||||
"layer_height": {"maximum_value": "(0.8 * min(extruderValues('machine_nozzle_size')))" },
|
||||
"layer_height_0": {"maximum_value": "(0.8 * min(extruderValues('machine_nozzle_size')))" },
|
||||
"line_width": {"value": "(machine_nozzle_size + 0.2)" },
|
||||
"wall_line_width_0": {"value": "(machine_nozzle_size)" },
|
||||
"infill_line_width": {"value": "(line_width)" },
|
||||
"initial_layer_line_width_factor": {"value": 110 },
|
||||
|
||||
"wall_thickness": {"value": "(line_width * 3) if infill_sparse_density < 95 else line_width" },
|
||||
|
@ -111,17 +108,24 @@
|
|||
"infill_pattern": {"value": "'lines'"},
|
||||
"infill_before_walls": {"value": true},
|
||||
|
||||
"material_print_temperature_layer_0": {"value": "material_print_temperature"},
|
||||
"material_initial_print_temperature": {"value": "material_print_temperature",
|
||||
"maximum_value_warning": "material_print_temperature + 15"},
|
||||
"material_final_print_temperature": {"value": "material_print_temperature"},
|
||||
"material_bed_temperature_layer_0": {"value": "material_bed_temperature"},
|
||||
"material_flow_layer_0": {"value": "material_flow"},
|
||||
"retraction_enable": {"value": true },
|
||||
"retract_at_layer_change": {"value": false },
|
||||
"retraction_min_travel": {"value": "(round(line_width * 10))"},
|
||||
"switch_extruder_retraction_speeds": {"value": "(retraction_speed)"},
|
||||
"switch_extruder_prime_speed": {"value": "(retraction_prime_speed)"},
|
||||
"default_material_print_temperature": {"maximum_value": "401" },
|
||||
"material_print_temperature": {"maximum_value": "401" },
|
||||
"material_print_temperature_layer_0": {"value": "material_print_temperature",
|
||||
"maximum_value": "401" },
|
||||
"material_initial_print_temperature": {"value": "material_print_temperature",
|
||||
"maximum_value_warning": "material_print_temperature + 15",
|
||||
"maximum_value": "401" },
|
||||
"material_initial_print_temperature": {"maximum_value": "401" },
|
||||
"material_final_print_temperature": {"value": "material_print_temperature",
|
||||
"maximum_value": "401" },
|
||||
"material_break_preparation_temperature": {"maximum_value": "401" },
|
||||
"material_bed_temperature_layer_0": {"value": "material_bed_temperature"},
|
||||
"material_flow_layer_0": {"value": "material_flow"},
|
||||
"retraction_enable": {"value": true },
|
||||
"retract_at_layer_change": {"value": false },
|
||||
"retraction_min_travel": {"value": "(round(line_width * 10))"},
|
||||
"switch_extruder_retraction_speeds": {"value": "(retraction_speed)"},
|
||||
"switch_extruder_prime_speed": {"value": "(retraction_prime_speed)"},
|
||||
|
||||
"speed_print": {"value": "50"},
|
||||
"speed_infill": {"value": "speed_print"},
|
||||
|
|
15
resources/extruders/beamup_l_extruder_0.def.json
Normal file
15
resources/extruders/beamup_l_extruder_0.def.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "beamup_l",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"extruder_nr": { "default_value": 0 },
|
||||
"machine_nozzle_size": { "default_value": 0.8 },
|
||||
"material_diameter": { "default_value": 1.75 }
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"machine_extruder_start_code": {
|
||||
"default_value": "\n;changing to tool1\nM83\nM109 T0 S{material_print_temperature}\nM114\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E-{switch_extruder_retraction_amount} F2400\nG1 Y40 F3000\nG1 X10 F12000\n\n"
|
||||
"default_value": "\n;changing to tool1\nT0\nM83\nM109 T0 S{material_print_temperature}\nM114\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E-{switch_extruder_retraction_amount} F2400\nG1 Y40 F3000\nG1 X10 F12000\n\n"
|
||||
},
|
||||
"machine_extruder_end_code": {
|
||||
"default_value": "\nG1 X10 Y40 F12000\nG1 X-25 F12000\nM109 T0 R{material_standby_temperature}\nG1 Y20 F3000\n; ending tool1\n\n"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"machine_extruder_start_code": {
|
||||
"default_value": "\n;changing to tool2\nM83\nM109 T1 S{material_print_temperature}\nM114\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E-{switch_extruder_retraction_amount} F2400\nG1 Y40 F3000\nG1 X10 F12000\n\n"
|
||||
"default_value": "\n;changing to tool2\nT1\nM83\nM109 T1 S{material_print_temperature}\nM114\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E{switch_extruder_retraction_amount} F300\nG1 E-{switch_extruder_retraction_amount} F2400\nG1 Y40 F3000\nG1 X10 F12000\n\n"
|
||||
},
|
||||
"machine_extruder_end_code": {
|
||||
"default_value": "\nG1 X10 Y40 F12000\nG1 X-25 F12000\nM109 T1 R{material_standby_temperature}\nG1 Y20 F3000\n; ending tool2\n\n"
|
||||
|
|
BIN
resources/meshes/beamup_l.3mf
Normal file
BIN
resources/meshes/beamup_l.3mf
Normal file
Binary file not shown.
|
@ -90,7 +90,7 @@ UM.PreferencesPage
|
|||
UM.Preferences.resetPreference("view/show_overhang");
|
||||
showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
|
||||
UM.Preferences.resetPreference("view/show_xray_warning");
|
||||
showXrayErrorCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_warning"))
|
||||
showXrayErrorCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_xray_warning"))
|
||||
UM.Preferences.resetPreference("view/center_on_select");
|
||||
centerOnSelectCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
|
||||
UM.Preferences.resetPreference("view/invert_zoom");
|
||||
|
@ -336,7 +336,7 @@ UM.PreferencesPage
|
|||
id: showOverhangCheckbox
|
||||
|
||||
checked: boolCheck(UM.Preferences.getValue("view/show_overhang"))
|
||||
onClicked: UM.Preferences.setValue("view/show_overhang", checked)
|
||||
onClicked: UM.Preferences.setValue("view/show_overhang", checked)
|
||||
|
||||
text: catalog.i18nc("@option:check", "Display overhang");
|
||||
}
|
||||
|
|
40
resources/quality/beamup_l/beamup_l_coarse.inst.cfg
Normal file
40
resources/quality/beamup_l/beamup_l_coarse.inst.cfg
Normal file
|
@ -0,0 +1,40 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = BeamUp L Coarse
|
||||
definition = beamup_l
|
||||
|
||||
[metadata]
|
||||
setting_version = 15
|
||||
type = quality
|
||||
quality_type = coarse
|
||||
weight = -3
|
||||
material = generic_pla
|
||||
|
||||
[values]
|
||||
layer_height = 0.30
|
||||
adhesion_type = brim
|
||||
brim_line_count = 8
|
||||
infill_before_walls = False
|
||||
initial_layer_line_width_factor = 120.0
|
||||
material_print_temperature = 215
|
||||
material_print_temperature_layer_0 = 235
|
||||
retraction_amount = 2
|
||||
retraction_speed = 30
|
||||
speed_infill = 55
|
||||
speed_layer_0 = 25
|
||||
speed_print = 55
|
||||
speed_support_interface = 55
|
||||
speed_topbottom = 55
|
||||
speed_wall_0 = 45
|
||||
speed_wall_x = 55
|
||||
support_enable = True
|
||||
support_angle = 60
|
||||
support_infill_rate = 20
|
||||
support_interface_enable = True
|
||||
support_interface_height = 0.60
|
||||
support_interface_pattern = zigzag
|
||||
support_interface_skip_height = 0.30
|
||||
support_offset = 0.8
|
||||
support_z_distance = 0.4
|
||||
wall_thickness = 1.6
|
||||
zig_zaggify_infill = True
|
40
resources/quality/beamup_l/beamup_l_draft.inst.cfg
Normal file
40
resources/quality/beamup_l/beamup_l_draft.inst.cfg
Normal file
|
@ -0,0 +1,40 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = BeamUp L Draft
|
||||
definition = beamup_l
|
||||
|
||||
[metadata]
|
||||
setting_version = 15
|
||||
type = quality
|
||||
quality_type = draft
|
||||
weight = -2
|
||||
material = generic_pla
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
adhesion_type = brim
|
||||
brim_line_count = 8
|
||||
infill_before_walls = False
|
||||
initial_layer_line_width_factor = 120.0
|
||||
material_print_temperature = 210
|
||||
material_print_temperature_layer_0 = 235
|
||||
retraction_amount = 2
|
||||
retraction_speed = 30
|
||||
speed_infill = 55
|
||||
speed_layer_0 = 25
|
||||
speed_print = 55
|
||||
speed_support_interface = 55
|
||||
speed_topbottom = 55
|
||||
speed_wall_0 = 45
|
||||
speed_wall_x = 55
|
||||
support_enable = True
|
||||
support_angle = 60
|
||||
support_infill_rate = 20
|
||||
support_interface_enable = True
|
||||
support_interface_height = 0.60
|
||||
support_interface_pattern = zigzag
|
||||
support_interface_skip_height = 0.20
|
||||
support_offset = 0.8
|
||||
support_z_distance = 0.3
|
||||
wall_thickness = 1.6
|
||||
zig_zaggify_infill = True
|
40
resources/quality/beamup_l/beamup_l_extra_fine.inst.cfg
Normal file
40
resources/quality/beamup_l/beamup_l_extra_fine.inst.cfg
Normal file
|
@ -0,0 +1,40 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = BeamUp L Extra Fine
|
||||
definition = beamup_l
|
||||
|
||||
[metadata]
|
||||
setting_version = 15
|
||||
type = quality
|
||||
quality_type = high
|
||||
weight = 1
|
||||
material = generic_pla
|
||||
|
||||
[values]
|
||||
layer_height = 0.06
|
||||
adhesion_type = brim
|
||||
brim_line_count = 8
|
||||
infill_before_walls = False
|
||||
initial_layer_line_width_factor = 120.0
|
||||
material_print_temperature = 195
|
||||
material_print_temperature_layer_0 = 235
|
||||
retraction_amount = 2
|
||||
retraction_speed = 30
|
||||
speed_infill = 45
|
||||
speed_layer_0 = 25
|
||||
speed_print = 45
|
||||
speed_support_interface = 45
|
||||
speed_topbottom = 45
|
||||
speed_wall_0 = 35
|
||||
speed_wall_x = 45
|
||||
support_enable = True
|
||||
support_angle = 60
|
||||
support_infill_rate = 20
|
||||
support_interface_enable = True
|
||||
support_interface_height = 0.30
|
||||
support_interface_pattern = zigzag
|
||||
support_interface_skip_height = 0.06
|
||||
support_offset = 0.8
|
||||
support_z_distance = 0.12
|
||||
wall_thickness = 1.6
|
||||
zig_zaggify_infill = True
|
40
resources/quality/beamup_l/beamup_l_fine.inst.cfg
Normal file
40
resources/quality/beamup_l/beamup_l_fine.inst.cfg
Normal file
|
@ -0,0 +1,40 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = BeamUp L Fine
|
||||
definition = beamup_l
|
||||
|
||||
[metadata]
|
||||
setting_version = 15
|
||||
type = quality
|
||||
quality_type = normal
|
||||
weight = 0
|
||||
material = generic_pla
|
||||
|
||||
[values]
|
||||
layer_height = 0.1
|
||||
adhesion_type = brim
|
||||
brim_line_count = 8
|
||||
infill_before_walls = False
|
||||
initial_layer_line_width_factor = 120.0
|
||||
material_print_temperature = 200
|
||||
material_print_temperature_layer_0 = 235
|
||||
retraction_amount = 2
|
||||
retraction_speed = 30
|
||||
speed_infill = 50
|
||||
speed_layer_0 = 25
|
||||
speed_print = 50
|
||||
speed_support_interface = 50
|
||||
speed_topbottom = 50
|
||||
speed_wall_0 = 40
|
||||
speed_wall_x = 50
|
||||
support_enable = True
|
||||
support_angle = 60
|
||||
support_infill_rate = 20
|
||||
support_interface_enable = True
|
||||
support_interface_height = 0.30
|
||||
support_interface_pattern = zigzag
|
||||
support_interface_skip_height = 0.10
|
||||
support_offset = 0.8
|
||||
support_z_distance = 0.2
|
||||
wall_thickness = 1.6
|
||||
zig_zaggify_infill = True
|
40
resources/quality/beamup_l/beamup_l_normal.inst.cfg
Normal file
40
resources/quality/beamup_l/beamup_l_normal.inst.cfg
Normal file
|
@ -0,0 +1,40 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = BeamUp L Normal
|
||||
definition = beamup_l
|
||||
|
||||
[metadata]
|
||||
setting_version = 15
|
||||
type = quality
|
||||
quality_type = fast
|
||||
weight = -1
|
||||
material = generic_pla
|
||||
|
||||
[values]
|
||||
layer_height = 0.15
|
||||
adhesion_type = brim
|
||||
brim_line_count = 8
|
||||
infill_before_walls = False
|
||||
initial_layer_line_width_factor = 120.0
|
||||
material_print_temperature = 205
|
||||
material_print_temperature_layer_0 = 235
|
||||
retraction_amount = 2
|
||||
retraction_speed = 30
|
||||
speed_infill = 50
|
||||
speed_layer_0 = 25
|
||||
speed_print = 50
|
||||
speed_support_interface = 50
|
||||
speed_topbottom = 50
|
||||
speed_wall_0 = 40
|
||||
speed_wall_x = 50
|
||||
support_enable = True
|
||||
support_angle = 60
|
||||
support_infill_rate = 20
|
||||
support_interface_enable = True
|
||||
support_interface_height = 0.45
|
||||
support_interface_pattern = zigzag
|
||||
support_interface_skip_height = 0.15
|
||||
support_offset = 0.8
|
||||
support_z_distance = 0.25
|
||||
wall_thickness = 1.6
|
||||
zig_zaggify_infill = True
|
|
@ -32,7 +32,6 @@ material_standby_temperature = 100
|
|||
multiple_mesh_overlap = 0
|
||||
prime_tower_enable = True
|
||||
prime_tower_wipe_enabled = True
|
||||
retraction_combing = off
|
||||
retraction_extrusion_window = 1
|
||||
retraction_hop = 0.2
|
||||
retraction_hop_enabled = False
|
||||
|
|
|
@ -32,7 +32,6 @@ material_standby_temperature = 100
|
|||
multiple_mesh_overlap = 0
|
||||
prime_tower_enable = True
|
||||
prime_tower_wipe_enabled = True
|
||||
retraction_combing = off
|
||||
retraction_extrusion_window = 1
|
||||
retraction_hop = 0.2
|
||||
retraction_hop_enabled = False
|
||||
|
|
|
@ -34,7 +34,6 @@ material_standby_temperature = 100
|
|||
multiple_mesh_overlap = 0
|
||||
prime_tower_enable = True
|
||||
prime_tower_wipe_enabled = True
|
||||
retraction_combing = off
|
||||
retraction_extrusion_window = 1
|
||||
retraction_hop = 0.2
|
||||
retraction_hop_enabled = False
|
||||
|
|
|
@ -33,7 +33,6 @@ material_standby_temperature = 100
|
|||
multiple_mesh_overlap = 0
|
||||
prime_tower_enable = True
|
||||
prime_tower_wipe_enabled = True
|
||||
retraction_combing = off
|
||||
retraction_extrusion_window = 1
|
||||
retraction_hop = 0.2
|
||||
retraction_hop_enabled = False
|
||||
|
|
|
@ -23,7 +23,6 @@ material_print_temperature = =default_material_print_temperature - 10
|
|||
material_print_temperature_layer_0 = =material_print_temperature
|
||||
material_standby_temperature = 100
|
||||
prime_tower_enable = True
|
||||
retraction_combing = off
|
||||
retraction_hop = 0.1
|
||||
retraction_hop_enabled = False
|
||||
skin_overlap = 0
|
||||
|
|
|
@ -24,7 +24,6 @@ material_print_temperature = =default_material_print_temperature - 5
|
|||
material_print_temperature_layer_0 = =material_print_temperature
|
||||
material_standby_temperature = 100
|
||||
prime_tower_enable = True
|
||||
retraction_combing = off
|
||||
retraction_hop = 0.1
|
||||
retraction_hop_enabled = False
|
||||
skin_overlap = 0
|
||||
|
|
|
@ -24,7 +24,6 @@ material_print_temperature = =default_material_print_temperature - 7
|
|||
material_print_temperature_layer_0 = =material_print_temperature
|
||||
material_standby_temperature = 100
|
||||
prime_tower_enable = True
|
||||
retraction_combing = off
|
||||
retraction_hop = 0.1
|
||||
retraction_hop_enabled = False
|
||||
skin_overlap = 0
|
||||
|
|
|
@ -252,7 +252,7 @@ class TestCalculateExtraZClearance:
|
|||
return properties.get(args[2])
|
||||
|
||||
def test_noContainerStack(self, build_volume: BuildVolume):
|
||||
assert build_volume._calculateExtraZClearance([]) is 0
|
||||
assert build_volume._calculateExtraZClearance([]) == 0
|
||||
|
||||
def test_withRetractionHop(self, build_volume: BuildVolume):
|
||||
mocked_global_stack = MagicMock(name="mocked_global_stack")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue