MultiplyObjectsJob.py 3.3 KB

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