chiark / gitweb /
Change how the engine is interfaced from the python code. Put the GCode viewer in...
[cura.git] / Cura / gui / util / engineResultView.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import wx
4 import numpy
5 import math
6
7 import OpenGL
8 #OpenGL.ERROR_CHECKING = False
9 from OpenGL.GLU import *
10 from OpenGL.GL import *
11
12 from Cura.util import profile
13 from Cura.gui.util import opengl
14 from Cura.gui.util import openglGui
15
16 class engineResultView(object):
17         def __init__(self, parent):
18                 self._parent = parent
19                 self._result = None
20                 self._enabled = False
21                 self._layerVBOs = []
22                 self._layer20VBOs = []
23
24                 self.layerSelect = openglGui.glSlider(self._parent, 10000, 0, 1, (-1,-2), lambda : self._parent.QueueRefresh())
25
26         def setResult(self, result):
27                 if self._result == result:
28                         return
29
30                 self._result = result
31
32                 #Clean the saved VBO's
33                 for layer in self._layerVBOs:
34                         for typeName in layer.keys():
35                                 self._parent.glReleaseList.append(layer[typeName])
36                 for layer in self._layer20VBOs:
37                         for typeName in layer.keys():
38                                 self._parent.glReleaseList.append(layer[typeName])
39                 self._layerVBOs = []
40                 self._layer20VBOs = []
41
42         def setEnabled(self, enabled):
43                 self._enabled = enabled
44                 self.layerSelect.setHidden(not enabled)
45
46         def OnDraw(self):
47                 if not self._enabled:
48                         return
49
50                 if self._result is not None and self._result._polygons is not None:
51                         self.layerSelect.setRange(1, len(self._result._polygons))
52
53                 glPushMatrix()
54                 glEnable(GL_BLEND)
55                 if profile.getMachineSetting('machine_center_is_zero') != 'True':
56                         glTranslate(-profile.getMachineSettingFloat('machine_width') / 2, -profile.getMachineSettingFloat('machine_depth') / 2, 0)
57                 glLineWidth(2)
58
59                 layerNr = self.layerSelect.getValue()
60                 if layerNr == self.layerSelect.getMaxValue():
61                         layerNr = max(layerNr, len(self._result._polygons))
62                 viewZ = (layerNr - 1) * profile.getProfileSettingFloat('layer_height') + profile.getProfileSettingFloat('bottom_thickness')
63                 self._parent._viewTarget[2] = viewZ
64                 msize = max(profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'))
65                 lineTypeList = [('inset0',[1,0,0,1]), ('insetx',[0,1,0,1]), ('openoutline',[1,0,0,1]), ('skin',[1,1,0,1]), ('infill',[1,1,0,1]), ('support',[0,1,1,1]), ('outline',[0,0,0,1])]
66                 n = 0
67                 layers = None #self._result.getGCodeLayers()
68                 generatedVBO = False
69                 while n < layerNr:
70                         if layerNr - n > 30:
71                                 idx = n / 20
72                                 while len(self._layer20VBOs) < idx + 1:
73                                         self._layer20VBOs.append({})
74                                 if self._result is not None and self._result._polygons is not None and n + 20 < len(self._result._polygons):
75                                         layerVBOs = self._layer20VBOs[idx]
76                                         for typeName, color in lineTypeList:
77                                                 if typeName in self._result._polygons[n + 19]:
78                                                         if typeName not in self._layer20VBOs[idx]:
79                                                                 if generatedVBO:
80                                                                         continue
81                                                                 polygons = []
82                                                                 for i in xrange(0, 20):
83                                                                         if typeName in self._result._polygons[n + i]:
84                                                                                 polygons += self._result._polygons[n + i][typeName]
85                                                                 layerVBOs[typeName] = self._polygonsToVBO_lines(polygons)
86                                                                 generatedVBO = True
87                                                         glColor4f(color[0]*0.5,color[1]*0.5,color[2]*0.5,color[3])
88                                                         layerVBOs[typeName].render()
89                                 n += 20
90                         else:
91                                 while len(self._layerVBOs) < n + 1:
92                                         self._layerVBOs.append({})
93                                 c = 1.0 - ((layerNr - n) - 1) * 0.05
94                                 c = max(0.5, c)
95                                 layerVBOs = self._layerVBOs[n]
96                                 if layers is not None and n < len(layers):
97                                         if 'GCODE-FILL' not in layerVBOs:
98                                                 layerVBOs['GCODE-FILL'] = self._gcodeToVBO_quads(layers[n:n+1], 'FILL')
99                                         glColor4f(c,c,0,1)
100                                         layerVBOs['GCODE-FILL'].render()
101                                 elif self._result is not None and self._result._polygons is not None and n < len(self._result._polygons):
102                                         polygons = self._result._polygons[n]
103                                         for typeName, color in lineTypeList:
104                                                 if typeName in polygons:
105                                                         if typeName not in layerVBOs:
106                                                                 layerVBOs[typeName] = self._polygonsToVBO_lines(polygons[typeName])
107                                                         glColor4f(color[0]*c,color[1]*c,color[2]*c,color[3])
108                                                         layerVBOs[typeName].render()
109                                 n += 1
110                 glPopMatrix()
111                 if generatedVBO:
112                         self._parent._queueRefresh()
113
114         def _polygonsToVBO_lines(self, polygons):
115                 verts = numpy.zeros((0, 3), numpy.float32)
116                 indices = numpy.zeros((0), numpy.uint32)
117                 for poly in polygons:
118                         i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
119                         i[-1] = len(verts)
120                         i = numpy.dstack((i[0:-1],i[1:])).flatten()
121                         indices = numpy.concatenate((indices, i), 0)
122                         verts = numpy.concatenate((verts, poly), 0)
123                 return opengl.GLVBO(GL_LINES, verts, indicesArray=indices)
124
125         def _polygonsToVBO_quads(self, polygons):
126                 verts = numpy.zeros((0, 3), numpy.float32)
127                 indices = numpy.zeros((0), numpy.uint32)
128                 for poly in polygons:
129                         i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
130                         i2 = numpy.arange(len(verts) + len(poly), len(verts) + len(poly) + len(poly) + 1, 1, numpy.uint32)
131                         i[-1] = len(verts)
132                         i2[-1] = len(verts) + len(poly)
133                         i = numpy.dstack((i[0:-1],i2[0:-1],i2[1:],i[1:])).flatten()
134                         indices = numpy.concatenate((indices, i), 0)
135                         verts = numpy.concatenate((verts, poly), 0)
136                         verts = numpy.concatenate((verts, poly * numpy.array([1,0,1],numpy.float32) + numpy.array([0,-100,0],numpy.float32)), 0)
137                 return opengl.GLVBO(GL_QUADS, verts, indicesArray=indices)
138
139         def _gcodeToVBO_lines(self, gcodeLayers, extrudeType):
140                 if ':' in extrudeType:
141                         extruder = int(extrudeType[extrudeType.find(':')+1:])
142                         extrudeType = extrudeType[0:extrudeType.find(':')]
143                 else:
144                         extruder = None
145                 verts = numpy.zeros((0, 3), numpy.float32)
146                 indices = numpy.zeros((0), numpy.uint32)
147                 for layer in gcodeLayers:
148                         for path in layer:
149                                 if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
150                                         i = numpy.arange(len(verts), len(verts) + len(path['points']), 1, numpy.uint32)
151                                         i = numpy.dstack((i[0:-1],i[1:])).flatten()
152                                         indices = numpy.concatenate((indices, i), 0)
153                                         verts = numpy.concatenate((verts, path['points']))
154                 return opengl.GLVBO(GL_LINES, verts, indicesArray=indices)
155
156         def _gcodeToVBO_quads(self, gcodeLayers, extrudeType):
157                 useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
158                 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
159                 filamentArea = math.pi * filamentRadius * filamentRadius
160
161                 if ':' in extrudeType:
162                         extruder = int(extrudeType[extrudeType.find(':')+1:])
163                         extrudeType = extrudeType[0:extrudeType.find(':')]
164                 else:
165                         extruder = None
166
167                 verts = numpy.zeros((0, 3), numpy.float32)
168                 indices = numpy.zeros((0), numpy.uint32)
169                 for layer in gcodeLayers:
170                         for path in layer:
171                                 if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
172                                         a = path['points']
173                                         if extrudeType == 'FILL':
174                                                 a[:,2] += 0.01
175
176                                         #Construct the normals of each line 90deg rotated on the X/Y plane
177                                         normals = a[1:] - a[:-1]
178                                         lengths = numpy.sqrt(normals[:,0]**2 + normals[:,1]**2)
179                                         normals[:,0], normals[:,1] = -normals[:,1] / lengths, normals[:,0] / lengths
180                                         normals[:,2] /= lengths
181
182                                         ePerDist = path['extrusion'][1:] / lengths
183                                         if useFilamentArea:
184                                                 lineWidth = ePerDist / path['layerThickness'] / 2.0
185                                         else:
186                                                 lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
187
188                                         normals[:,0] *= lineWidth
189                                         normals[:,1] *= lineWidth
190
191                                         b = numpy.zeros((len(a)-1, 0), numpy.float32)
192                                         b = numpy.concatenate((b, a[1:] + normals), 1)
193                                         b = numpy.concatenate((b, a[1:] - normals), 1)
194                                         b = numpy.concatenate((b, a[:-1] - normals), 1)
195                                         b = numpy.concatenate((b, a[:-1] + normals), 1)
196                                         b = b.reshape((len(b) * 4, 3))
197
198                                         i = numpy.arange(len(verts), len(verts) + len(b), 1, numpy.uint32)
199
200                                         verts = numpy.concatenate((verts, b))
201                                         indices = numpy.concatenate((indices, i))
202                 return opengl.GLVBO(GL_QUADS, verts, indicesArray=indices)
203
204         def OnKeyChar(self, keyCode):
205                 if not self._enabled:
206                         return
207
208                 if wx.GetKeyState(wx.WXK_SHIFT) or wx.GetKeyState(wx.WXK_CONTROL):
209                         if keyCode == wx.WXK_UP:
210                                 self.layerSelect.setValue(self.layerSelect.getValue() + 1)
211                                 self._parent.QueueRefresh()
212                                 return True
213                         elif keyCode == wx.WXK_DOWN:
214                                 self.layerSelect.setValue(self.layerSelect.getValue() - 1)
215                                 self._parent.QueueRefresh()
216                                 return True
217                         elif keyCode == wx.WXK_PAGEUP:
218                                 self.layerSelect.setValue(self.layerSelect.getValue() + 10)
219                                 self._parent.QueueRefresh()
220                                 return True
221                         elif keyCode == wx.WXK_PAGEDOWN:
222                                 self.layerSelect.setValue(self.layerSelect.getValue() - 10)
223                                 self._parent.QueueRefresh()
224                                 return True
225                 return False
226
227                 # if self.viewMode == 'gcode' and self._gcode is not None:
228                 #       try:
229                 #               self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
230                 #       except:
231                 #               pass
232
233         # def _loadGCode(self):
234         #       self._gcode.progressCallback = self._gcodeLoadCallback
235         #       if self._gcodeFilename is not None:
236         #               self._gcode.load(self._gcodeFilename)
237         #       else:
238         #               self._gcode.load(self._gcodeData)
239         #
240         # def _gcodeLoadCallback(self, progress):
241         #       if not self or self._gcode is None:
242         #               return True
243         #       if len(self._gcode.layerList) % 15 == 0:
244         #               time.sleep(0.1)
245         #       if self._gcode is None:
246         #               return True
247         #       self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
248         #       if self.viewMode == 'gcode':
249         #               self._queueRefresh()
250         #       return False
251
252                         # if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
253                         #       glDisable(GL_DEPTH_TEST)
254                         #       glPushMatrix()
255                         #       glLoadIdentity()
256                         #       glTranslate(0,-4,-10)
257                         #       glColor4ub(60,60,60,255)
258                         #       opengl.glDrawStringCenter(_("Loading toolpath for visualization..."))
259                         #       glPopMatrix()
260
261
262 # if self._gcode is not None:
263 #                       self._gcode = None
264 #                       for layerVBOlist in self._gcodeVBOs:
265 #                               for vbo in layerVBOlist:
266 #                                       self.glReleaseList.append(vbo)
267 #                       self._gcodeVBOs = []
268
269                         # if self._gcode is not None and self._gcode.layerList is None:
270                         #       self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
271                         #       self._gcodeLoadThread.daemon = True
272                         #       self._gcodeLoadThread.start()
273                         #
274
275                         #
276                         # if self._gcode is not None and self._gcode.layerList is not None:
277                         #       glPushMatrix()
278                         #       if profile.getMachineSetting('machine_center_is_zero') != 'True':
279                         #               glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
280                         #       t = time.time()
281                         #       drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
282                         #       for n in xrange(0, drawUpTill):
283                         #               c = 1.0 - float(drawUpTill - n) / 15
284                         #               c = max(0.3, c)
285                         #               if len(self._gcodeVBOs) < n + 1:
286                         #                       self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
287                         #                       if time.time() - t > 0.5:
288                         #                               self.QueueRefresh()
289                         #                               break
290                         #               #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
291                         #               if n == drawUpTill - 1:
292                         #                       if len(self._gcodeVBOs[n]) < 9:
293                         #                               self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
294                         #                       glColor3f(c, 0, 0)
295                         #                       self._gcodeVBOs[n][8].render(GL_QUADS)
296                         #                       glColor3f(c/2, 0, c)
297                         #                       self._gcodeVBOs[n][9].render(GL_QUADS)
298                         #                       glColor3f(0, c, c/2)
299                         #                       self._gcodeVBOs[n][10].render(GL_QUADS)
300                         #                       glColor3f(c, 0, 0)
301                         #                       self._gcodeVBOs[n][11].render(GL_QUADS)
302                         #
303                         #                       glColor3f(0, c, 0)
304                         #                       self._gcodeVBOs[n][12].render(GL_QUADS)
305                         #                       glColor3f(c/2, c/2, 0.0)
306                         #                       self._gcodeVBOs[n][13].render(GL_QUADS)
307                         #                       glColor3f(0, c, c)
308                         #                       self._gcodeVBOs[n][14].render(GL_QUADS)
309                         #                       self._gcodeVBOs[n][15].render(GL_QUADS)
310                         #                       glColor3f(0, 0, c)
311                         #                       self._gcodeVBOs[n][16].render(GL_LINES)
312                         #               else:
313                         #                       glColor3f(c, 0, 0)
314                         #                       self._gcodeVBOs[n][0].render(GL_LINES)
315                         #                       glColor3f(c/2, 0, c)
316                         #                       self._gcodeVBOs[n][1].render(GL_LINES)
317                         #                       glColor3f(0, c, c/2)
318                         #                       self._gcodeVBOs[n][2].render(GL_LINES)
319                         #                       glColor3f(c, 0, 0)
320                         #                       self._gcodeVBOs[n][3].render(GL_LINES)
321                         #
322                         #                       glColor3f(0, c, 0)
323                         #                       self._gcodeVBOs[n][4].render(GL_LINES)
324                         #                       glColor3f(c/2, c/2, 0.0)
325                         #                       self._gcodeVBOs[n][5].render(GL_LINES)
326                         #                       glColor3f(0, c, c)
327                         #                       self._gcodeVBOs[n][6].render(GL_LINES)
328                         #                       self._gcodeVBOs[n][7].render(GL_LINES)
329                         #       glPopMatrix()
330         #
331         # def _generateGCodeVBOs(self, layer):
332         #       ret = []
333         #       for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
334         #               if ':' in extrudeType:
335         #                       extruder = int(extrudeType[extrudeType.find(':')+1:])
336         #                       extrudeType = extrudeType[0:extrudeType.find(':')]
337         #               else:
338         #                       extruder = None
339         #               pointList = numpy.zeros((0,3), numpy.float32)
340         #               for path in layer:
341         #                       if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
342         #                               a = path['points']
343         #                               a = numpy.concatenate((a[:-1], a[1:]), 1)
344         #                               a = a.reshape((len(a) * 2, 3))
345         #                               pointList = numpy.concatenate((pointList, a))
346         #               ret.append(opengl.GLVBO(pointList))
347         #       return ret
348         #
349         # def _generateGCodeVBOs2(self, layer):
350         #       filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
351         #       filamentArea = math.pi * filamentRadius * filamentRadius
352         #       useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
353         #
354         #       ret = []
355         #       for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
356         #               if ':' in extrudeType:
357         #                       extruder = int(extrudeType[extrudeType.find(':')+1:])
358         #                       extrudeType = extrudeType[0:extrudeType.find(':')]
359         #               else:
360         #                       extruder = None
361         #               pointList = numpy.zeros((0,3), numpy.float32)
362         #               for path in layer:
363         #                       if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
364         #                               a = path['points']
365         #                               if extrudeType == 'FILL':
366         #                                       a[:,2] += 0.01
367         #
368         #                               normal = a[1:] - a[:-1]
369         #                               lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
370         #                               normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
371         #                               normal[:,2] /= lens
372         #
373         #                               ePerDist = path['extrusion'][1:] / lens
374         #                               if useFilamentArea:
375         #                                       lineWidth = ePerDist / path['layerThickness'] / 2.0
376         #                               else:
377         #                                       lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
378         #
379         #                               normal[:,0] *= lineWidth
380         #                               normal[:,1] *= lineWidth
381         #
382         #                               b = numpy.zeros((len(a)-1, 0), numpy.float32)
383         #                               b = numpy.concatenate((b, a[1:] + normal), 1)
384         #                               b = numpy.concatenate((b, a[1:] - normal), 1)
385         #                               b = numpy.concatenate((b, a[:-1] - normal), 1)
386         #                               b = numpy.concatenate((b, a[:-1] + normal), 1)
387         #                               b = b.reshape((len(b) * 4, 3))
388         #
389         #                               if len(a) > 2:
390         #                                       normal2 = normal[:-1] + normal[1:]
391         #                                       lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
392         #                                       normal2[:,0] /= lens2
393         #                                       normal2[:,1] /= lens2
394         #                                       normal2[:,0] *= lineWidth[:-1]
395         #                                       normal2[:,1] *= lineWidth[:-1]
396         #
397         #                                       c = numpy.zeros((len(a)-2, 0), numpy.float32)
398         #                                       c = numpy.concatenate((c, a[1:-1]), 1)
399         #                                       c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1)
400         #                                       c = numpy.concatenate((c, a[1:-1]+normal2), 1)
401         #                                       c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1)
402         #
403         #                                       c = numpy.concatenate((c, a[1:-1]), 1)
404         #                                       c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
405         #                                       c = numpy.concatenate((c, a[1:-1]-normal2), 1)
406         #                                       c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
407         #
408         #                                       c = c.reshape((len(c) * 8, 3))
409         #
410         #                                       pointList = numpy.concatenate((pointList, b, c))
411         #                               else:
412         #                                       pointList = numpy.concatenate((pointList, b))
413         #               ret.append(opengl.GLVBO(pointList))
414         #
415         #       pointList = numpy.zeros((0,3), numpy.float32)
416         #       for path in layer:
417         #               if path['type'] == 'move':
418         #                       a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
419         #                       a = numpy.concatenate((a[:-1], a[1:]), 1)
420         #                       a = a.reshape((len(a) * 2, 3))
421         #                       pointList = numpy.concatenate((pointList, a))
422         #               if path['type'] == 'retract':
423         #                       a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
424         #                       a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
425         #                       a = a.reshape((len(a) * 2, 3))
426         #                       pointList = numpy.concatenate((pointList, a))
427         #       ret.append(opengl.GLVBO(pointList))
428         #
429         #       return ret