GCodeWriter.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Copyright (c) 2016 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from UM.Mesh.MeshWriter import MeshWriter
  4. from UM.Logger import Logger
  5. from UM.Application import Application
  6. import UM.Settings.ContainerRegistry
  7. from cura.CuraApplication import CuraApplication
  8. from cura.Settings.ExtruderManager import ExtruderManager
  9. import re #For escaping characters in the settings.
  10. import json
  11. ## Writes g-code to a file.
  12. #
  13. # While this poses as a mesh writer, what this really does is take the g-code
  14. # in the entire scene and write it to an output device. Since the g-code of a
  15. # single mesh isn't separable from the rest what with rafts and travel moves
  16. # and all, it doesn't make sense to write just a single mesh.
  17. #
  18. # So this plug-in takes the g-code that is stored in the root of the scene
  19. # node tree, adds a bit of extra information about the profiles and writes
  20. # that to the output device.
  21. class GCodeWriter(MeshWriter):
  22. ## The file format version of the serialised g-code.
  23. #
  24. # It can only read settings with the same version as the version it was
  25. # written with. If the file format is changed in a way that breaks reverse
  26. # compatibility, increment this version number!
  27. version = 3
  28. ## Dictionary that defines how characters are escaped when embedded in
  29. # g-code.
  30. #
  31. # Note that the keys of this dictionary are regex strings. The values are
  32. # not.
  33. escape_characters = {
  34. re.escape("\\"): "\\\\", # The escape character.
  35. re.escape("\n"): "\\n", # Newlines. They break off the comment.
  36. re.escape("\r"): "\\r" # Carriage return. Windows users may need this for visualisation in their editors.
  37. }
  38. def __init__(self):
  39. super().__init__()
  40. def write(self, stream, node, mode = MeshWriter.OutputMode.TextMode):
  41. if mode != MeshWriter.OutputMode.TextMode:
  42. Logger.log("e", "GCode Writer does not support non-text mode.")
  43. return False
  44. scene = Application.getInstance().getController().getScene()
  45. gcode_list = getattr(scene, "gcode_list")
  46. if gcode_list:
  47. for gcode in gcode_list:
  48. stream.write(gcode)
  49. # Serialise the current container stack and put it at the end of the file.
  50. settings = self._serialiseSettings(Application.getInstance().getGlobalContainerStack())
  51. stream.write(settings)
  52. return True
  53. return False
  54. ## Serialises a container stack to prepare it for writing at the end of the
  55. # g-code.
  56. #
  57. # The settings are serialised, and special characters (including newline)
  58. # are escaped.
  59. #
  60. # \param settings A container stack to serialise.
  61. # \return A serialised string of the settings.
  62. def _serialiseSettings(self, stack):
  63. prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
  64. prefix_length = len(prefix)
  65. container_with_profile = stack.findContainer({"type": "quality"})
  66. machine_manager = CuraApplication.getInstance().getMachineManager()
  67. # Duplicate the current quality profile and update it with any user settings.
  68. flat_quality_id = machine_manager.duplicateContainer(container_with_profile.getId())
  69. flat_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = flat_quality_id)[0]
  70. user_settings = stack.getTop()
  71. for key in user_settings.getAllKeys():
  72. flat_quality.setProperty(key, "value", user_settings.getProperty(key, "value"))
  73. serialized = flat_quality.serialize()
  74. data = {"global_quality": serialized}
  75. manager = ExtruderManager.getInstance()
  76. for extruder in manager.getMachineExtruders(stack.getBottom().getId()):
  77. extruder_quality = extruder.findContainer({"type": "quality"})
  78. flat_extruder_quality_id = machine_manager.duplicateContainer(extruder_quality.getId())
  79. flat_extruder_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=flat_extruder_quality_id)[0]
  80. extruder_user_settings = extruder.getTop()
  81. for key in extruder_user_settings.getAllKeys():
  82. flat_extruder_quality.setProperty(key, "value", extruder_user_settings.getProperty(key, "value"))
  83. extruder_serialized = flat_extruder_quality.serialize()
  84. data.setdefault("extruder_quality", []).append(extruder_serialized)
  85. json_string = json.dumps(data)
  86. # Escape characters that have a special meaning in g-code comments.
  87. pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
  88. # Perform the replacement with a regular expression.
  89. escaped_string = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], json_string)
  90. # Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
  91. result = ""
  92. # Lines have 80 characters, so the payload of each line is 80 - prefix.
  93. for pos in range(0, len(escaped_string), 80 - prefix_length):
  94. result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n"
  95. return result