|
@@ -3,6 +3,7 @@
|
|
|
|
|
|
from cura.Settings.ExtruderManager import ExtruderManager
|
|
|
from UM.i18n import i18nCatalog
|
|
|
+from UM.Scene.Platform import Platform
|
|
|
from UM.Scene.SceneNode import SceneNode
|
|
|
from UM.Application import Application
|
|
|
from UM.Resources import Resources
|
|
@@ -18,12 +19,32 @@ from UM.View.GL.OpenGL import OpenGL
|
|
|
catalog = i18nCatalog("cura")
|
|
|
|
|
|
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.
|
|
|
class BuildVolume(SceneNode):
|
|
|
VolumeOutlineColor = Color(12, 169, 227, 255)
|
|
@@ -46,6 +67,11 @@ class BuildVolume(SceneNode):
|
|
|
self.setCalculateBoundingBox(False)
|
|
|
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
|
|
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
|
|
|
self._onGlobalContainerStackChanged()
|
|
@@ -77,6 +103,9 @@ class BuildVolume(SceneNode):
|
|
|
renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
|
|
|
if self._disallowed_area_mesh:
|
|
|
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
|
|
|
|
|
|
## Recalculates the build volume & disallowed areas.
|
|
@@ -93,6 +122,7 @@ class BuildVolume(SceneNode):
|
|
|
|
|
|
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(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)
|
|
@@ -117,11 +147,23 @@ class BuildVolume(SceneNode):
|
|
|
Vector(max_w, min_h - 0.2, max_d),
|
|
|
Vector(min_w, min_h - 0.2, max_d)
|
|
|
)
|
|
|
+
|
|
|
for n in range(0, 6):
|
|
|
v = mb.getVertex(n)
|
|
|
mb.setVertexUVCoordinates(n, v[0], v[2])
|
|
|
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_size = 0
|
|
|
if self._disallowed_areas:
|
|
@@ -177,6 +219,21 @@ class BuildVolume(SceneNode):
|
|
|
" \"Print Sequence\" setting to prevent the gantry from colliding"
|
|
|
" 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):
|
|
|
if self._active_container_stack:
|
|
|
self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
|
|
@@ -195,6 +252,7 @@ class BuildVolume(SceneNode):
|
|
|
self._depth = self._active_container_stack.getProperty("machine_depth", "value")
|
|
|
|
|
|
self._updateDisallowedAreas()
|
|
|
+ self._updateRaftThickness()
|
|
|
|
|
|
self.rebuild()
|
|
|
|
|
@@ -202,32 +260,40 @@ class BuildVolume(SceneNode):
|
|
|
if property_name != "value":
|
|
|
return
|
|
|
|
|
|
+ rebuild_me = False
|
|
|
if setting_key == "print_sequence":
|
|
|
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time":
|
|
|
self._height = self._active_container_stack.getProperty("gantry_height", "value")
|
|
|
self._buildVolumeMessage()
|
|
|
else:
|
|
|
self._height = self._active_container_stack.getProperty("machine_height", "value")
|
|
|
- self.rebuild()
|
|
|
+ rebuild_me = True
|
|
|
+
|
|
|
if setting_key in self._skirt_settings:
|
|
|
self._updateDisallowedAreas()
|
|
|
+ rebuild_me = True
|
|
|
+
|
|
|
+ if setting_key in self._raft_settings:
|
|
|
+ self._updateRaftThickness()
|
|
|
+ rebuild_me = True
|
|
|
+
|
|
|
+ if rebuild_me:
|
|
|
self.rebuild()
|
|
|
|
|
|
def _updateDisallowedAreas(self):
|
|
|
if not self._active_container_stack:
|
|
|
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 = []
|
|
|
|
|
|
# Add extruder prime locations as disallowed areas.
|
|
|
# Probably needs some rework after coordinate system change.
|
|
|
- machine_definition = self._active_container_stack.getBottom()
|
|
|
- current_machine_id = machine_definition.getId()
|
|
|
extruder_manager = ExtruderManager.getInstance()
|
|
|
- extruders = extruder_manager.getMachineExtruders(current_machine_id)
|
|
|
- machine_width = machine_definition.getProperty("machine_width", "value")
|
|
|
- machine_depth = machine_definition.getProperty("machine_depth", "value")
|
|
|
+ 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")
|
|
@@ -249,16 +315,7 @@ class BuildVolume(SceneNode):
|
|
|
# Extend every area already in the disallowed_areas with the skirt size.
|
|
|
for area in disallowed_areas:
|
|
|
poly = Polygon(numpy.array(area, numpy.float32))
|
|
|
- poly = poly.getMinkowskiHull(Polygon(numpy.array([
|
|
|
- [-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)))
|
|
|
+ poly = poly.getMinkowskiHull(Polygon(approximatedCircleVertices(skirt_size)))
|
|
|
|
|
|
areas.append(poly)
|
|
|
|
|
@@ -297,7 +354,7 @@ class BuildVolume(SceneNode):
|
|
|
|
|
|
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):
|
|
|
skirt_size = 0.0
|
|
|
|
|
@@ -323,3 +380,4 @@ class BuildVolume(SceneNode):
|
|
|
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"]
|
|
|
+ _raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
|