OneAtATimeIterator.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import sys
  4. from UM.Scene.Iterator import Iterator
  5. from UM.Scene.SceneNode import SceneNode
  6. # Iterator that determines the object print order when one-at a time mode is enabled.
  7. #
  8. # In one-at-a-time mode, only one extruder can be enabled to print. In order to maximize the number of objects we can
  9. # print, we need to print from the corner that's closest to the extruder that's being used. Here is an illustration:
  10. #
  11. # +--------------------------------+
  12. # | |
  13. # | |
  14. # | | - Rectangle represents the complete print head including fans, etc.
  15. # | X X | y - X's are the nozzles
  16. # | (1) (2) | |
  17. # | | |
  18. # +--------------------------------+ +--> x
  19. #
  20. # In this case, the nozzles are symmetric, nozzle (1) is closer to the bottom left corner while (2) is closer to the
  21. # bottom right. If we use nozzle (1) to print, then we better off printing from the bottom left corner so the print
  22. # head will not collide into an object on its top-right side, which is a very large unused area. Following the same
  23. # logic, if we are printing with nozzle (2), then it's better to print from the bottom-right side.
  24. #
  25. # This iterator determines the print order following the rules above.
  26. #
  27. class OneAtATimeIterator(Iterator.Iterator):
  28. def __init__(self, scene_node):
  29. from cura.CuraApplication import CuraApplication
  30. self._global_stack = CuraApplication.getInstance().getGlobalContainerStack()
  31. self._original_node_list = []
  32. super().__init__(scene_node) # Call super to make multiple inheritance work.
  33. def getMachineNearestCornerToExtruder(self, global_stack):
  34. head_and_fans_coordinates = global_stack.getHeadAndFansCoordinates()
  35. used_extruder = None
  36. for extruder in global_stack.extruders.values():
  37. if extruder.isEnabled:
  38. used_extruder = extruder
  39. break
  40. extruder_offsets = [used_extruder.getProperty("machine_nozzle_offset_x", "value"),
  41. used_extruder.getProperty("machine_nozzle_offset_y", "value")]
  42. # find the corner that's closest to the origin
  43. min_distance2 = sys.maxsize
  44. min_coord = None
  45. for coord in head_and_fans_coordinates:
  46. x = coord[0] - extruder_offsets[0]
  47. y = coord[1] - extruder_offsets[1]
  48. distance2 = x**2 + y**2
  49. if distance2 <= min_distance2:
  50. min_distance2 = distance2
  51. min_coord = coord
  52. return min_coord
  53. def _fillStack(self):
  54. min_coord = self.getMachineNearestCornerToExtruder(self._global_stack)
  55. transform_x = -int(round(min_coord[0] / abs(min_coord[0])))
  56. transform_y = -int(round(min_coord[1] / abs(min_coord[1])))
  57. machine_size = [self._global_stack.getProperty("machine_width", "value"),
  58. self._global_stack.getProperty("machine_depth", "value")]
  59. def flip_x(polygon):
  60. tm2 = [-1, 0, 0, 1, 0, 0]
  61. return affinity.affine_transform(affinity.translate(polygon, xoff = -machine_size[0]), tm2)
  62. def flip_y(polygon):
  63. tm2 = [1, 0, 0, -1, 0, 0]
  64. return affinity.affine_transform(affinity.translate(polygon, yoff = -machine_size[1]), tm2)
  65. from shapely import affinity
  66. from shapely.geometry import Polygon
  67. node_list = []
  68. for node in self._scene_node.getChildren():
  69. if not issubclass(type(node), SceneNode):
  70. continue
  71. convex_hull = node.callDecoration("getConvexHull")
  72. if convex_hull:
  73. xmin = min(x for x, _ in convex_hull._points)
  74. xmax = max(x for x, _ in convex_hull._points)
  75. ymin = min(y for _, y in convex_hull._points)
  76. ymax = max(y for _, y in convex_hull._points)
  77. convex_hull_polygon = Polygon.from_bounds(xmin, ymin, xmax, ymax)
  78. if transform_x < 0:
  79. convex_hull_polygon = flip_x(convex_hull_polygon)
  80. if transform_y < 0:
  81. convex_hull_polygon = flip_y(convex_hull_polygon)
  82. node_list.append({"node": node,
  83. "min_coord": [convex_hull_polygon.bounds[0], convex_hull_polygon.bounds[1]],
  84. })
  85. node_list = sorted(node_list, key = lambda d: d["min_coord"])
  86. self._node_stack = [d["node"] for d in node_list]