Do boundary checks on nodes for which the boundary check is unknown

Just before deciding whether to drop down the node on the build plate.

Contributes to issue CURA-4797.
This commit is contained in:
Ghostkeeper 2018-01-23 11:21:32 +01:00
parent cf556ccf8f
commit 27e441ecd9
No known key found for this signature in database
GPG Key ID: 5252B696FB5E7C7A
2 changed files with 48 additions and 47 deletions

View File

@ -1,8 +1,7 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Scene.Platform import Platform from UM.Scene.Platform import Platform
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
@ -194,52 +193,51 @@ class BuildVolume(SceneNode):
return True return True
## For every sliceable node, update node._outside_buildarea ## For every sliceable node, update node._outside_buildarea.
def updateAllBoundaryChecks(self):
self.updateNodeBoundaryCheck(Application.getInstance().getController().getScene().getRoot())
## For a single node, update _outside_buildarea.
# #
def updateNodeBoundaryCheck(self): # If the node is a group node, the child nodes will also get updated.
root = Application.getInstance().getController().getScene().getRoot() # \param node The node to update the boundary checks of.
nodes = list(BreadthFirstIterator(root)) def updateNodeBoundaryCheck(self, node: SceneNode):
group_nodes = [] if not node.callDecoration("isSliceable") and not node.callDecoration("isGroup"):
for child in node.getChildren(): #Still update the children! For instance, the root is not sliceable.
self.updateNodeBoundaryCheck(child)
return #Don't compute for non-sliceable nodes.
build_volume_bounding_box = self.getBoundingBox() #Mark the node as outside the build volume if the bounding box test fails.
if build_volume_bounding_box: build_volume = self.getBoundingBox()
# It's over 9000! if build_volume is None:
build_volume_bounding_box = build_volume_bounding_box.set(bottom=-9001) #No bounding box. This is triggered when running Cura from command line with a model for the first time.
else: #In that situation there is a model, but no machine (and therefore no build volume).
# 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 return
build_volume = build_volume.set(bottom = -999999) #Allow models to clip the build plate. This should allow printing but remove the bottom side of the model underneath the build plate.
bounding_box = node.getBoundingBox()
if build_volume.intersectsBox(bounding_box) != AxisAlignedBox.IntersectionResult.FullIntersection:
node._outside_buildarea = True
else:
for node in nodes: #Check for collisions between disallowed areas and the object.
# Need to check group nodes later convex_hull = node.callDecoration("getConvexHull")
if node.callDecoration("isGroup"): if not convex_hull or not convex_hull.isValid():
group_nodes.append(node) # Keep list of affected group_nodes return
for area in self.getDisallowedAreas():
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): overlap = convex_hull.intersectsPolygon(area)
node._outside_buildarea = False if overlap is not None:
bbox = node.getBoundingBox()
# Mark the node as outside the build volume if the bounding box test fails.
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
node._outside_buildarea = True node._outside_buildarea = True
continue break
else:
node._outside_buildarea = False
convex_hull = node.callDecoration("getConvexHull") #Group nodes should override the _outside_buildarea property of their children.
if convex_hull: if node.callDecoration("isGroup"):
if not convex_hull.isValid(): for child in node.getAllChildren():
return child._outside_buildarea = node._outside_buildarea
# Check for collisions between disallowed areas and the object else:
for area in self.getDisallowedAreas(): for child in node.getChildren():
overlap = convex_hull.intersectsPolygon(area) self.updateNodeBoundaryCheck(child)
if overlap is None:
continue
node._outside_buildarea = True
continue
# Group nodes should override the _outside_buildarea property of their children.
for group_node in group_nodes:
for child_node in group_node.getAllChildren():
child_node._outside_buildarea = group_node._outside_buildarea
## Recalculates the build volume & disallowed areas. ## Recalculates the build volume & disallowed areas.
def rebuild(self): def rebuild(self):
@ -424,7 +422,7 @@ class BuildVolume(SceneNode):
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
self.updateNodeBoundaryCheck() self.updateAllBoundaryChecks()
def getBoundingBox(self) -> AxisAlignedBox: def getBoundingBox(self) -> AxisAlignedBox:
return self._volume_aabb return self._volume_aabb

View File

@ -56,14 +56,17 @@ class PlatformPhysics:
# By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve. # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
nodes = list(BreadthFirstIterator(root)) nodes = list(BreadthFirstIterator(root))
# Only check nodes inside build area.
nodes = [node for node in nodes if getattr(node, "_outside_buildarea", False)]
random.shuffle(nodes) random.shuffle(nodes)
for node in nodes: for node in nodes:
if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None: if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None:
continue continue
#Only check nodes inside the build area.
if not hasattr(node, "_outside_buildarea"):
self._build_volume.updateNodeBoundaryCheck(node)
if getattr(node, "_outside_buildarea", True):
continue
bbox = node.getBoundingBox() bbox = node.getBoundingBox()
# Move it downwards if bottom is above platform # Move it downwards if bottom is above platform
@ -155,7 +158,7 @@ class PlatformPhysics:
# After moving, we have to evaluate the boundary checks for nodes # After moving, we have to evaluate the boundary checks for nodes
build_volume = Application.getInstance().getBuildVolume() build_volume = Application.getInstance().getBuildVolume()
build_volume.updateNodeBoundaryCheck() build_volume.updateAllBoundaryChecks()
def _onToolOperationStarted(self, tool): def _onToolOperationStarted(self, tool):
self._enabled = False self._enabled = False