mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-20 20:59:48 +08:00

This makes for ugly g-code files, true, but at least the functionality of saving settings is useful now: It's traceable. Could've implemented this somewhere else too, but this is fine for now. Contributes to issue CURA-1278.
90 lines
4.1 KiB
Python
90 lines
4.1 KiB
Python
# Copyright (c) 2016 Ultimaker B.V.
|
|
# Cura is released under the terms of the AGPLv3 or higher.
|
|
|
|
from UM.Mesh.MeshWriter import MeshWriter
|
|
from UM.Logger import Logger
|
|
from UM.Application import Application
|
|
from UM.Settings.InstanceContainer import InstanceContainer #To create a complete setting profile to store in the g-code.
|
|
import re #For escaping characters in the settings.
|
|
|
|
## Writes g-code to a file.
|
|
#
|
|
# While this poses as a mesh writer, what this really does is take the g-code
|
|
# in the entire scene and write it to an output device. Since the g-code of a
|
|
# single mesh isn't separable from the rest what with rafts and travel moves
|
|
# and all, it doesn't make sense to write just a single mesh.
|
|
#
|
|
# So this plug-in takes the g-code that is stored in the root of the scene
|
|
# node tree, adds a bit of extra information about the profiles and writes
|
|
# that to the output device.
|
|
class GCodeWriter(MeshWriter):
|
|
## The file format version of the serialised g-code.
|
|
#
|
|
# It can only read settings with the same version as the version it was
|
|
# written with. If the file format is changed in a way that breaks reverse
|
|
# compatibility, increment this version number!
|
|
version = 1
|
|
|
|
## Dictionary that defines how characters are escaped when embedded in
|
|
# g-code.
|
|
#
|
|
# Note that the keys of this dictionary are regex strings. The values are
|
|
# not.
|
|
escape_characters = {
|
|
re.escape("\\"): "\\\\", # The escape character.
|
|
re.escape("\n"): "\\n", # Newlines. They break off the comment.
|
|
re.escape("\r"): "\\r" # Carriage return. Windows users may need this for visualisation in their editors.
|
|
}
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def write(self, stream, node, mode = MeshWriter.OutputMode.TextMode):
|
|
if mode != MeshWriter.OutputMode.TextMode:
|
|
Logger.log("e", "GCode Writer does not support non-text mode.")
|
|
return False
|
|
|
|
scene = Application.getInstance().getController().getScene()
|
|
gcode_list = getattr(scene, "gcode_list")
|
|
if gcode_list:
|
|
for gcode in gcode_list:
|
|
stream.write(gcode)
|
|
# Serialise the current container stack and put it at the end of the file.
|
|
settings = self._serialiseSettings(Application.getInstance().getGlobalContainerStack())
|
|
stream.write(settings)
|
|
return True
|
|
|
|
return False
|
|
|
|
## Serialises a container stack to prepare it for writing at the end of the
|
|
# g-code.
|
|
#
|
|
# The settings are serialised, and special characters (including newline)
|
|
# are escaped.
|
|
#
|
|
# \param settings A container stack to serialise.
|
|
# \return A serialised string of the settings.
|
|
def _serialiseSettings(self, settings):
|
|
prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
|
|
prefix_length = len(prefix)
|
|
|
|
all_settings = InstanceContainer("G-code-imported-profile") #Create a new 'profile' with ALL settings so that the slice can be precisely reproduced.
|
|
all_settings.setDefinition(settings.getBottom())
|
|
for key in settings.getAllKeys():
|
|
all_settings.setProperty(key, "value", settings.getProperty(key, "value")) #Just copy everything over to the setting instance.
|
|
serialised = all_settings.serialize()
|
|
|
|
# Escape characters that have a special meaning in g-code comments.
|
|
pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
|
|
# Perform the replacement with a regular expression.
|
|
serialised = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], serialised)
|
|
|
|
# Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
|
|
result = ""
|
|
|
|
# Lines have 80 characters, so the payload of each line is 80 - prefix.
|
|
for pos in range(0, len(serialised), 80 - prefix_length):
|
|
result += prefix + serialised[pos : pos + 80 - prefix_length] + "\n"
|
|
serialised = result
|
|
|
|
return serialised |