1 from __future__ import absolute_import
9 from util import util3d
12 def __init__(self, newType, pathType, layerNr, startPoint):
14 self.pathType = pathType
15 self.list = [startPoint]
16 self.layerNr = layerNr
23 self.extrusionAmount = 0
24 self.totalMoveTimeMinute = 0
25 self.progressCallback = None
27 def load(self, filename):
28 fileSize = os.stat(filename).st_size
30 gcodeFile = open(filename, 'r')
31 pos = util3d.Vector3()
32 posOffset = util3d.Vector3()
36 totalMoveTimeMinute = 0.0
42 layerNr = 0; #Note layer 0 will be the start code.
44 currentPath = gcodePath('move', pathType, layerNr, pos.copy())
45 currentPath.list[0].e = totalExtrusion
46 pathList.append(currentPath)
47 for line in gcodeFile:
48 if filePos != gcodeFile.tell():
49 filePos = gcodeFile.tell()
50 if self.progressCallback != None:
51 self.progressCallback(float(filePos) / float(fileSize))
52 if line.startswith(';TYPE:'):
53 pathType = line[6:].strip()
54 if pathType != "CUSTOM":
58 #Slic3r GCode comment parser
59 comment = line[line.find(';')+1:].strip()
62 elif comment == 'perimeter':
63 pathType = 'WALL-INNER'
64 elif comment == 'skirt':
66 if pathType != "CUSTOM":
68 line = line[0:line.find(';')]
70 G = self.getCodeInt(line, 'G')
72 if G == 0 or G == 1: #Move
73 x = self.getCodeFloat(line, 'X')
74 y = self.getCodeFloat(line, 'Y')
75 z = self.getCodeFloat(line, 'Z')
76 e = self.getCodeFloat(line, 'E')
77 f = self.getCodeFloat(line, 'F')
94 if oldPos.z != pos.z and startCodeDone:
98 if x is not None or y is not None or z is not None:
99 totalMoveTimeMinute += (oldPos - pos).vsize() / feedRate
107 totalExtrusion += e - currentE
116 if totalExtrusion > maxExtrusion:
117 maxExtrusion = totalExtrusion
118 if currentPath.type != moveType or currentPath.pathType != pathType:
119 currentPath = gcodePath(moveType, pathType, layerNr, currentPath.list[-1])
120 pathList.append(currentPath)
122 newPos.e = totalExtrusion
123 currentPath.list.append(newPos)
124 elif G == 20: #Units are inches
126 elif G == 21: #Units are mm
129 x = self.getCodeFloat(line, 'X')
130 y = self.getCodeFloat(line, 'Y')
131 z = self.getCodeFloat(line, 'Z')
132 if x is None and y is None and z is None:
133 pos = util3d.Vector3()
141 elif G == 90: #Absolute position
143 elif G == 91: #Relative position
146 x = self.getCodeFloat(line, 'X')
147 y = self.getCodeFloat(line, 'Y')
148 z = self.getCodeFloat(line, 'Z')
149 e = self.getCodeFloat(line, 'E')
153 posOffset.x = pos.x + x
155 posOffset.y = pos.y + y
157 posOffset.z = pos.z + z
159 print "Unknown G code:" + str(G)
161 M = self.getCodeInt(line, 'M')
163 if M == 1: #Message with possible wait (ignored)
165 elif M == 84: #Disable step drivers
167 elif M == 92: #Set steps per unit
169 elif M == 104: #Set temperature, no wait
171 elif M == 105: #Get temperature
173 elif M == 106: #Enable fan
175 elif M == 107: #Disable fan
177 elif M == 108: #Extruder RPM (these should not be in the final GCode, but they are)
179 elif M == 109: #Set temperature, wait
181 elif M == 113: #Extruder PWM (these should not be in the final GCode, but they are)
184 print "Unknown M code:" + str(M)
186 self.layerCount = layerNr
187 self.pathList = pathList
188 self.extrusionAmount = maxExtrusion
189 self.totalMoveTimeMinute = totalMoveTimeMinute
190 print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
191 print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
193 def getCodeInt(self, line, code):
194 if code not in self.regMatch:
195 self.regMatch[code] = re.compile(code + '([^\s]+)')
196 m = self.regMatch[code].search(line)
200 return int(m.group(1))
204 def getCodeFloat(self, line, code):
205 if code not in self.regMatch:
206 self.regMatch[code] = re.compile(code + '([^\s]+)')
207 m = self.regMatch[code].search(line)
211 return float(m.group(1))
215 if __name__ == '__main__':
216 for filename in sys.argv[1:]:
217 gcode().load(filename)