1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
8 #OpenGL.ERROR_CHECKING = False
9 from OpenGL.GLU import *
10 from OpenGL.GL import *
12 from Cura.util import profile
13 from Cura.gui.util import openglHelpers
14 from Cura.gui.util import openglGui
16 class engineResultView(object):
17 def __init__(self, parent):
21 self._gcodeLoadProgress = 0
23 self._layer20VBOs = []
25 self.layerSelect = openglGui.glSlider(self._parent, 10000, 0, 1, (-1,-2), lambda : self._parent.QueueRefresh())
27 def setResult(self, result):
28 if self._result == result:
33 #Clean the saved VBO's
34 for layer in self._layerVBOs:
35 for typeName in layer.keys():
36 self._parent.glReleaseList.append(layer[typeName])
37 for layer in self._layer20VBOs:
38 for typeName in layer.keys():
39 self._parent.glReleaseList.append(layer[typeName])
41 self._layer20VBOs = []
43 def setEnabled(self, enabled):
44 self._enabled = enabled
45 self.layerSelect.setHidden(not enabled)
47 def _gcodeLoadCallback(self, result, progress):
48 if result != self._result:
49 #Abort loading from this thread.
51 self._gcodeLoadProgress = progress
52 self._parent._queueRefresh()
60 if result is not None and result._polygons is not None:
61 self.layerSelect.setRange(1, len(result._polygons))
62 if result is not None:
63 gcodeLayers = result.getGCodeLayers(self._gcodeLoadCallback)
69 if profile.getMachineSetting('machine_center_is_zero') != 'True':
70 glTranslate(-profile.getMachineSettingFloat('machine_width') / 2, -profile.getMachineSettingFloat('machine_depth') / 2, 0)
73 layerNr = self.layerSelect.getValue()
74 if layerNr == self.layerSelect.getMaxValue():
75 layerNr = max(layerNr, len(result._polygons))
76 viewZ = (layerNr - 1) * profile.getProfileSettingFloat('layer_height') + profile.getProfileSettingFloat('bottom_thickness')
77 self._parent._viewTarget[2] = viewZ
78 msize = max(profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'))
80 ('inset0', 'WALL-OUTER', [1,0,0,1]),
81 ('insetx', 'WALL-INNER', [0,1,0,1]),
82 ('openoutline', None, [1,0,0,1]),
83 ('skin', 'FILL', [1,1,0,1]),
84 ('infill', None, [1,1,0,1]),
85 ('support', 'SUPPORT', [0,1,1,1]),
86 ('skirt', 'SKIRT', [0,1,1,1]),
87 ('outline', None, [0,0,0,1])
92 if layerNr - n > 30 and n % 20 == 0:
94 while len(self._layer20VBOs) < idx + 1:
95 self._layer20VBOs.append({})
96 if result is not None and result._polygons is not None and n + 20 < len(result._polygons):
97 layerVBOs = self._layer20VBOs[idx]
98 for typeName, typeNameGCode, color in lineTypeList:
99 if (typeName in result._polygons[n + 19]) or (typeName == 'skirt' and typeName in result._polygons[n]):
100 if typeName not in layerVBOs:
104 for i in xrange(0, 20):
105 if typeName in result._polygons[n + i]:
106 polygons += result._polygons[n + i][typeName]
107 layerVBOs[typeName] = self._polygonsToVBO_lines(polygons)
109 glColor4f(color[0]*0.5,color[1]*0.5,color[2]*0.5,color[3])
110 layerVBOs[typeName].render()
113 c = 1.0 - ((layerNr - n) - 1) * 0.05
115 while len(self._layerVBOs) < n + 1:
116 self._layerVBOs.append({})
117 layerVBOs = self._layerVBOs[n]
118 if gcodeLayers is not None and layerNr - 10 < n < (len(gcodeLayers) - 1):
119 for typeNamePolygons, typeName, color in lineTypeList:
122 if 'GCODE-' + typeName not in layerVBOs:
123 layerVBOs['GCODE-' + typeName] = self._gcodeToVBO_quads(gcodeLayers[n+1:n+2], typeName)
124 glColor4f(color[0]*c,color[1]*c,color[2]*c,color[3])
125 layerVBOs['GCODE-' + typeName].render()
128 if 'GCODE-MOVE' not in layerVBOs:
129 layerVBOs['GCODE-MOVE'] = self._gcodeToVBO_lines(gcodeLayers[n+1:n+2])
131 layerVBOs['GCODE-MOVE'].render()
132 elif result is not None and result._polygons is not None and n < len(result._polygons):
133 polygons = result._polygons[n]
134 for typeName, typeNameGCode, color in lineTypeList:
135 if typeName in polygons:
136 if typeName not in layerVBOs:
137 layerVBOs[typeName] = self._polygonsToVBO_lines(polygons[typeName])
138 glColor4f(color[0]*c,color[1]*c,color[2]*c,color[3])
139 layerVBOs[typeName].render()
143 self._parent._queueRefresh()
145 if gcodeLayers is not None and self._gcodeLoadProgress != 0.0 and self._gcodeLoadProgress != 1.0:
148 glTranslate(0,-0.8,-2)
149 glColor4ub(60,60,60,255)
150 openglHelpers.glDrawStringCenter(_("Loading toolpath for visualization (%d%%)") % (self._gcodeLoadProgress * 100))
153 def _polygonsToVBO_lines(self, polygons):
154 verts = numpy.zeros((0, 3), numpy.float32)
155 indices = numpy.zeros((0), numpy.uint32)
156 for poly in polygons:
158 i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
160 i = numpy.dstack((i[0:-1],i[1:])).flatten()
162 i = numpy.arange(len(verts), len(verts) + len(poly), 1, numpy.uint32)
163 indices = numpy.concatenate((indices, i), 0)
164 verts = numpy.concatenate((verts, poly), 0)
165 return openglHelpers.GLVBO(GL_LINES, verts, indicesArray=indices)
167 def _polygonsToVBO_quads(self, polygons):
168 verts = numpy.zeros((0, 3), numpy.float32)
169 indices = numpy.zeros((0), numpy.uint32)
170 for poly in polygons:
171 i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
172 i2 = numpy.arange(len(verts) + len(poly), len(verts) + len(poly) + len(poly) + 1, 1, numpy.uint32)
174 i2[-1] = len(verts) + len(poly)
175 i = numpy.dstack((i[0:-1],i2[0:-1],i2[1:],i[1:])).flatten()
176 indices = numpy.concatenate((indices, i), 0)
177 verts = numpy.concatenate((verts, poly), 0)
178 verts = numpy.concatenate((verts, poly * numpy.array([1,0,1],numpy.float32) + numpy.array([0,-100,0],numpy.float32)), 0)
179 return openglHelpers.GLVBO(GL_QUADS, verts, indicesArray=indices)
181 def _gcodeToVBO_lines(self, gcodeLayers, extrudeType):
182 if ':' in extrudeType:
183 extruder = int(extrudeType[extrudeType.find(':')+1:])
184 extrudeType = extrudeType[0:extrudeType.find(':')]
187 verts = numpy.zeros((0, 3), numpy.float32)
188 indices = numpy.zeros((0), numpy.uint32)
189 for layer in gcodeLayers:
191 if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
192 i = numpy.arange(len(verts), len(verts) + len(path['points']), 1, numpy.uint32)
193 i = numpy.dstack((i[0:-1],i[1:])).flatten()
194 indices = numpy.concatenate((indices, i), 0)
195 verts = numpy.concatenate((verts, path['points']))
196 return openglHelpers.GLVBO(GL_LINES, verts, indicesArray=indices)
198 def _gcodeToVBO_quads(self, gcodeLayers, extrudeType):
199 useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
200 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
201 filamentArea = math.pi * filamentRadius * filamentRadius
203 if ':' in extrudeType:
204 extruder = int(extrudeType[extrudeType.find(':')+1:])
205 extrudeType = extrudeType[0:extrudeType.find(':')]
209 verts = numpy.zeros((0, 3), numpy.float32)
210 indices = numpy.zeros((0), numpy.uint32)
211 for layer in gcodeLayers:
213 if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
215 if extrudeType == 'FILL':
218 #Construct the normals of each line 90deg rotated on the X/Y plane
219 normals = a[1:] - a[:-1]
220 lengths = numpy.sqrt(normals[:,0]**2 + normals[:,1]**2)
221 normals[:,0], normals[:,1] = -normals[:,1] / lengths, normals[:,0] / lengths
222 normals[:,2] /= lengths
224 ePerDist = path['extrusion'][1:] / lengths
226 lineWidth = ePerDist / path['layerThickness'] / 2.0
228 lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
230 normals[:,0] *= lineWidth
231 normals[:,1] *= lineWidth
233 b = numpy.zeros((len(a)-1, 0), numpy.float32)
234 b = numpy.concatenate((b, a[1:] + normals), 1)
235 b = numpy.concatenate((b, a[1:] - normals), 1)
236 b = numpy.concatenate((b, a[:-1] - normals), 1)
237 b = numpy.concatenate((b, a[:-1] + normals), 1)
238 b = b.reshape((len(b) * 4, 3))
240 i = numpy.arange(len(verts), len(verts) + len(b), 1, numpy.uint32)
242 verts = numpy.concatenate((verts, b))
243 indices = numpy.concatenate((indices, i))
244 return openglHelpers.GLVBO(GL_QUADS, verts, indicesArray=indices)
246 def _gcodeToVBO_lines(self, gcodeLayers):
247 verts = numpy.zeros((0,3), numpy.float32)
248 indices = numpy.zeros((0), numpy.uint32)
249 for layer in gcodeLayers:
251 if path['type'] == 'move':
252 a = path['points'] + numpy.array([0,0,0.02], numpy.float32)
253 i = numpy.arange(len(verts), len(verts) + len(a), 1, numpy.uint32)
254 i = numpy.dstack((i[0:-1],i[1:])).flatten()
255 verts = numpy.concatenate((verts, a))
256 indices = numpy.concatenate((indices, i))
257 if path['type'] == 'retract':
258 a = path['points'] + numpy.array([0,0,0.02], numpy.float32)
259 a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
260 a = a.reshape((len(a) * 2, 3))
261 i = numpy.arange(len(verts), len(verts) + len(a), 1, numpy.uint32)
262 verts = numpy.concatenate((verts, a))
263 indices = numpy.concatenate((indices, i))
264 return openglHelpers.GLVBO(GL_LINES, verts, indicesArray=indices)
266 def OnKeyChar(self, keyCode):
267 if not self._enabled:
270 if wx.GetKeyState(wx.WXK_SHIFT) or wx.GetKeyState(wx.WXK_CONTROL):
271 if keyCode == wx.WXK_UP:
272 self.layerSelect.setValue(self.layerSelect.getValue() + 1)
273 self._parent.QueueRefresh()
275 elif keyCode == wx.WXK_DOWN:
276 self.layerSelect.setValue(self.layerSelect.getValue() - 1)
277 self._parent.QueueRefresh()
279 elif keyCode == wx.WXK_PAGEUP:
280 self.layerSelect.setValue(self.layerSelect.getValue() + 10)
281 self._parent.QueueRefresh()
283 elif keyCode == wx.WXK_PAGEDOWN:
284 self.layerSelect.setValue(self.layerSelect.getValue() - 10)
285 self._parent.QueueRefresh()