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