MultiplyObjectsJob.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import copy
  4. from typing import List
  5. from UM.Application import Application
  6. from UM.Job import Job
  7. from UM.Message import Message
  8. from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
  9. from UM.Scene.SceneNode import SceneNode
  10. from UM.i18n import i18nCatalog
  11. from cura.Arranging.Nest2DArrange import arrange
  12. i18n_catalog = i18nCatalog("cura")
  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) -> None:
  20. status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0,
  21. dismissable = False, progress = 0,
  22. title = i18n_catalog.i18nc("@info:title", "Placing Objects"))
  23. status_message.show()
  24. scene = Application.getInstance().getController().getScene()
  25. global_container_stack = Application.getInstance().getGlobalContainerStack()
  26. if global_container_stack is None:
  27. return # We can't do anything in this case.
  28. root = scene.getRoot()
  29. processed_nodes = [] # type: List[SceneNode]
  30. nodes = []
  31. fixed_nodes = []
  32. for node_ in DepthFirstIterator(root):
  33. # Only count sliceable objects
  34. if node_.callDecoration("isSliceable"):
  35. fixed_nodes.append(node_)
  36. for node in self._objects:
  37. # If object is part of a group, multiply group
  38. current_node = node
  39. while current_node.getParent() and (current_node.getParent().callDecoration("isGroup") or current_node.getParent().callDecoration("isSliceable")):
  40. current_node = current_node.getParent()
  41. if current_node in processed_nodes:
  42. continue
  43. processed_nodes.append(current_node)
  44. for _ in range(self._count):
  45. new_node = copy.deepcopy(node)
  46. # Same build plate
  47. build_plate_number = current_node.callDecoration("getBuildPlateNumber")
  48. new_node.callDecoration("setBuildPlateNumber", build_plate_number)
  49. for child in new_node.getChildren():
  50. child.callDecoration("setBuildPlateNumber", build_plate_number)
  51. nodes.append(new_node)
  52. found_solution_for_all = True
  53. if nodes:
  54. found_solution_for_all = arrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes,
  55. factor = 10000, add_new_nodes_in_scene = True)
  56. status_message.hide()
  57. if not found_solution_for_all:
  58. no_full_solution_message = Message(
  59. i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"),
  60. title = i18n_catalog.i18nc("@info:title", "Placing Object"),
  61. message_type = Message.MessageType.WARNING)
  62. no_full_solution_message.show()