MultiplyObjectsJob.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import copy
  4. from UM.Job import Job
  5. from UM.Operations.GroupedOperation import GroupedOperation
  6. from UM.Message import Message
  7. from UM.i18n import i18nCatalog
  8. i18n_catalog = i18nCatalog("cura")
  9. from cura.Arranging.Arrange import Arrange
  10. from cura.Arranging.ShapeArray import ShapeArray
  11. from UM.Application import Application
  12. from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
  13. class MultiplyObjectsJob(Job):
  14. def __init__(self, objects, count, min_offset = 8):
  15. super().__init__()
  16. self._objects = objects
  17. self._count = count
  18. self._min_offset = min_offset
  19. def run(self):
  20. status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0,
  21. dismissable=False, progress=0, title = i18n_catalog.i18nc("@info:title", "Placing Objects"))
  22. status_message.show()
  23. scene = Application.getInstance().getController().getScene()
  24. total_progress = len(self._objects) * self._count
  25. current_progress = 0
  26. global_container_stack = Application.getInstance().getGlobalContainerStack()
  27. machine_width = global_container_stack.getProperty("machine_width", "value")
  28. machine_depth = global_container_stack.getProperty("machine_depth", "value")
  29. root = scene.getRoot()
  30. scale = 0.5
  31. arranger = Arrange.create(x = machine_width, y = machine_depth, scene_root = root, scale = scale, min_offset = self._min_offset)
  32. processed_nodes = []
  33. nodes = []
  34. not_fit_count = 0
  35. for node in self._objects:
  36. # If object is part of a group, multiply group
  37. current_node = node
  38. while current_node.getParent() and (current_node.getParent().callDecoration("isGroup") or current_node.getParent().callDecoration("isSliceable")):
  39. current_node = current_node.getParent()
  40. if current_node in processed_nodes:
  41. continue
  42. processed_nodes.append(current_node)
  43. node_too_big = False
  44. if node.getBoundingBox().width < machine_width or node.getBoundingBox().depth < machine_depth:
  45. offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset = self._min_offset, scale = scale)
  46. else:
  47. node_too_big = True
  48. found_solution_for_all = True
  49. arranger.resetLastPriority()
  50. for i in range(self._count):
  51. # We do place the nodes one by one, as we want to yield in between.
  52. new_node = copy.deepcopy(node)
  53. solution_found = False
  54. if not node_too_big:
  55. solution_found = arranger.findNodePlacement(new_node, offset_shape_arr, hull_shape_arr)
  56. if node_too_big or not solution_found:
  57. found_solution_for_all = False
  58. new_location = new_node.getPosition()
  59. new_location = new_location.set(z = - not_fit_count * 20)
  60. new_node.setPosition(new_location)
  61. not_fit_count += 1
  62. # Same build plate
  63. build_plate_number = current_node.callDecoration("getBuildPlateNumber")
  64. new_node.callDecoration("setBuildPlateNumber", build_plate_number)
  65. for child in new_node.getChildren():
  66. child.callDecoration("setBuildPlateNumber", build_plate_number)
  67. nodes.append(new_node)
  68. current_progress += 1
  69. status_message.setProgress((current_progress / total_progress) * 100)
  70. Job.yieldThread()
  71. Job.yieldThread()
  72. if nodes:
  73. op = GroupedOperation()
  74. for new_node in nodes:
  75. op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
  76. op.push()
  77. status_message.hide()
  78. if not found_solution_for_all:
  79. no_full_solution_message = Message(i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"), title = i18n_catalog.i18nc("@info:title", "Placing Object"))
  80. no_full_solution_message.show()