From af06096e080d7fae92b66d20b8d8f8b98ac8bd52 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Wed, 9 May 2018 11:13:53 +0200 Subject: [PATCH 1/3] Add typing As per code style. Contributes to issue CURA-5330. --- plugins/GCodeReader/FlavorParser.py | 48 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/plugins/GCodeReader/FlavorParser.py b/plugins/GCodeReader/FlavorParser.py index 2679cc23a4..91f68db743 100644 --- a/plugins/GCodeReader/FlavorParser.py +++ b/plugins/GCodeReader/FlavorParser.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application @@ -23,12 +23,16 @@ from cura.Settings.ExtruderManager import ExtruderManager import numpy import math import re +from typing import Dict, List, NamedTuple, Optional, Union from collections import namedtuple -# This parser is intented for interpret the common firmware codes among all the different flavors +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: - def __init__(self): + def __init__(self) -> None: Application.getInstance().hideMessageSignal.connect(self._onHideMessage) self._cancelled = False self._message = None @@ -45,7 +49,7 @@ class FlavorParser: Preferences.getInstance().addPreference("gcodereader/show_caution", True) - def _clearValues(self): + def _clearValues(self) -> None: self._extruder_number = 0 self._extrusion_length_offset = [0] self._layer_type = LayerPolygon.Inset0Type @@ -57,7 +61,7 @@ class FlavorParser: self._is_absolute_extrusion = True # It can become absolute (M82, default) or relative (M83) @staticmethod - def _getValue(line, code): + def _getValue(line: str, code: str) -> Optional[Union[str, int, float]]: n = line.find(code) if n < 0: return None @@ -72,29 +76,29 @@ class FlavorParser: except: return None - def _getInt(self, line, code): + def _getInt(self, line: str, code: str) -> Optional[int]: value = self._getValue(line, code) try: return int(value) except: return None - def _getFloat(self, line, code): + def _getFloat(self, line: str, code: str) -> Optional[float]: value = self._getValue(line, code) try: return float(value) except: return None - def _onHideMessage(self, message): + def _onHideMessage(self, message: str) -> None: if message == self._message: self._cancelled = True @staticmethod - def _getNullBoundingBox(): + def _getNullBoundingBox() -> AxisAlignedBox: return AxisAlignedBox(minimum=Vector(0, 0, 0), maximum=Vector(10, 10, 10)) - def _createPolygon(self, layer_thickness, path, extruder_offsets): + def _createPolygon(self, layer_thickness: float, path: List[Position], extruder_offsets: List[float]) -> bool: countvalid = 0 for point in path: if point[5] > 0: @@ -140,12 +144,12 @@ class FlavorParser: this_layer.polygons.append(this_poly) return True - def _createEmptyLayer(self, layer_number): + def _createEmptyLayer(self, layer_number: int) -> None: self._layer_data_builder.addLayer(layer_number) self._layer_data_builder.setLayerHeight(layer_number, 0) self._layer_data_builder.setLayerThickness(layer_number, 0) - def _calculateLineWidth(self, current_point, previous_point, current_extrusion, previous_extrusion, layer_thickness): + def _calculateLineWidth(self, current_point: Position, previous_point: Position, current_extrusion: float, previous_extrusion: float, layer_thickness: float) -> float: # Area of the filament Af = (self._filament_diameter / 2) ** 2 * numpy.pi # Length of the extruded filament @@ -167,7 +171,7 @@ class FlavorParser: return 0.35 return line_width - def _gCode0(self, position, params, path): + def _gCode0(self, position: Position, params: Position, path: List[Position]) -> Position: x, y, z, f, e = position if self._is_absolute_positioning: @@ -203,7 +207,7 @@ class FlavorParser: _gCode1 = _gCode0 ## Home the head. - def _gCode28(self, position, params, path): + def _gCode28(self, position: Position, params: Position, path: List[Position]) -> Position: return self._position( params.x if params.x is not None else position.x, params.y if params.y is not None else position.y, @@ -212,20 +216,20 @@ class FlavorParser: position.e) ## Set the absolute positioning - def _gCode90(self, position, params, path): + def _gCode90(self, position: Position, params: Position, path: List[Position]) -> Position: self._is_absolute_positioning = True self._is_absolute_extrusion = True return position ## Set the relative positioning - def _gCode91(self, position, params, path): + def _gCode91(self, position: Position, params: Position, path: List[Position]) -> Position: self._is_absolute_positioning = False self._is_absolute_extrusion = False 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, params, path): + def _gCode92(self, position: Position, params: Position, path: List[Position]) -> Position: 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 self._extrusion_length_offset[self._extruder_number] += position.e[self._extruder_number] - params.e @@ -237,7 +241,7 @@ class FlavorParser: params.f if params.f is not None else position.f, position.e) - def processGCode(self, G, line, position, path): + def processGCode(self, G: int, line: str, position: Position, path: List[Position]) -> Position: func = getattr(self, "_gCode%s" % G, None) line = line.split(";", 1)[0] # Remove comments (if any) if func is not None: @@ -264,21 +268,21 @@ class FlavorParser: return func(position, params, path) return position - def processTCode(self, T, line, position, path): + def processTCode(self, T: int, line: str, position: Position, path: List[Position]) -> Position: self._extruder_number = T if self._extruder_number + 1 > len(position.e): self._extrusion_length_offset.extend([0] * (self._extruder_number - len(position.e) + 1)) position.e.extend([0] * (self._extruder_number - len(position.e) + 1)) return position - def processMCode(self, M, line, position, path): + def processMCode(self, M: int, line: str, position: Position, path: List[Position]) -> Position: pass _type_keyword = ";TYPE:" _layer_keyword = ";LAYER:" ## For showing correct x, y offsets for each extruder - def _extruderOffsets(self): + def _extruderOffsets(self) -> Dict[int, float]: result = {} for extruder in ExtruderManager.getInstance().getExtruderStacks(): result[int(extruder.getMetaData().get("position", "0"))] = [ @@ -286,7 +290,7 @@ class FlavorParser: extruder.getProperty("machine_nozzle_offset_y", "value")] return result - def processGCodeStream(self, stream): + def processGCodeStream(self, stream: str) -> Optional[CuraSceneNode]: Logger.log("d", "Preparing to load GCode") self._cancelled = False # We obtain the filament diameter from the selected extruder to calculate line widths From fb2a8c8d57ae60f235acbd97d19aec66f4379367 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Wed, 9 May 2018 11:29:45 +0200 Subject: [PATCH 2/3] Fix typing of paths There is still something up with the E values. Most probably an actual bug. We'll investigate. Contributes to issue CURA-5330. --- plugins/GCodeReader/FlavorParser.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/GCodeReader/FlavorParser.py b/plugins/GCodeReader/FlavorParser.py index 91f68db743..a0b112bc5e 100644 --- a/plugins/GCodeReader/FlavorParser.py +++ b/plugins/GCodeReader/FlavorParser.py @@ -26,7 +26,7 @@ import re from typing import Dict, List, NamedTuple, Optional, Union from collections import namedtuple -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", float)]) ## This parser is intended to interpret the common firmware codes among all the # different flavors @@ -98,7 +98,7 @@ class FlavorParser: def _getNullBoundingBox() -> AxisAlignedBox: return AxisAlignedBox(minimum=Vector(0, 0, 0), maximum=Vector(10, 10, 10)) - def _createPolygon(self, layer_thickness: float, path: List[Position], extruder_offsets: List[float]) -> bool: + def _createPolygon(self, layer_thickness: float, path: List[List[Union[float, int]]], extruder_offsets: List[float]) -> bool: countvalid = 0 for point in path: if point[5] > 0: @@ -171,7 +171,7 @@ class FlavorParser: return 0.35 return line_width - def _gCode0(self, position: Position, params: Position, path: List[Position]) -> Position: + def _gCode0(self, position: Position, params: Position, path: List[List[Union[float, int]]]) -> Position: x, y, z, f, e = position if self._is_absolute_positioning: @@ -207,7 +207,7 @@ class FlavorParser: _gCode1 = _gCode0 ## Home the head. - def _gCode28(self, position: Position, params: Position, path: List[Position]) -> Position: + def _gCode28(self, position: Position, params: Position, path: List[List[Union[float, int]]]) -> Position: return self._position( params.x if params.x is not None else position.x, params.y if params.y is not None else position.y, @@ -216,20 +216,20 @@ class FlavorParser: position.e) ## Set the absolute positioning - def _gCode90(self, position: Position, params: Position, path: List[Position]) -> Position: + def _gCode90(self, position: Position, params: Position, path: List[List[Union[float, int]]]) -> Position: self._is_absolute_positioning = True self._is_absolute_extrusion = True return position ## Set the relative positioning - def _gCode91(self, position: Position, params: Position, path: List[Position]) -> Position: + def _gCode91(self, position: Position, params: Position, path: List[List[Union[float, int]]]) -> Position: self._is_absolute_positioning = False self._is_absolute_extrusion = False 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: Position, path: List[Position]) -> Position: + def _gCode92(self, position: Position, params: Position, path: List[List[Union[float, int]]]) -> Position: 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 self._extrusion_length_offset[self._extruder_number] += position.e[self._extruder_number] - params.e @@ -241,7 +241,7 @@ class FlavorParser: params.f if params.f is not None else position.f, position.e) - def processGCode(self, G: int, line: str, position: Position, path: List[Position]) -> Position: + def processGCode(self, G: int, line: str, position: Position, path: List[List[Union[float, int]]]) -> Position: func = getattr(self, "_gCode%s" % G, None) line = line.split(";", 1)[0] # Remove comments (if any) if func is not None: @@ -268,7 +268,7 @@ class FlavorParser: return func(position, params, path) return position - def processTCode(self, T: int, line: str, position: Position, path: List[Position]) -> Position: + def processTCode(self, T: int, line: str, position: Position, path: List[List[Union[float, int]]]) -> Position: self._extruder_number = T if self._extruder_number + 1 > len(position.e): self._extrusion_length_offset.extend([0] * (self._extruder_number - len(position.e) + 1)) @@ -282,7 +282,7 @@ class FlavorParser: _layer_keyword = ";LAYER:" ## For showing correct x, y offsets for each extruder - def _extruderOffsets(self) -> Dict[int, float]: + def _extruderOffsets(self) -> Dict[int, List[float]]: result = {} for extruder in ExtruderManager.getInstance().getExtruderStacks(): result[int(extruder.getMetaData().get("position", "0"))] = [ From 6772dc9ea79736085773398c1c8917c8bc50d252 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Wed, 9 May 2018 13:25:15 +0200 Subject: [PATCH 3/3] Show g-code in position it would print Rather than trying to retrieve from the g-code what the position was that it was originally sliced. It was trying to find whether it was sliced for a printer with center_is_zero by seeing if there are any negative coordinates in the g-code, which was faulty. Now we don't even try to do that any more. We just find where the print would end up if it were printed with the currently selected printer. Contributes to issue CURA-5068 and fixes #3634. --- plugins/GCodeReader/FlavorParser.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/plugins/GCodeReader/FlavorParser.py b/plugins/GCodeReader/FlavorParser.py index a0b112bc5e..9a043f4961 100644 --- a/plugins/GCodeReader/FlavorParser.py +++ b/plugins/GCodeReader/FlavorParser.py @@ -56,7 +56,6 @@ class FlavorParser: self._layer_number = 0 self._previous_z = 0 self._layer_data_builder = LayerDataBuilder.LayerDataBuilder() - self._center_is_zero = False self._is_absolute_positioning = True # It can be absolute (G90) or relative (G91) self._is_absolute_extrusion = True # It can become absolute (M82, default) or relative (M83) @@ -262,8 +261,6 @@ class FlavorParser: f = float(item[1:]) / 60 if item[0] == "E": e = float(item[1:]) - if self._is_absolute_positioning and ((x is not None and x < 0) or (y is not None and y < 0)): - self._center_is_zero = True params = self._position(x, y, z, f, e) return func(position, params, path) return position @@ -275,7 +272,7 @@ class FlavorParser: position.e.extend([0] * (self._extruder_number - len(position.e) + 1)) return position - def processMCode(self, M: int, line: str, position: Position, path: List[Position]) -> Position: + def processMCode(self, M: int, line: str, position: Position, path: List[List[Union[float, int]]]) -> Position: pass _type_keyword = ";TYPE:" @@ -458,10 +455,9 @@ class FlavorParser: Logger.log("w", "File doesn't contain any valid layers") settings = Application.getInstance().getGlobalContainerStack() - machine_width = settings.getProperty("machine_width", "value") - machine_depth = settings.getProperty("machine_depth", "value") - - if not self._center_is_zero: + if not settings.getProperty("machine_center_is_zero", "value"): + machine_width = settings.getProperty("machine_width", "value") + machine_depth = settings.getProperty("machine_depth", "value") scene_node.setPosition(Vector(-machine_width / 2, 0, machine_depth / 2)) Logger.log("d", "GCode loading finished")