ConvexHullJob.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. # Copyright (c) 2015 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from UM.Job import Job
  4. from UM.Application import Application
  5. from UM.Math.Polygon import Polygon
  6. import numpy
  7. import copy
  8. from . import ConvexHullNode
  9. ## Job to async calculate the convex hull of a node.
  10. class ConvexHullJob(Job):
  11. def __init__(self, node):
  12. super().__init__()
  13. self._node = node
  14. def run(self):
  15. if not self._node:
  16. return
  17. ## If the scene node is a group, use the hull of the children to calculate its hull.
  18. if self._node.callDecoration("isGroup"):
  19. hull = Polygon(numpy.zeros((0, 2), dtype=numpy.int32))
  20. for child in self._node.getChildren():
  21. child_hull = child.callDecoration("getConvexHull")
  22. if child_hull:
  23. hull.setPoints(numpy.append(hull.getPoints(), child_hull.getPoints(), axis = 0))
  24. if hull.getPoints().size < 3:
  25. self._node.callDecoration("setConvexHull", None)
  26. self._node.callDecoration("setConvexHullJob", None)
  27. return
  28. Job.yieldThread()
  29. else:
  30. if not self._node.getMeshData():
  31. return
  32. mesh = self._node.getMeshData()
  33. vertex_data = mesh.getTransformed(self._node.getWorldTransformation()).getVertices()
  34. # Don't use data below 0.
  35. # TODO; We need a better check for this as this gives poor results for meshes with long edges.
  36. vertex_data = vertex_data[vertex_data[:,1] >= 0]
  37. hull = Polygon(numpy.rint(vertex_data[:, [0, 2]]).astype(int))
  38. # First, calculate the normal convex hull around the points
  39. hull = hull.getConvexHull()
  40. # Then, do a Minkowski hull with a simple 1x1 quad to outset and round the normal convex hull.
  41. # This is done because of rounding errors.
  42. hull = hull.getMinkowskiHull(Polygon(numpy.array([[-1, -1], [-1, 1], [1, 1], [1, -1]], numpy.float32)))
  43. profile = Application.getInstance().getMachineManager().getWorkingProfile()
  44. if profile:
  45. if profile.getSettingValue("print_sequence") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
  46. # Printing one at a time and it's not an object in a group
  47. self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull))
  48. head_and_fans = Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"), numpy.float32))
  49. # Full head hull is used to actually check the order.
  50. full_head_hull = hull.getMinkowskiHull(head_and_fans)
  51. self._node.callDecoration("setConvexHullHeadFull", full_head_hull)
  52. mirrored = copy.deepcopy(head_and_fans)
  53. mirrored.mirror([0, 0], [0, 1]) #Mirror horizontally.
  54. mirrored.mirror([0, 0], [1, 0]) #Mirror vertically.
  55. head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)
  56. # Min head hull is used for the push free
  57. min_head_hull = hull.getMinkowskiHull(head_and_fans)
  58. self._node.callDecoration("setConvexHullHead", min_head_hull)
  59. hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_polygon"),numpy.float32)))
  60. else:
  61. self._node.callDecoration("setConvexHullHead", None)
  62. if self._node.getParent() is None: # Node was already deleted before job is done.
  63. self._node.callDecoration("setConvexHullNode",None)
  64. self._node.callDecoration("setConvexHull", None)
  65. self._node.callDecoration("setConvexHullJob", None)
  66. return
  67. hull_node = ConvexHullNode.ConvexHullNode(self._node, hull, Application.getInstance().getController().getScene().getRoot())
  68. self._node.callDecoration("setConvexHullNode", hull_node)
  69. self._node.callDecoration("setConvexHull", hull)
  70. self._node.callDecoration("setConvexHullJob", None)
  71. if self._node.getParent() and self._node.getParent().callDecoration("isGroup"):
  72. job = self._node.getParent().callDecoration("getConvexHullJob")
  73. if job:
  74. job.cancel()
  75. self._node.getParent().callDecoration("setConvexHull", None)
  76. hull_node = self._node.getParent().callDecoration("getConvexHullNode")
  77. if hull_node:
  78. hull_node.setParent(None)