diff --git a/GcodeFileSplitter.py b/GcodeFileSplitter.py index 7620a72..e7e5cf4 100644 --- a/GcodeFileSplitter.py +++ b/GcodeFileSplitter.py @@ -10,8 +10,8 @@ logging.basicConfig(level=logging.DEBUG, FLOAT_OR_INT = r'-?\d+(\.\d*)?' +RE_ENGINE_VERSION = re.compile(r'SteamEngine (\d+\.\d+\.\d+)') RE_LAYER_COUNT = re.compile(r';LAYER_COUNT:(\d+)', re.MULTILINE) -RE_LAYER = re.compile(r'(;LAYER:\d+)', re.MULTILINE) RE_LAYER_NUMBER = re.compile(r';LAYER:(\d+)') RE_FOOTER_START = re.compile(r'(;TIME_ELAPSED:\d+\.\d+)\n[^;]', re.MULTILINE) RE_FAN_SPEED = re.compile(r'(M106 .+)\n', re.MULTILINE) @@ -19,6 +19,9 @@ RE_LAYER_ZHEIGHT = re.compile(r'G0 .*Z({})'.format(FLOAT_OR_INT)) RE_EXTRUSION = re.compile(r'G1 .*E({})'.format(FLOAT_OR_INT)) RE_MILLIMETERS = re.compile(r'({})mm'.format(FLOAT_OR_INT)) +RE_LAYER_V3 = re.compile(r'(;LAYER:\d+)', re.MULTILINE) +RE_LAYER_V4 = re.compile(r'^G0.* Z\d+\.?\d*$|^;LAYER:0$', re.MULTILINE) + class GcodeFileAnalyzer: @classmethod @@ -38,6 +41,7 @@ class GcodeFileAnalyzer: f.write('\n'.join(lines)) def __init__(self, lines): + self.curaVersion: tuple(int) = None self.lines: list(str) = lines self.header: list(str) = [] self.footer: list(str) = [] @@ -50,23 +54,15 @@ class GcodeFileAnalyzer: logging.info('Analyzing GCode') fullCode = '\n'.join(self.lines) + versionMatch = RE_ENGINE_VERSION.search(fullCode) + self.curaVersion = tuple(int(v) for v in versionMatch.group(1).split('.')) + # Find footer footerStartMatch = RE_FOOTER_START.search(fullCode) startOfFooterIndex = self.lines.index(footerStartMatch.group(1)) + 1 self.footer = self.lines[startOfFooterIndex:] - # Find layers - layerCountMatch = RE_LAYER_COUNT.search(fullCode) - self.layerCount = int(layerCountMatch.group(1)) - layersList = RE_LAYER.findall(fullCode) - - if len(layersList) != self.layerCount: - logging.warning('Gcode states wrong layer count {}. But found {} layers.' - .format(layerCountMatch.group(0), len(layersList))) - self.layerCount = len(layersList) - - layersIndices = [self.lines.index(layer) for layer in layersList] + [startOfFooterIndex] - self.layers = [Layer(self.lines[i:j]) for i, j in zip(layersIndices[:-1], layersIndices[1:])] + layersIndices = self.__FindLayers(fullCode, startOfFooterIndex) # Find header self.header = self.lines[:layersIndices[0]] @@ -76,6 +72,31 @@ class GcodeFileAnalyzer: if fanSpeedMatch: self.fanSpeedCode = fanSpeedMatch.group(1) + def __FindLayers(self, fullCode, startOfFooterIndex): + # Find layers + layerCountMatch = RE_LAYER_COUNT.search(fullCode) + self.layerCount = int(layerCountMatch.group(1)) + + if self.curaVersion < (4, 0, 0): + # Layers start at line ;LAYER: + layersList = RE_LAYER_V3.findall(fullCode) + + else: # Version > 4.0.0 + # Layers start already before line ;LAYER: + # (except for ;LAYER:0) + # Look for actual Z-position changes + layersList = RE_LAYER_V4.findall(fullCode) + layersList.remove(layersList[1]) # drop Z-change for layer 0, because it happens after the ;LAYER:0 line + + if len(layersList) != self.layerCount: + logging.warning('Gcode states wrong layer count {}. But found {} layers.' + .format(layerCountMatch.group(0), len(layersList))) + self.layerCount = len(layersList) + + layersIndices = [self.lines.index(layer) for layer in layersList] + [startOfFooterIndex] + self.layers = [Layer(self.lines[i:j]) for i, j in zip(layersIndices[:-1], layersIndices[1:])] + return layersIndices + def ExportSplitted(self, splitBeforeLayers: list) -> list: splitBeforeLayers = self._FindLayerIndices(splitBeforeLayers) assert all(l in range(1, self.layerCount) for l in splitBeforeLayers) @@ -165,9 +186,9 @@ class Layer: self.startExtrusion: float = 0 self.endExtrusion: float = 0 self.number: int = 0 - self.__AnalyzeGcode() + self.__AnalyzeLayerGcode() - def __AnalyzeGcode(self): + def __AnalyzeLayerGcode(self): """ Analyze layer GCode to find its Z height and extrusion position """ # Find Layer number @@ -211,5 +232,13 @@ if __name__ == '__main__': # GcodeFileAnalyzer.SplitFileAtLayers('test/BigL.gcode', ['2.8001mm', 300]) # GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Thingiverse\Murmelbahnen\The_Cyclone_triple_lift_triple_track_marble_machine\files\gcode\Marble_machine.gcode", # ['97.3mm', 405, 480]) - GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Thingiverse\Shuttle\Shuttle100.gcode", - ['87.60mm']) + # GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Thingiverse\Shuttle\Shuttle100.gcode", + # ['87.60mm']) + # GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Geschenke\Nudossi\NudossiDeckel_Yakup.gcode", + # [124]) + # GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Geschenke\Nudossi\NudossiDeckel_Harun.gcode", + # [124]) + # GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Thingiverse\MoonLamp\gcode\moon5inches.gcode", + # [100, 200, 400, 600, 700]) + GcodeFileAnalyzer.SplitFileAtLayers(r"Q:\DIY\3Dprint\Models\Pi\PiJukebox\bottom_2020-11-22\bottom.gcode", + [87])