This commit is contained in:
fieldOfView 2016-07-26 18:55:59 +02:00
commit 35107742d6
4 changed files with 122 additions and 83 deletions

View file

@ -51,6 +51,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
return None return None
hull = self._compute2DConvexHull() hull = self._compute2DConvexHull()
if self._global_stack and self._node: if self._global_stack and self._node:
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"): if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32))) hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32)))
@ -72,7 +73,9 @@ class ConvexHullDecorator(SceneNodeDecorator):
if self._global_stack: if self._global_stack:
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"): if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
return self._compute2DConvexHeadMin() head_with_fans = self._compute2DConvexHeadMin()
head_with_fans_with_adhesion_margin = self._add2DAdhesionMargin(head_with_fans)
return head_with_fans_with_adhesion_margin
return None return None
## Get convex hull of the node ## Get convex hull of the node
@ -84,6 +87,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
if self._global_stack: if self._global_stack:
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"): if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
# Printing one at a time and it's not an object in a group # Printing one at a time and it's not an object in a group
return self._compute2DConvexHull() return self._compute2DConvexHull()
return None return None
@ -99,11 +103,6 @@ class ConvexHullDecorator(SceneNodeDecorator):
convex_hull = self.getConvexHull() convex_hull = self.getConvexHull()
if self._convex_hull_node: if self._convex_hull_node:
# Check if convex hull has changed
if (self._convex_hull_node.getHull() == convex_hull and
self._convex_hull_node.getThickness() == self._raft_thickness):
return
self._convex_hull_node.setParent(None) self._convex_hull_node.setParent(None)
hull_node = ConvexHullNode.ConvexHullNode(self._node, convex_hull, self._raft_thickness, root) hull_node = ConvexHullNode.ConvexHullNode(self._node, convex_hull, self._raft_thickness, root)
self._convex_hull_node = hull_node self._convex_hull_node = hull_node
@ -219,6 +218,44 @@ class ConvexHullDecorator(SceneNodeDecorator):
min_head_hull = self._compute2DConvexHull().getMinkowskiHull(head_and_fans) min_head_hull = self._compute2DConvexHull().getMinkowskiHull(head_and_fans)
return min_head_hull return min_head_hull
## Compensate given 2D polygon with adhesion margin
# \return 2D polygon with added margin
def _add2DAdhesionMargin(self, poly):
# Compensate for raft/skirt/brim
# Add extra margin depending on adhesion type
adhesion_type = self._global_stack.getProperty("adhesion_type", "value")
extra_margin = 0
machine_head_coords = numpy.array(
self._global_stack.getProperty("machine_head_with_fans_polygon", "value"),
numpy.float32)
head_y_size = abs(machine_head_coords).min() # safe margin to take off in all directions
if adhesion_type == "raft":
extra_margin = max(0, self._global_stack.getProperty("raft_margin", "value") - head_y_size)
elif adhesion_type == "brim":
extra_margin = max(0, self._global_stack.getProperty("brim_width", "value") - head_y_size)
elif adhesion_type == "skirt":
extra_margin = max(
0, self._global_stack.getProperty("skirt_gap", "value") +
self._global_stack.getProperty("skirt_line_count", "value") * self._global_stack.getProperty("skirt_brim_line_width", "value") -
head_y_size)
# adjust head_and_fans with extra margin
if extra_margin > 0:
# In Cura 2.2+, there is a function to create this circle-like polygon.
extra_margin_polygon = Polygon(numpy.array([
[-extra_margin, 0],
[-extra_margin * 0.707, extra_margin * 0.707],
[0, extra_margin],
[extra_margin * 0.707, extra_margin * 0.707],
[extra_margin, 0],
[extra_margin * 0.707, -extra_margin * 0.707],
[0, -extra_margin],
[-extra_margin * 0.707, -extra_margin * 0.707]
], numpy.float32))
poly = poly.getMinkowskiHull(extra_margin_polygon)
return poly
def _roundHull(self, convex_hull): def _roundHull(self, convex_hull):
return convex_hull.getMinkowskiHull(Polygon(numpy.array([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32))) return convex_hull.getMinkowskiHull(Polygon(numpy.array([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32)))
@ -249,4 +286,5 @@ class ConvexHullDecorator(SceneNodeDecorator):
_affected_settings = [ _affected_settings = [
"adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers",
"raft_surface_thickness", "raft_airgap", "print_sequence"] "raft_surface_thickness", "raft_airgap", "print_sequence",
"skirt_gap", "skirt_line_count", "skirt_brim_line_width", "skirt_distance"]

View file

@ -28,15 +28,16 @@ class ConvexHullNode(SceneNode):
# The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting. # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
self._mesh_height = 0.1 self._mesh_height = 0.1
self._thickness = thickness
# The node this mesh is "watching" # The node this mesh is "watching"
self._node = node self._node = node
self._convex_hull_head_mesh = None
self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged) self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged)
self._onNodeDecoratorsChanged(self._node) self._onNodeDecoratorsChanged(self._node)
self._convex_hull_head_mesh = None
self._hull = hull self._hull = hull
self._thickness = thickness
if self._hull: if self._hull:
hull_mesh_builder = MeshBuilder() hull_mesh_builder = MeshBuilder()
@ -46,11 +47,6 @@ class ConvexHullNode(SceneNode):
hull_mesh = hull_mesh_builder.build() hull_mesh = hull_mesh_builder.build()
self.setMeshData(hull_mesh) self.setMeshData(hull_mesh)
convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head:
convex_hull_head_builder = MeshBuilder()
convex_hull_head_builder.addConvexPolygon(convex_hull_head.getPoints(), self._mesh_height-thickness)
self._convex_hull_head_mesh = convex_hull_head_builder.build()
def getHull(self): def getHull(self):
return self._hull return self._hull
@ -78,6 +74,12 @@ class ConvexHullNode(SceneNode):
def _onNodeDecoratorsChanged(self, node): def _onNodeDecoratorsChanged(self, node):
self._color = Color(35, 35, 35, 0.5) self._color = Color(35, 35, 35, 0.5)
convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head:
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: if not node:
return return

View file

@ -64,9 +64,8 @@ class MachineManager(QObject):
# Make sure _active_container_stack is properly initiated # Make sure _active_container_stack is properly initiated
ExtruderManager.getInstance().setActiveExtruderIndex(0) ExtruderManager.getInstance().setActiveExtruderIndex(0)
self._auto_change_material_hotend_flood_window = 10 # The minimum number of seconds between asking if the material or hotend on the machine should be used self._auto_materials_changed = {}
self._auto_change_material_hotend_flood_time = 0 # The last timestamp (in seconds) when the user was asked about changing the material or hotend to whatis loaded on the machine self._auto_hotends_changed = {}
self._auto_change_material_hotend_flood_last_choice = None # The last choice that was made, so we can apply that choice again
globalContainerChanged = pyqtSignal() globalContainerChanged = pyqtSignal()
activeMaterialChanged = pyqtSignal() activeMaterialChanged = pyqtSignal()
@ -104,48 +103,46 @@ class MachineManager(QObject):
if not self._global_container_stack: if not self._global_container_stack:
return return
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = self._global_container_stack.getBottom().getId(), name = hotend_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type="variant", definition=self._global_container_stack.getBottom().getId(), name=hotend_id)
if containers: if containers: # New material ID is known
extruder_manager = ExtruderManager.getInstance() extruder_manager = ExtruderManager.getInstance()
old_index = extruder_manager.activeExtruderIndex extruders = list(extruder_manager.getMachineExtruders(self.activeMachineId))
if old_index != index: matching_extruder = None
extruder_manager.setActiveExtruderIndex(index) for extruder in extruders:
else: if str(index) == extruder.getMetaDataEntry("position"):
old_index = None matching_extruder = extruder
break
if matching_extruder and matching_extruder.findContainer({"type": "variant"}).getName() != hotend_id:
# Save the material that needs to be changed. Multiple changes will be handled by the callback.
self._auto_hotends_changed[str(index)] = containers[0].getId()
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"),
catalog.i18nc("@label",
"Do you want to change the materials and hotends to match the material in your printer?"),
catalog.i18nc("@label",
"The materials and / or hotends on your printer were changed. For best results always slice for the materials . hotends that are inserted in your printer."),
buttons=QMessageBox.Yes + QMessageBox.No,
icon=QMessageBox.Question,
callback=self._materialHotendChangedCallback)
if self.activeVariantId != containers[0].getId():
if time.time() - self._auto_change_material_hotend_flood_time > self._auto_change_material_hotend_flood_window:
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the hotend to match the hotend in your printer?"),
catalog.i18nc("@label", "The hotend on your printer was changed. For best results always slice for the hotend that is inserted in your printer."),
buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._hotendChangedDialogCallback, callback_arguments = [index, containers[0].getId()])
else:
self._hotendChangedDialogCallback(self._auto_change_material_hotend_flood_last_choice, index, containers[0].getId())
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
else: else:
Logger.log("w", "No variant found for printer definition %s with id %s" % (self._global_container_stack.getBottom().getId(), hotend_id)) Logger.log("w", "No variant found for printer definition %s with id %s" % (self._global_container_stack.getBottom().getId(), hotend_id))
def _hotendChangedDialogCallback(self, button, index, hotend_id): def _autoUpdateHotends(self):
self._auto_change_material_hotend_flood_time = time.time()
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))
extruder_manager = ExtruderManager.getInstance() extruder_manager = ExtruderManager.getInstance()
old_index = extruder_manager.activeExtruderIndex for position in self._auto_hotends_changed:
if old_index != index: hotend_id = self._auto_hotends_changed[position]
extruder_manager.setActiveExtruderIndex(index) old_index = extruder_manager.activeExtruderIndex
else:
old_index = None
self.setActiveVariant(hotend_id) if old_index != int(position):
extruder_manager.setActiveExtruderIndex(int(position))
else:
old_index = None
Logger.log("d", "Setting hotend variant of hotend %s to %s" % (position, hotend_id))
self.setActiveVariant(hotend_id)
if old_index is not None: if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index) extruder_manager.setActiveExtruderIndex(old_index)
def _onMaterialIdChanged(self, index, material_id): def _onMaterialIdChanged(self, index, material_id):
if not self._global_container_stack: if not self._global_container_stack:
@ -154,50 +151,50 @@ class MachineManager(QObject):
definition_id = "fdmprinter" definition_id = "fdmprinter"
if self._global_container_stack.getMetaDataEntry("has_machine_materials", False): if self._global_container_stack.getMetaDataEntry("has_machine_materials", False):
definition_id = self._global_container_stack.getBottom().getId() definition_id = self._global_container_stack.getBottom().getId()
extruder_manager = ExtruderManager.getInstance()
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition_id, GUID = material_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition_id, GUID = material_id)
if containers: if containers: # New material ID is known
extruder_manager = ExtruderManager.getInstance() extruders = list(extruder_manager.getMachineExtruders(self.activeMachineId))
old_index = extruder_manager.activeExtruderIndex matching_extruder = None
if old_index != index: for extruder in extruders:
extruder_manager.setActiveExtruderIndex(index) if str(index) == extruder.getMetaDataEntry("position"):
else: matching_extruder = extruder
old_index = None break
if self.activeMaterialId != containers[0].getId(): if matching_extruder and matching_extruder.findContainer({"type":"material"}).getMetaDataEntry("GUID") != material_id:
if time.time() - self._auto_change_material_hotend_flood_time > self._auto_change_material_hotend_flood_window: # Save the material that needs to be changed. Multiple changes will be handled by the callback.
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the material to match the material in your printer?"), self._auto_materials_changed[str(index)] = containers[0].getId()
catalog.i18nc("@label", "The material on your printer was changed. For best results always slice for the material that is inserted in your printer."), Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the materials and hotends to match the material in your printer?"),
buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialIdChangedDialogCallback, callback_arguments = [index, containers[0].getId()]) catalog.i18nc("@label", "The materials and / or hotends on your printer were changed. For best results always slice for the materials . hotends that are inserted in your printer."),
else: buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialHotendChangedCallback)
self._materialIdChangedDialogCallback(self._auto_change_material_hotend_flood_last_choice, index, containers[0].getId())
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
else: else:
Logger.log("w", "No material definition found for printer definition %s and GUID %s" % (definition_id, material_id)) Logger.log("w", "No material definition found for printer definition %s and GUID %s" % (definition_id, material_id))
def _materialIdChangedDialogCallback(self, button, index, material_id): def _materialHotendChangedCallback(self, button):
self._auto_change_material_hotend_flood_time = time.time()
self._auto_change_material_hotend_flood_last_choice = button
if button == QMessageBox.No: if button == QMessageBox.No:
self._auto_materials_changed = {}
self._auto_hotends_changed = {}
return return
self._autoUpdateMaterials()
self._autoUpdateHotends()
Logger.log("d", "Setting material of hotend %d to %s" % (index, material_id)) def _autoUpdateMaterials(self):
extruder_manager = ExtruderManager.getInstance() extruder_manager = ExtruderManager.getInstance()
old_index = extruder_manager.activeExtruderIndex for position in self._auto_materials_changed:
if old_index != index: material_id = self._auto_materials_changed[position]
extruder_manager.setActiveExtruderIndex(index) old_index = extruder_manager.activeExtruderIndex
else:
old_index = None
self.setActiveMaterial(material_id) if old_index != int(position):
extruder_manager.setActiveExtruderIndex(int(position))
else:
old_index = None
if old_index is not None: Logger.log("d", "Setting material of hotend %s to %s" % (position, material_id))
extruder_manager.setActiveExtruderIndex(old_index) self.setActiveMaterial(material_id)
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
def _onGlobalPropertyChanged(self, key, property_name): def _onGlobalPropertyChanged(self, key, property_name):
if property_name == "value": if property_name == "value":

View file

@ -80,6 +80,7 @@ class GCodeWriter(MeshWriter):
flat_quality_id = machine_manager.duplicateContainer(container_with_profile.getId()) flat_quality_id = machine_manager.duplicateContainer(container_with_profile.getId())
flat_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = flat_quality_id)[0] flat_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = flat_quality_id)[0]
flat_quality._dirty = False
user_settings = stack.getTop() user_settings = stack.getTop()
# We don't want to send out any signals, so disconnect them. # We don't want to send out any signals, so disconnect them.
@ -97,11 +98,12 @@ class GCodeWriter(MeshWriter):
flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId()) flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId())
flat_extruder_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=flat_extruder_quality_id)[0] flat_extruder_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=flat_extruder_quality_id)[0]
flat_extruder_quality._dirty = False
extruder_user_settings = extruder.getTop() extruder_user_settings = extruder.getTop()
# We don't want to send out any signals, so disconnect them. # We don't want to send out any signals, so disconnect them.
flat_extruder_quality.propertyChanged.disconnectAll() flat_extruder_quality.propertyChanged.disconnectAll()
for key in extruder_user_settings.getAllKeys(): for key in extruder_user_settings.getAllKeys():
flat_extruder_quality.setProperty(key, "value", extruder_user_settings.getProperty(key, "value")) flat_extruder_quality.setProperty(key, "value", extruder_user_settings.getProperty(key, "value"))