chiark / gitweb /
Merge commit '870c4952fdb3268f5d4b6359d2e8046a6bb8df4f'
[cura.git] / Cura / util / gcodeInterpreter.py
1 from __future__ import absolute_import
2 import __init__
3
4 import sys
5 import math
6 import re
7 import os
8
9 from util import util3d
10
11 class gcodePath():
12         def __init__(self, newType, pathType, startPoint):
13                 self.type = newType
14                 self.pathType = pathType
15                 self.list = [startPoint]
16
17 class gcode():
18         def __init__(self):
19                 self.regMatch = {}
20                 self.layerList = []
21                 self.extrusionAmount = 0
22                 self.totalMoveTimeMinute = 0
23                 self.progressCallback = None
24         
25         def load(self, filename):
26                 self._fileSize = os.stat(filename).st_size
27                 gcodeFile = open(filename, 'r')
28                 self._load(gcodeFile)
29                 gcodeFile.close()
30         
31         def loadList(self, l):
32                 self._load(l)
33         
34         def _load(self, gcodeFile):
35                 filePos = 0
36                 pos = util3d.Vector3()
37                 posOffset = util3d.Vector3()
38                 currentE = 0.0
39                 totalExtrusion = 0.0
40                 maxExtrusion = 0.0
41                 totalMoveTimeMinute = 0.0
42                 scale = 1.0
43                 posAbs = True
44                 feedRate = 3600
45                 pathType = 'CUSTOM';
46                 startCodeDone = False
47                 currentLayer = []
48                 currentPath = gcodePath('move', pathType, pos.copy())
49                 currentPath.list[0].e = totalExtrusion
50                 currentLayer.append(currentPath)
51                 for line in gcodeFile:
52                         if self.progressCallback != None:
53                                 if filePos != gcodeFile.tell():
54                                         filePos = gcodeFile.tell()
55                                         self.progressCallback(float(filePos) / float(self._fileSize))
56                         
57                         #Parse Cura_SF comments
58                         if line.startswith(';TYPE:'):
59                                 pathType = line[6:].strip()
60                                 if pathType != "CUSTOM":
61                                         startCodeDone = True
62                                         
63                         if ';' in line:
64                                 #Slic3r GCode comment parser
65                                 comment = line[line.find(';')+1:].strip()
66                                 if comment == 'fill':
67                                         pathType = 'FILL'
68                                 elif comment == 'perimeter':
69                                         pathType = 'WALL-INNER'
70                                 elif comment == 'skirt':
71                                         pathType = 'SKIRT'
72                                 if pathType != "CUSTOM":
73                                         startCodeDone = True
74                                 line = line[0:line.find(';')]
75                         
76                         G = self.getCodeInt(line, 'G')
77                         if G is not None:
78                                 if G == 0 or G == 1:    #Move
79                                         x = self.getCodeFloat(line, 'X')
80                                         y = self.getCodeFloat(line, 'Y')
81                                         z = self.getCodeFloat(line, 'Z')
82                                         e = self.getCodeFloat(line, 'E')
83                                         f = self.getCodeFloat(line, 'F')
84                                         oldPos = pos.copy()
85                                         if x is not None:
86                                                 if posAbs:
87                                                         pos.x = x * scale
88                                                 else:
89                                                         pos.x += x * scale
90                                         if y is not None:
91                                                 if posAbs:
92                                                         pos.y = y * scale
93                                                 else:
94                                                         pos.y += y * scale
95                                         if z is not None:
96                                                 if posAbs:
97                                                         pos.z = z * scale
98                                                 else:
99                                                         pos.z += z * scale
100                                                 #Check if we have a new layer.
101                                                 if oldPos.z != pos.z and startCodeDone:
102                                                         self.layerList.append(currentLayer)
103                                                         currentLayer = []
104                                         if f is not None:
105                                                 feedRate = f
106                                         if x is not None or y is not None or z is not None:
107                                                 totalMoveTimeMinute += (oldPos - pos).vsize() / feedRate
108                                         moveType = 'move'
109                                         if e is not None:
110                                                 if posAbs:
111                                                         if e > currentE:
112                                                                 moveType = 'extrude'
113                                                         if e < currentE:
114                                                                 moveType = 'retract'
115                                                         totalExtrusion += e - currentE
116                                                         currentE = e
117                                                 else:
118                                                         if e > 0:
119                                                                 moveType = 'extrude'
120                                                         if e < 0:
121                                                                 moveType = 'retract'
122                                                         totalExtrusion += e
123                                                         currentE += e
124                                                 if totalExtrusion > maxExtrusion:
125                                                         maxExtrusion = totalExtrusion
126                                         if currentPath.type != moveType or currentPath.pathType != pathType:
127                                                 currentPath = gcodePath(moveType, pathType, currentPath.list[-1])
128                                                 currentLayer.append(currentPath)
129                                         newPos = pos.copy()
130                                         newPos.e = totalExtrusion
131                                         currentPath.list.append(newPos)
132                                 elif G == 20:   #Units are inches
133                                         scale = 25.4
134                                 elif G == 21:   #Units are mm
135                                         scale = 1.0
136                                 elif G == 28:   #Home
137                                         x = self.getCodeFloat(line, 'X')
138                                         y = self.getCodeFloat(line, 'Y')
139                                         z = self.getCodeFloat(line, 'Z')
140                                         if x is None and y is None and z is None:
141                                                 pos = util3d.Vector3()
142                                         else:
143                                                 if x is not None:
144                                                         pos.x = 0.0
145                                                 if y is not None:
146                                                         pos.y = 0.0
147                                                 if z is not None:
148                                                         pos.z = 0.0
149                                 elif G == 90:   #Absolute position
150                                         posAbs = True
151                                 elif G == 91:   #Relative position
152                                         posAbs = False
153                                 elif G == 92:
154                                         x = self.getCodeFloat(line, 'X')
155                                         y = self.getCodeFloat(line, 'Y')
156                                         z = self.getCodeFloat(line, 'Z')
157                                         e = self.getCodeFloat(line, 'E')
158                                         if e is not None:
159                                                 currentE = e
160                                         if x is not None:
161                                                 posOffset.x = pos.x + x
162                                         if y is not None:
163                                                 posOffset.y = pos.y + y
164                                         if z is not None:
165                                                 posOffset.z = pos.z + z
166                                 else:
167                                         print "Unknown G code:" + str(G)
168                         else:
169                                 M = self.getCodeInt(line, 'M')
170                                 if M is not None:
171                                         if M == 1:      #Message with possible wait (ignored)
172                                                 pass
173                                         elif M == 84:   #Disable step drivers
174                                                 pass
175                                         elif M == 92:   #Set steps per unit
176                                                 pass
177                                         elif M == 104:  #Set temperature, no wait
178                                                 pass
179                                         elif M == 105:  #Get temperature
180                                                 pass
181                                         elif M == 106:  #Enable fan
182                                                 pass
183                                         elif M == 107:  #Disable fan
184                                                 pass
185                                         elif M == 108:  #Extruder RPM (these should not be in the final GCode, but they are)
186                                                 pass
187                                         elif M == 109:  #Set temperature, wait
188                                                 pass
189                                         elif M == 113:  #Extruder PWM (these should not be in the final GCode, but they are)
190                                                 pass
191                                         else:
192                                                 print "Unknown M code:" + str(M)
193                 self.layerList.append(currentLayer)
194                 self.extrusionAmount = maxExtrusion
195                 self.totalMoveTimeMinute = totalMoveTimeMinute
196                 print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
197                 print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
198
199         def getCodeInt(self, line, code):
200                 if code not in self.regMatch:
201                         self.regMatch[code] = re.compile(code + '([^\s]+)')
202                 m = self.regMatch[code].search(line)
203                 if m == None:
204                         return None
205                 try:
206                         return int(m.group(1))
207                 except:
208                         return None
209
210         def getCodeFloat(self, line, code):
211                 if code not in self.regMatch:
212                         self.regMatch[code] = re.compile(code + '([^\s]+)')
213                 m = self.regMatch[code].search(line)
214                 if m == None:
215                         return None
216                 try:
217                         return float(m.group(1))
218                 except:
219                         return None
220
221 if __name__ == '__main__':
222         for filename in sys.argv[1:]:
223                 gcode().load(filename)
224