ColorMix.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # ColorMix script - 2-1 extruder color mix and blending
  2. # This script is specific for the Geeetech A10M dual extruder but should work with other Marlin printers.
  3. # It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher.
  4. # This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
  5. #Authors of the 2-1 ColorMix plug-in / script:
  6. # Written by John Hryb - john.hryb.4@gmail.com
  7. ##history / change-log:
  8. ##V1.0.0
  9. ## Uses -
  10. ## M163 - Set Mix Factor
  11. ## M164 - Save Mix - saves to T3 as a unique mix
  12. import re #To perform the search and replace.
  13. from ..Script import Script
  14. class ColorMix(Script):
  15. def __init__(self):
  16. super().__init__()
  17. def getSettingDataString(self):
  18. return """{
  19. "name":"ColorMix 2-1",
  20. "key":"ColorMix 2-1",
  21. "metadata": {},
  22. "version": 2,
  23. "settings":
  24. {
  25. "measurement_units":
  26. {
  27. "label": "Units of measurement",
  28. "description": "Input value as mm or layer number.",
  29. "type": "enum",
  30. "options": {"mm":"mm","layer":"Layer"},
  31. "default_value": "layer"
  32. },
  33. "start_height":
  34. {
  35. "label": "Start Height",
  36. "description": "Value to start at (mm or layer)",
  37. "type": "float",
  38. "default_value": 0,
  39. "minimum_value": "0"
  40. },
  41. "behavior":
  42. {
  43. "label": "Fixed or blend",
  44. "description": "Select Fixed (set new mixture) or Blend mode (dynamic mix)",
  45. "type": "enum",
  46. "options": {"fixed_value":"Fixed","blend_value":"Blend"},
  47. "default_value": "fixed_value"
  48. },
  49. "finish_height":
  50. {
  51. "label": "Finish Height",
  52. "description": "Value to stop at (mm or layer)",
  53. "type": "float",
  54. "default_value": 0,
  55. "minimum_value": "0",
  56. "minimum_value_warning": "0.1",
  57. "enabled": "c_behavior == 'blend_value'"
  58. },
  59. "mix_start_ratio":
  60. {
  61. "label": "Start mix ratio",
  62. "description": "First extruder percentage 0-100",
  63. "type": "float",
  64. "default_value": 100,
  65. "minimum_value": "0",
  66. "minimum_value_warning": "0",
  67. "maximum_value_warning": "100"
  68. },
  69. "mix_finish_ratio":
  70. {
  71. "label": "End mix ratio",
  72. "description": "First extruder percentage 0-100 to finish blend",
  73. "type": "float",
  74. "default_value": 0,
  75. "minimum_value": "0",
  76. "minimum_value_warning": "0",
  77. "maximum_value_warning": "100",
  78. "enabled": "c_behavior == 'blend_value'"
  79. },
  80. "notes":
  81. {
  82. "label": "Notes",
  83. "description": "A spot to put a note",
  84. "type": "str",
  85. "default_value": ""
  86. }
  87. }
  88. }"""
  89. def getValue(self, line, key, default = None): #replace default getvalue due to comment-reading feature
  90. if not key in line or (";" in line and line.find(key) > line.find(";") and
  91. not ";ChangeAtZ" in key and not ";LAYER:" in key):
  92. return default
  93. subPart = line[line.find(key) + len(key):] #allows for string lengths larger than 1
  94. if ";ChangeAtZ" in key:
  95. m = re.search("^[0-4]", subPart)
  96. elif ";LAYER:" in key:
  97. m = re.search("^[+-]?[0-9]*", subPart)
  98. else:
  99. #the minus at the beginning allows for negative values, e.g. for delta printers
  100. m = re.search("^[-]?[0-9]*\.?[0-9]*", subPart)
  101. if m == None:
  102. return default
  103. try:
  104. return float(m.group(0))
  105. except:
  106. return default
  107. def execute(self, data):
  108. #get user variables
  109. firstHeight = 0.0
  110. secondHeight = 0.0
  111. firstMix = 0.0
  112. SecondMix = 0.0
  113. firstHeight = self.getSettingValueByKey("start_height")
  114. secondHeight = self.getSettingValueByKey("finish_height")
  115. firstMix = self.getSettingValueByKey("mix_start_ratio")
  116. SecondMix = self.getSettingValueByKey("mix_finish_ratio")
  117. #locals
  118. layer = 0
  119. #get layer height
  120. layerHeight = .2
  121. for active_layer in data:
  122. lines = active_layer.split("\n")
  123. for line in lines:
  124. if ";Layer height: " in line:
  125. layerHeight = self.getValue(line, ";Layer height: ", layerHeight)
  126. break
  127. #get layers to use
  128. startLayer = 0
  129. endLayer = 0
  130. if self.getSettingValueByKey("measurement_units") == "mm":
  131. if firstHeight == 0:
  132. startLayer = 0
  133. else:
  134. startLayer = firstHeight / layerHeight
  135. if secondHeight == 0:
  136. endLayer = 0
  137. else:
  138. endLayer = secondHeight / layerHeight
  139. else: #layer height
  140. startLayer = firstHeight
  141. endLayer = secondHeight
  142. #see if one-shot
  143. if self.getSettingValueByKey("behavior") == "fixed_value":
  144. endLayer = startLayer
  145. firstExtruderIncrements = 0
  146. else: #blend
  147. firstExtruderIncrements = (SecondMix - firstMix) / (endLayer - startLayer)
  148. firstExtruderValue = 0
  149. index = 0
  150. #start scanning
  151. for active_layer in data:
  152. modified_gcode = ""
  153. lineIndex = 0;
  154. lines = active_layer.split("\n")
  155. for line in lines:
  156. #dont leave blanks
  157. if line != "":
  158. modified_gcode += line + "\n"
  159. # find current layer
  160. if ";LAYER:" in line:
  161. layer = self.getValue(line, ";LAYER:", layer)
  162. if (layer >= startLayer) and (layer <= endLayer): #find layers of interest
  163. if lines[lineIndex + 4] == "T2": #check if needing to delete old data
  164. del lines[(lineIndex + 1):(lineIndex + 5)]
  165. firstExtruderValue = int(((layer - startLayer) * firstExtruderIncrements) + firstMix)
  166. if firstExtruderValue == 100:
  167. modified_gcode += "M163 S0 P1\n"
  168. modified_gcode += "M163 S1 P0\n"
  169. elif firstExtruderValue == 0:
  170. modified_gcode += "M163 S0 P0\n"
  171. modified_gcode += "M163 S1 P1\n"
  172. else:
  173. modified_gcode += "M163 S0 P0.{:02d}\n".format(firstExtruderValue)
  174. modified_gcode += "M163 S1 P0.{:02d}\n".format(100 - firstExtruderValue)
  175. modified_gcode += "M164 S2\n"
  176. modified_gcode += "T2\n"
  177. lineIndex += 1 #for deleting index
  178. data[index] = modified_gcode
  179. index += 1
  180. return data