Convert doxygen to rst for GcodeReader, GcodeGzReader/Writer,

GCodeProfileReader
This commit is contained in:
Nino van Hooff 2020-05-08 15:58:51 +02:00
parent 6ca9b4678e
commit 40327c4259
5 changed files with 98 additions and 64 deletions

View file

@ -7,10 +7,13 @@ from UM.Mesh.MeshReader import MeshReader #The class we're extending/implementin
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType #To add the .gcode.gz files to the MIME type database. from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType #To add the .gcode.gz files to the MIME type database.
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
## A file reader that reads gzipped g-code.
#
# If you're zipping g-code, you might as well use gzip!
class GCodeGzReader(MeshReader): class GCodeGzReader(MeshReader):
"""A file reader that reads gzipped g-code.
If you're zipping g-code, you might as well use gzip!
"""
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
MimeTypeDatabase.addMimeType( MimeTypeDatabase.addMimeType(

View file

@ -13,26 +13,31 @@ from UM.Scene.SceneNode import SceneNode #For typing.
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
## A file writer that writes gzipped g-code.
#
# If you're zipping g-code, you might as well use gzip!
class GCodeGzWriter(MeshWriter): class GCodeGzWriter(MeshWriter):
"""A file writer that writes gzipped g-code.
If you're zipping g-code, you might as well use gzip!
"""
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(add_to_recent_files = False) super().__init__(add_to_recent_files = False)
## Writes the gzipped g-code to a stream.
#
# Note that even though the function accepts a collection of nodes, the
# entire scene is always written to the file since it is not possible to
# separate the g-code for just specific nodes.
#
# \param stream The stream to write the gzipped g-code to.
# \param nodes This is ignored.
# \param mode Additional information on what type of stream to use. This
# must always be binary mode.
# \return Whether the write was successful.
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode) -> bool: def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode) -> bool:
"""Writes the gzipped g-code to a stream.
Note that even though the function accepts a collection of nodes, the
entire scene is always written to the file since it is not possible to
separate the g-code for just specific nodes.
:param stream: The stream to write the gzipped g-code to.
:param nodes: This is ignored.
:param mode: Additional information on what type of stream to use. This
must always be binary mode.
:return: Whether the write was successful.
"""
if mode != MeshWriter.OutputMode.BinaryMode: if mode != MeshWriter.OutputMode.BinaryMode:
Logger.log("e", "GCodeGzWriter does not support text mode.") Logger.log("e", "GCodeGzWriter does not support text mode.")
self.setInformation(catalog.i18nc("@error:not supported", "GCodeGzWriter does not support text mode.")) self.setInformation(catalog.i18nc("@error:not supported", "GCodeGzWriter does not support text mode."))

View file

@ -12,40 +12,48 @@ catalog = i18nCatalog("cura")
from cura.ReaderWriters.ProfileReader import ProfileReader, NoProfileException from cura.ReaderWriters.ProfileReader import ProfileReader, NoProfileException
## A class that reads profile data from g-code files.
#
# It reads the profile data from g-code files and stores it in a new profile.
# This class currently does not process the rest of the g-code in any way.
class GCodeProfileReader(ProfileReader): class GCodeProfileReader(ProfileReader):
## The file format version of the serialized g-code. """A class that reads profile data from g-code files.
#
# It can only read settings with the same version as the version it was It reads the profile data from g-code files and stores it in a new profile.
# written with. If the file format is changed in a way that breaks reverse This class currently does not process the rest of the g-code in any way.
# compatibility, increment this version number! """
version = 3
version = 3
"""The file format version of the serialized 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!
"""
## 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 = { escape_characters = {
re.escape("\\\\"): "\\", #The escape character. re.escape("\\\\"): "\\", #The escape character.
re.escape("\\n"): "\n", #Newlines. They break off the comment. 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. re.escape("\\r"): "\r" #Carriage return. Windows users may need this for visualisation in their editors.
} }
"""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.
"""
## Initialises the g-code reader as a profile reader.
def __init__(self): def __init__(self):
"""Initialises the g-code reader as a profile reader."""
super().__init__() super().__init__()
## Reads a g-code file, loading the profile from it.
#
# \param file_name The name of the file to read the profile from.
# \return The profile that was in the specified file, if any. If the
# specified file was no g-code or contained no parsable profile, \code
# None \endcode is returned.
def read(self, file_name): def read(self, file_name):
"""Reads a g-code file, loading the profile from it.
:param file_name: The name of the file to read the profile from.
:return: The profile that was in the specified file, if any. If the
specified file was no g-code or contained no parsable profile,
None is returned.
"""
if file_name.split(".")[-1] != "gcode": if file_name.split(".")[-1] != "gcode":
return None return None
@ -94,22 +102,28 @@ class GCodeProfileReader(ProfileReader):
profiles.append(readQualityProfileFromString(profile_string)) profiles.append(readQualityProfileFromString(profile_string))
return profiles return profiles
## Unescape a string which has been escaped for use in a gcode comment.
# def unescapeGcodeComment(string: str) -> str:
# \param string The string to unescape. """Unescape a string which has been escaped for use in a gcode comment.
# \return \type{str} The unscaped string.
def unescapeGcodeComment(string): :param string: The string to unescape.
:return: The unescaped string.
"""
# Un-escape the serialized profile. # Un-escape the serialized profile.
pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys())) pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys()))
# Perform the replacement with a regular expression. # Perform the replacement with a regular expression.
return pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], string) return pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], string)
## Read in a profile from a serialized string.
# def readQualityProfileFromString(profile_string) -> InstanceContainer:
# \param profile_string The profile data in serialized form. """Read in a profile from a serialized string.
# \return \type{Profile} the resulting Profile object or None if it could not be read.
def readQualityProfileFromString(profile_string): :param profile_string: The profile data in serialized form.
:return: The resulting Profile object or None if it could not be read.
"""
# Create an empty profile - the id and name will be changed by the ContainerRegistry # Create an empty profile - the id and name will be changed by the ContainerRegistry
profile = InstanceContainer("") profile = InstanceContainer("")
try: try:

View file

@ -28,9 +28,8 @@ PositionOptional = NamedTuple("Position", [("x", Optional[float]), ("y", Optiona
Position = NamedTuple("Position", [("x", float), ("y", float), ("z", float), ("f", float), ("e", List[float])]) Position = NamedTuple("Position", [("x", float), ("y", float), ("z", float), ("f", float), ("e", List[float])])
## This parser is intended to interpret the common firmware codes among all the
# different flavors
class FlavorParser: class FlavorParser:
"""This parser is intended to interpret the common firmware codes among all the different flavors"""
def __init__(self) -> None: def __init__(self) -> None:
CuraApplication.getInstance().hideMessageSignal.connect(self._onHideMessage) CuraApplication.getInstance().hideMessageSignal.connect(self._onHideMessage)
@ -212,8 +211,9 @@ class FlavorParser:
# G0 and G1 should be handled exactly the same. # G0 and G1 should be handled exactly the same.
_gCode1 = _gCode0 _gCode1 = _gCode0
## Home the head.
def _gCode28(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position: def _gCode28(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position:
"""Home the head."""
return self._position( return self._position(
params.x if params.x is not None else position.x, params.x if params.x is not None else position.x,
params.y if params.y is not None else position.y, params.y if params.y is not None else position.y,
@ -221,21 +221,26 @@ class FlavorParser:
position.f, position.f,
position.e) position.e)
## Set the absolute positioning
def _gCode90(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position: def _gCode90(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position:
"""Set the absolute positioning"""
self._is_absolute_positioning = True self._is_absolute_positioning = True
self._is_absolute_extrusion = True self._is_absolute_extrusion = True
return position return position
## Set the relative positioning
def _gCode91(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position: def _gCode91(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position:
"""Set the relative positioning"""
self._is_absolute_positioning = False self._is_absolute_positioning = False
self._is_absolute_extrusion = False self._is_absolute_extrusion = False
return position return position
## Reset the current position to the values specified.
# For example: G92 X10 will set the X to 10 without any physical motion.
def _gCode92(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position: def _gCode92(self, position: Position, params: PositionOptional, path: List[List[Union[float, int]]]) -> Position:
"""Reset the current position to the values specified.
For example: G92 X10 will set the X to 10 without any physical motion.
"""
if params.e is not None: if params.e is not None:
# Sometimes a G92 E0 is introduced in the middle of the GCode so we need to keep those offsets for calculate the line_width # Sometimes a G92 E0 is introduced in the middle of the GCode so we need to keep those offsets for calculate the line_width
self._extrusion_length_offset[self._extruder_number] = position.e[self._extruder_number] - params.e self._extrusion_length_offset[self._extruder_number] = position.e[self._extruder_number] - params.e
@ -291,8 +296,9 @@ class FlavorParser:
_type_keyword = ";TYPE:" _type_keyword = ";TYPE:"
_layer_keyword = ";LAYER:" _layer_keyword = ";LAYER:"
## For showing correct x, y offsets for each extruder
def _extruderOffsets(self) -> Dict[int, List[float]]: def _extruderOffsets(self) -> Dict[int, List[float]]:
"""For showing correct x, y offsets for each extruder"""
result = {} result = {}
for extruder in ExtruderManager.getInstance().getActiveExtruderStacks(): for extruder in ExtruderManager.getInstance().getActiveExtruderStacks():
result[int(extruder.getMetaData().get("position", "0"))] = [ result[int(extruder.getMetaData().get("position", "0"))] = [

View file

@ -3,8 +3,10 @@
from . import FlavorParser from . import FlavorParser
## This parser is intended to interpret the RepRap Firmware g-code flavor.
class RepRapFlavorParser(FlavorParser.FlavorParser): class RepRapFlavorParser(FlavorParser.FlavorParser):
"""This parser is intended to interpret the RepRap Firmware g-code flavor."""
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -17,16 +19,20 @@ class RepRapFlavorParser(FlavorParser.FlavorParser):
# Set relative extrusion mode # Set relative extrusion mode
self._is_absolute_extrusion = False self._is_absolute_extrusion = False
## Set the absolute positioning
# RepRapFlavor code G90 sets position of X, Y, Z to absolute
# For absolute E, M82 is used
def _gCode90(self, position, params, path): def _gCode90(self, position, params, path):
"""Set the absolute positioning
RepRapFlavor code G90 sets position of X, Y, Z to absolute
For absolute E, M82 is used
"""
self._is_absolute_positioning = True self._is_absolute_positioning = True
return position return position
## Set the relative positioning
# RepRapFlavor code G91 sets position of X, Y, Z to relative
# For relative E, M83 is used
def _gCode91(self, position, params, path): def _gCode91(self, position, params, path):
"""Set the relative positioning
RepRapFlavor code G91 sets position of X, Y, Z to relative
For relative E, M83 is used
"""
self._is_absolute_positioning = False self._is_absolute_positioning = False
return position return position