RetractContinue.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # Copyright (c) 2023 UltiMaker B.V.
  2. # The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
  3. from ..Script import Script
  4. from UM.Application import Application # To get current absolute/relative setting.
  5. from UM.Math.Vector import Vector
  6. from typing import List, Tuple
  7. class RetractContinue(Script):
  8. """Continues retracting during all travel moves."""
  9. def getSettingDataString(self) -> str:
  10. return """{
  11. "name": "Retract Continue",
  12. "key": "RetractContinue",
  13. "metadata": {},
  14. "version": 2,
  15. "settings":
  16. {
  17. "extra_retraction_speed":
  18. {
  19. "label": "Extra Retraction Ratio",
  20. "description": "How much does it retract during the travel move, by ratio of the travel length.",
  21. "type": "float",
  22. "default_value": 0.05
  23. }
  24. }
  25. }"""
  26. def _getTravelMove(self, travel_move: str, default_pos: Vector) -> Tuple[Vector, float]:
  27. travel = Vector(
  28. self.getValue(travel_move, "X", default_pos.x),
  29. self.getValue(travel_move, "Y", default_pos.y),
  30. self.getValue(travel_move, "Z", default_pos.z)
  31. )
  32. f = self.getValue(travel_move, "F", -1.0)
  33. return travel, f
  34. def _travelMoveString(self, travel: Vector, f: float, e: float) -> str:
  35. # Note that only G1 moves are written, since extrusion is included.
  36. if f <= 0.0:
  37. return f"G1 X{travel.x:.5f} Y{travel.y:.5f} Z{travel.z:.5f} E{e:.5f}"
  38. else:
  39. return f"G1 F{f:.5f} X{travel.x:.5f} Y{travel.y:.5f} Z{travel.z:.5f} E{e:.5f}"
  40. def execute(self, data: List[str]) -> List[str]:
  41. current_e = 0.0
  42. to_compensate = 0 # Used when extrusion mode is relative.
  43. is_active = False # Whether retract-continue is in effect.
  44. current_pos = Vector(0.0, 0.0, 0.0)
  45. last_pos = Vector(0.0, 0.0, 0.0)
  46. extra_retraction_speed = self.getSettingValueByKey("extra_retraction_speed")
  47. relative_extrusion = Application.getInstance().getGlobalContainerStack().getProperty(
  48. "relative_extrusion", "value"
  49. )
  50. for layer_number, layer in enumerate(data):
  51. lines = layer.split("\n")
  52. for line_number, line in enumerate(lines):
  53. # Focus on move-type lines.
  54. code_g = self.getValue(line, "G")
  55. if code_g not in [0, 1]:
  56. continue
  57. # Track X,Y,Z location.
  58. last_pos = last_pos.set(current_pos.x, current_pos.y, current_pos.z)
  59. current_pos = current_pos.set(
  60. self.getValue(line, "X", current_pos.x),
  61. self.getValue(line, "Y", current_pos.y),
  62. self.getValue(line, "Z", current_pos.z)
  63. )
  64. # Track extrusion 'axis' position.
  65. last_e = current_e
  66. e_value = self.getValue(line, "E")
  67. if e_value:
  68. current_e = (current_e if relative_extrusion else 0) + e_value
  69. # Handle lines: Detect retractions and compensate relative if G1, potential retract-continue if G0.
  70. if code_g == 1:
  71. if last_e > (current_e + 0.0001): # Account for floating point inaccuracies.
  72. # There is a retraction, each following G0 command needs to continue the retraction.
  73. is_active = True
  74. continue
  75. elif relative_extrusion and is_active:
  76. # If 'relative', the first G1 command after the total retraction will have to compensate more.
  77. travel, f = self._getTravelMove(lines[line_number], current_pos)
  78. lines[line_number] = self._travelMoveString(travel, f, to_compensate + e_value)
  79. to_compensate = 0.0
  80. # There is no retraction (see continue in the retract-clause) and everything else has been handled.
  81. is_active = False
  82. elif code_g == 0:
  83. if not is_active:
  84. continue
  85. # The retract-continue is active, so each G0 until the next extrusion needs to continue retraction.
  86. travel, f = self._getTravelMove(lines[line_number], current_pos)
  87. travel_length = (current_pos - last_pos).length()
  88. extra_retract = travel_length * extra_retraction_speed
  89. new_e = (0 if relative_extrusion else current_e) - extra_retract
  90. to_compensate += extra_retract
  91. current_e -= extra_retract
  92. lines[line_number] = self._travelMoveString(travel, f, new_e)
  93. new_layer = "\n".join(lines)
  94. data[layer_number] = new_layer
  95. return data