ConvexHullNode.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional, TYPE_CHECKING
  4. from UM.Application import Application
  5. from UM.Math.Polygon import Polygon
  6. from UM.Qt.QtApplication import QtApplication
  7. from UM.Scene.SceneNode import SceneNode
  8. from UM.Resources import Resources
  9. from UM.Math.Color import Color
  10. from UM.Mesh.MeshBuilder import MeshBuilder # To create a mesh to display the convex hull with.
  11. from UM.View.GL.OpenGL import OpenGL
  12. if TYPE_CHECKING:
  13. from UM.Mesh.MeshData import MeshData
  14. class ConvexHullNode(SceneNode):
  15. shader = None # To prevent the shader from being re-built over and over again, only load it once.
  16. def __init__(self, node: SceneNode, hull: Optional[Polygon], thickness: float, parent: Optional[SceneNode] = None) -> None:
  17. """Convex hull node is a special type of scene node that is used to display an area, to indicate the
  18. location an object uses on the buildplate. This area (or area's in case of one at a time printing) is
  19. then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded
  20. to represent the raft as well.
  21. """
  22. super().__init__(parent)
  23. self.setCalculateBoundingBox(False)
  24. self._original_parent = parent
  25. # Color of the drawn convex hull
  26. if not Application.getInstance().getIsHeadLess():
  27. theme = QtApplication.getInstance().getTheme()
  28. if theme:
  29. self._color = Color(*theme.getColor("convex_hull").getRgb())
  30. else:
  31. self._color = Color(0, 0, 0)
  32. else:
  33. self._color = Color(0, 0, 0)
  34. # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
  35. self._mesh_height = 0.1
  36. self._thickness = thickness
  37. # The node this mesh is "watching"
  38. self._node = node
  39. # Area of the head + fans for display as a shadow on the buildplate
  40. self._convex_hull_head_mesh = None # type: Optional[MeshData]
  41. self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged)
  42. self._onNodeDecoratorsChanged(self._node)
  43. self._hull = hull
  44. if self._hull:
  45. hull_mesh_builder = MeshBuilder()
  46. if self._thickness == 0:
  47. if hull_mesh_builder.addConvexPolygon(
  48. self._hull.getPoints()[::], # bottom layer is reversed
  49. self._mesh_height, color = self._color):
  50. hull_mesh_builder.resetNormals()
  51. hull_mesh = hull_mesh_builder.build()
  52. self.setMeshData(hull_mesh)
  53. else:
  54. if hull_mesh_builder.addConvexPolygonExtrusion(
  55. self._hull.getPoints()[::-1], # bottom layer is reversed
  56. self._mesh_height - thickness, self._mesh_height, color = self._color):
  57. hull_mesh_builder.resetNormals()
  58. hull_mesh = hull_mesh_builder.build()
  59. self.setMeshData(hull_mesh)
  60. def getHull(self):
  61. return self._hull
  62. def getThickness(self):
  63. return self._thickness
  64. def getWatchedNode(self):
  65. return self._node
  66. def render(self, renderer):
  67. if not ConvexHullNode.shader:
  68. ConvexHullNode.shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
  69. ConvexHullNode.shader.setUniformValue("u_diffuseColor", self._color)
  70. ConvexHullNode.shader.setUniformValue("u_opacity", 0.6)
  71. batch = renderer.getNamedBatch("convex_hull_node")
  72. if not batch:
  73. batch = renderer.createRenderBatch(transparent = True, shader = ConvexHullNode.shader, backface_cull = True, sort = -8)
  74. renderer.addRenderBatch(batch, name = "convex_hull_node")
  75. batch.addItem(self.getWorldTransformation(copy = False), self.getMeshData())
  76. if self._convex_hull_head_mesh:
  77. # The full head. Rendered as a hint to the user: If this area overlaps another object A; this object
  78. # cannot be printed after A, because the head would hit A while printing the current object
  79. renderer.queueNode(self, shader = ConvexHullNode.shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
  80. return True
  81. def _onNodeDecoratorsChanged(self, node: SceneNode) -> None:
  82. convex_hull_head = self._node.callDecoration("getConvexHullHeadFull")
  83. if convex_hull_head:
  84. convex_hull_head_builder = MeshBuilder()
  85. convex_hull_head_builder.addConvexPolygon(convex_hull_head.getPoints(), self._mesh_height - self._thickness)
  86. self._convex_hull_head_mesh = convex_hull_head_builder.build()