InsertAtLayerChange.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # Copyright (c) 2020 Ultimaker B.V.
  2. # Created by Wayne Porter
  3. # Re-write in April of 2024 by GregValiant (Greg Foresi)
  4. # Changes:
  5. # Added an 'Enable' setting
  6. # Added support for multi-line insertions (comma delimited)
  7. # Added insertions in a range of layers or a single insertion at a layer. Numbers are consistent with the Cura Preview (base1)
  8. # Added frequency of Insertion (once only, every layer, every 2nd, 3rd, 5th, 10th, 25th, 50th, 100th)
  9. # Added support for 'One at a Time' print sequence
  10. # Rafts are allowed and accounted for but no insertions are made in raft layers
  11. from ..Script import Script
  12. import re
  13. from UM.Application import Application
  14. class InsertAtLayerChange(Script):
  15. def getSettingDataString(self):
  16. return """{
  17. "name": "Insert at Layer Change",
  18. "key": "InsertAtLayerChange",
  19. "metadata": {},
  20. "version": 2,
  21. "settings":
  22. {
  23. "enabled":
  24. {
  25. "label": "Enable this script",
  26. "description": "You must enable the script for it to run.",
  27. "type": "bool",
  28. "default_value": true,
  29. "enabled": true
  30. },
  31. "insert_frequency":
  32. {
  33. "label": "How often to insert",
  34. "description": "Every so many layers starting with the Start Layer OR as single insertion at a specific layer. If the print sequence is 'one_at_a_time' then the insertions will be made for every model. Insertions are made at the beginning of a layer.",
  35. "type": "enum",
  36. "options": {
  37. "once_only": "One insertion only",
  38. "every_layer": "Every Layer",
  39. "every_2nd": "Every 2nd",
  40. "every_3rd": "Every 3rd",
  41. "every_5th": "Every 5th",
  42. "every_10th": "Every 10th",
  43. "every_25th": "Every 25th",
  44. "every_50th": "Every 50th",
  45. "every_100th": "Every 100th"},
  46. "default_value": "every_layer",
  47. "enabled": "enabled"
  48. },
  49. "start_layer":
  50. {
  51. "label": "Starting Layer",
  52. "description": "The layer before which the first insertion will take place. If the Print_Sequence is 'All at Once' then use the layer numbers from the Cura Preview. Enter '1' to start at gcode LAYER:0. In 'One at a Time' mode use the layer numbers from the first model that prints AND all models will receive the same insertions. NOTE: There is never an insertion for raft layers.",
  53. "type": "int",
  54. "default_value": 1,
  55. "minimum_value": 1,
  56. "enabled": "insert_frequency != 'once_only' and enabled"
  57. },
  58. "end_layer":
  59. {
  60. "label": "Ending Layer",
  61. "description": "The layer before which the last insertion will take place. Enter '-1' to indicate the entire file. Use layer numbers from the Cura Preview.",
  62. "type": "int",
  63. "default_value": -1,
  64. "minimum_value": -1,
  65. "enabled": "insert_frequency != 'once_only' and enabled"
  66. },
  67. "single_end_layer":
  68. {
  69. "label": "Layer # for Single Insertion.",
  70. "description": "The layer before which the Gcode insertion will take place. Use the layer numbers from the Cura Preview.",
  71. "type": "str",
  72. "default_value": "",
  73. "enabled": "insert_frequency == 'once_only' and enabled"
  74. },
  75. "gcode_to_add":
  76. {
  77. "label": "G-code to insert.",
  78. "description": "G-code to add at start of the layer. Use a comma to delimit multi-line commands. EX: G28 X Y,M220 S100,M117 HELL0. NOTE: All inserted text will be converted to upper-case as some firmwares don't understand lower-case.",
  79. "type": "str",
  80. "default_value": "",
  81. "enabled": "enabled"
  82. }
  83. }
  84. }"""
  85. def execute(self, data):
  86. # Exit if the script is not enabled
  87. if not bool(self.getSettingValueByKey("enabled")):
  88. return data
  89. #Initialize variables
  90. mycode = self.getSettingValueByKey("gcode_to_add").upper()
  91. start_layer = int(self.getSettingValueByKey("start_layer"))
  92. end_layer = int(self.getSettingValueByKey("end_layer"))
  93. when_to_insert = self.getSettingValueByKey("insert_frequency")
  94. end_list = [0]
  95. print_sequence = Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value")
  96. # Get the topmost layer number and adjust the end_list
  97. if end_layer == -1:
  98. if print_sequence == "all_at_once":
  99. for lnum in range(0, len(data) - 1):
  100. if ";LAYER:" in data[lnum]:
  101. the_top = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
  102. end_list[0] = the_top
  103. # Get the topmost layer number for each model and append it to the end_list
  104. if print_sequence == "one_at_a_time":
  105. for lnum in range(0, 10):
  106. if ";LAYER:0" in data[lnum]:
  107. start_at = lnum + 1
  108. break
  109. for lnum in range(start_at, len(data)-1, 1):
  110. if ";LAYER:" in data[lnum] and not ";LAYER:0" in data[lnum] and not ";LAYER:-" in data[lnum]:
  111. end_list[len(end_list) - 1] = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
  112. continue
  113. if ";LAYER:0" in data[lnum]:
  114. end_list.append(0)
  115. elif end_layer != -1:
  116. if print_sequence == "all_at_once":
  117. # Catch an error if the entered End_Layer > the top layer in the gcode
  118. for e_num, layer in enumerate(data):
  119. if ";LAYER:" in layer:
  120. top_layer = int(data[e_num].split(";LAYER:")[1].split("\n")[0])
  121. end_list[0] = end_layer - 1
  122. if top_layer < end_layer - 1:
  123. end_list[0] = top_layer
  124. elif print_sequence == "one_at_a_time":
  125. # Find the index of the first Layer:0
  126. for lnum in range(0, 10):
  127. if ";LAYER:0" in data[lnum]:
  128. start_at = lnum + 1
  129. break
  130. # Get the top layer number for each model
  131. for lnum in range(start_at, len(data)-1):
  132. if ";LAYER:" in data[lnum] and not ";LAYER:0" in data[lnum] and not ";LAYER:-" in data[lnum]:
  133. end_list[len(end_list) - 1] = int(data[lnum].split(";LAYER:")[1].split("\n")[0])
  134. if ";LAYER:0" in data[lnum]:
  135. end_list.append(0)
  136. # Adjust the end list if an end layer was named
  137. for index, num in enumerate(end_list):
  138. if num > end_layer - 1:
  139. end_list[index] = end_layer - 1
  140. #If the gcode_to_enter is multi-line then replace the commas with newline characters
  141. if mycode != "":
  142. if "," in mycode:
  143. mycode = re.sub(",", "\n",mycode)
  144. gcode_to_add = mycode
  145. #Get the insertion frequency
  146. match when_to_insert:
  147. case "every_layer":
  148. freq = 1
  149. case "every_2nd":
  150. freq = 2
  151. case "every_3rd":
  152. freq = 3
  153. case "every_5th":
  154. freq = 5
  155. case "every_10th":
  156. freq = 10
  157. case "every_25th":
  158. freq = 25
  159. case "every_50th":
  160. freq = 50
  161. case "every_100th":
  162. freq = 100
  163. case "once_only":
  164. the_insert_layer = int(self.getSettingValueByKey("single_end_layer"))-1
  165. case _:
  166. raise ValueError(f"Unexpected insertion frequency {when_to_insert}")
  167. #Single insertion
  168. if when_to_insert == "once_only":
  169. # For print sequence 'All at once'
  170. if print_sequence == "all_at_once":
  171. for index, layer in enumerate(data):
  172. if ";LAYER:" + str(the_insert_layer) + "\n" in layer:
  173. lines = layer.split("\n")
  174. lines.insert(1,gcode_to_add)
  175. data[index] = "\n".join(lines)
  176. return data
  177. # For print sequence 'One at a time'
  178. else:
  179. for index, layer in enumerate(data):
  180. if ";LAYER:" + str(the_insert_layer) + "\n" in layer:
  181. lines = layer.split("\n")
  182. lines.insert(1,gcode_to_add)
  183. data[index] = "\n".join(lines)
  184. return data
  185. # For multiple insertions
  186. if when_to_insert != "once_only":
  187. # Search from the line after the first Layer:0 so we know when a model ends if in One at a Time mode.
  188. first_0 = True
  189. next_layer = start_layer - 1
  190. end_layer = end_list.pop(0)
  191. for index, layer in enumerate(data):
  192. lines = layer.split("\n")
  193. for l_index, line in enumerate(lines):
  194. if ";LAYER:" in line:
  195. layer_number = int(line.split(":")[1])
  196. if layer_number == next_layer and layer_number <= end_layer:
  197. lines.insert(l_index + 1,gcode_to_add)
  198. data[index] = "\n".join(lines)
  199. next_layer += freq
  200. # Reset the next_layer for one-at-a-time
  201. if next_layer > int(end_layer):
  202. next_layer = start_layer - 1
  203. # Index to the next end_layer when a Layer:0 is encountered
  204. try:
  205. if not first_0 and layer_number == 0:
  206. end_layer = end_list.pop(0)
  207. except:
  208. pass
  209. # Beyond the initial Layer:0 futher Layer:0's indicate the top layer of a model.
  210. if layer_number == 0:
  211. first_0 = False
  212. break
  213. return data