chiark / gitweb /
71e26f0c65f030f5c698fc893ac15a12e9e3f2e9
[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, layerNr, startPoint):
13                 self.type = newType
14                 self.pathType = pathType
15                 self.list = [startPoint]
16                 self.layerNr = layerNr
17
18 class gcode():
19         def __init__(self):
20                 self.regMatch = {}
21                 self.layerCount = 0
22                 self.pathList = []
23                 self.extrusionAmount = 0
24                 self.totalMoveTimeMinute = 0
25                 self.progressCallback = None
26         
27         def load(self, filename):
28                 fileSize = os.stat(filename).st_size
29                 filePos = 0
30                 gcodeFile = open(filename, 'r')
31                 pos = util3d.Vector3()
32                 posOffset = util3d.Vector3()
33                 currentE = 0.0
34                 totalExtrusion = 0.0
35                 maxExtrusion = 0.0
36                 totalMoveTimeMinute = 0.0
37                 pathList = []
38                 scale = 1.0
39                 posAbs = True
40                 feedRate = 3600
41                 pathType = 'CUSTOM';
42                 layerNr = 0;    #Note layer 0 will be the start code.
43                 startCodeDone = False
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":
55                                         startCodeDone = True
56                                         
57                         if ';' in line:
58                                 #Slic3r GCode comment parser
59                                 comment = line[line.find(';')+1:].strip()
60                                 if comment == 'fill':
61                                         pathType = 'FILL'
62                                 elif comment == 'perimeter':
63                                         pathType = 'WALL-INNER'
64                                 elif comment == 'skirt':
65                                         pathType = 'SKIRT'
66                                 if pathType != "CUSTOM":
67                                         startCodeDone = True
68                                 line = line[0:line.find(';')]
69                         
70                         G = self.getCodeInt(line, 'G')
71                         if G is not None:
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')
78                                         oldPos = pos.copy()
79                                         if x is not None:
80                                                 if posAbs:
81                                                         pos.x = x * scale
82                                                 else:
83                                                         pos.x += x * scale
84                                         if y is not None:
85                                                 if posAbs:
86                                                         pos.y = y * scale
87                                                 else:
88                                                         pos.y += y * scale
89                                         if z is not None:
90                                                 if posAbs:
91                                                         pos.z = z * scale
92                                                 else:
93                                                         pos.z += z * scale
94                                                 if oldPos.z != pos.z and startCodeDone:
95                                                         layerNr += 1
96                                         if f is not None:
97                                                 feedRate = f
98                                         if x is not None or y is not None or z is not None:
99                                                 totalMoveTimeMinute += (oldPos - pos).vsize() / feedRate
100                                         moveType = 'move'
101                                         if e is not None:
102                                                 if posAbs:
103                                                         if e > currentE:
104                                                                 moveType = 'extrude'
105                                                         if e < currentE:
106                                                                 moveType = 'retract'
107                                                         totalExtrusion += e - currentE
108                                                         currentE = e
109                                                 else:
110                                                         if e > 0:
111                                                                 moveType = 'extrude'
112                                                         if e < 0:
113                                                                 moveType = 'retract'
114                                                         totalExtrusion += e
115                                                         currentE += e
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)
121                                         newPos = pos.copy()
122                                         newPos.e = totalExtrusion
123                                         currentPath.list.append(newPos)
124                                 elif G == 20:   #Units are inches
125                                         scale = 25.4
126                                 elif G == 21:   #Units are mm
127                                         scale = 1.0
128                                 elif G == 28:   #Home
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()
134                                         else:
135                                                 if x is not None:
136                                                         pos.x = 0.0
137                                                 if y is not None:
138                                                         pos.y = 0.0
139                                                 if z is not None:
140                                                         pos.z = 0.0
141                                 elif G == 90:   #Absolute position
142                                         posAbs = True
143                                 elif G == 91:   #Relative position
144                                         posAbs = False
145                                 elif G == 92:
146                                         x = self.getCodeFloat(line, 'X')
147                                         y = self.getCodeFloat(line, 'Y')
148                                         z = self.getCodeFloat(line, 'Z')
149                                         e = self.getCodeFloat(line, 'E')
150                                         if e is not None:
151                                                 currentE = e
152                                         if x is not None:
153                                                 posOffset.x = pos.x + x
154                                         if y is not None:
155                                                 posOffset.y = pos.y + y
156                                         if z is not None:
157                                                 posOffset.z = pos.z + z
158                                 else:
159                                         print "Unknown G code:" + str(G)
160                         else:
161                                 M = self.getCodeInt(line, 'M')
162                                 if M is not None:
163                                         if M == 1:      #Message with possible wait (ignored)
164                                                 pass
165                                         elif M == 84:   #Disable step drivers
166                                                 pass
167                                         elif M == 92:   #Set steps per unit
168                                                 pass
169                                         elif M == 104:  #Set temperature, no wait
170                                                 pass
171                                         elif M == 105:  #Get temperature
172                                                 pass
173                                         elif M == 106:  #Enable fan
174                                                 pass
175                                         elif M == 107:  #Disable fan
176                                                 pass
177                                         elif M == 108:  #Extruder RPM (these should not be in the final GCode, but they are)
178                                                 pass
179                                         elif M == 109:  #Set temperature, wait
180                                                 pass
181                                         elif M == 113:  #Extruder PWM (these should not be in the final GCode, but they are)
182                                                 pass
183                                         else:
184                                                 print "Unknown M code:" + str(M)
185                 gcodeFile.close()
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)
192
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)
197                 if m == None:
198                         return None
199                 try:
200                         return int(m.group(1))
201                 except:
202                         return None
203
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)
208                 if m == None:
209                         return None
210                 try:
211                         return float(m.group(1))
212                 except:
213                         return None
214
215 if __name__ == '__main__':
216         for filename in sys.argv[1:]:
217                 gcode().load(filename)
218