X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=cura.git;a=blobdiff_plain;f=Cura%2Fgui%2FsceneView.py;h=337a18835306c54f4c2ba590ac2cbcabc99519b5;hp=ebf28566e3d8c15d0a354e6b544b475effdfc9cd;hb=6208201bafdeaf82883181471c6da3a41283cfe7;hpb=f395f7e33ee4f62fe851389b529cdf10108f7cf1 diff --git a/Cura/gui/sceneView.py b/Cura/gui/sceneView.py index ebf28566..337a1883 100644 --- a/Cura/gui/sceneView.py +++ b/Cura/gui/sceneView.py @@ -9,9 +9,10 @@ import traceback import threading import math import platform +import cStringIO as StringIO import OpenGL -OpenGL.ERROR_CHECKING = False +#OpenGL.ERROR_CHECKING = False from OpenGL.GLU import * from OpenGL.GL import * @@ -24,12 +25,12 @@ from Cura.util import resources from Cura.util import sliceEngine from Cura.util import machineCom from Cura.util import removableStorage -from Cura.util import gcodeInterpreter from Cura.util import explorer from Cura.util.printerConnection import printerConnectionManager from Cura.gui.util import previewTools from Cura.gui.util import opengl from Cura.gui.util import openglGui +from Cura.gui.util import engineResultView from Cura.gui.tools import youmagineGui from Cura.gui.tools import imageToMesh @@ -41,10 +42,6 @@ class SceneView(openglGui.glGuiPanel): self._pitch = 60 self._zoom = 300 self._scene = objectScene.Scene() - self._gcode = None - self._gcodeVBOs = [] - self._gcodeFilename = None - self._gcodeLoadThread = None self._objectShader = None self._objectLoadShader = None self._focusObj = None @@ -108,16 +105,16 @@ class SceneView(openglGui.glGuiPanel): self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None) self.viewSelection = openglGui.glComboButton(self, _("View mode"), [7,19,11,15,23], [_("Normal"), _("Overhang"), _("Transparent"), _("X-Ray"), _("Layers")], (-1,0), self.OnViewChange) - self.layerSelect = openglGui.glSlider(self, 10000, 0, 1, (-1,-2), lambda : self.QueueRefresh()) self.youMagineButton = openglGui.glButton(self, 26, _("Share on YouMagine"), (2,0), lambda button: youmagineGui.youmagineManager(self.GetTopLevelParent(), self._scene)) self.youMagineButton.setDisabled(True) self.notification = openglGui.glNotification(self, (0, 0)) - self._slicer = sliceEngine.Slicer(self._updateSliceProgress) + self._engine = sliceEngine.Engine(self._updateEngineProgress) + self._engineResultView = engineResultView.engineResultView(self) self._sceneUpdateTimer = wx.Timer(self) - self.Bind(wx.EVT_TIMER, self._onRunSlicer, self._sceneUpdateTimer) + self.Bind(wx.EVT_TIMER, self._onRunEngine, self._sceneUpdateTimer) self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) @@ -128,14 +125,7 @@ class SceneView(openglGui.glGuiPanel): def loadGCodeFile(self, filename): self.OnDeleteAll(None) - if self._gcode is not None: - self._gcode = None - for layerVBOlist in self._gcodeVBOs: - for vbo in layerVBOlist: - self.glReleaseList.append(vbo) - self._gcodeVBOs = [] - self._gcode = gcodeInterpreter.gcode() - self._gcodeFilename = filename + #TODO: Load straight GCodeFile self.printButton.setBottomText('') self.viewSelection.setValue(4) self.printButton.setDisabled(False) @@ -242,7 +232,7 @@ class SceneView(openglGui.glGuiPanel): else: drive = drives[0] filename = self._scene._objectList[0].getName() + '.gcode' - threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start() + threading.Thread(target=self._saveGCode,args=(drive[1] + filename, drive[1])).start() elif connectionGroup is not None: connections = connectionGroup.getAvailableConnections() if len(connections) < 2: @@ -267,7 +257,7 @@ class SceneView(openglGui.glGuiPanel): menu.connectionMap[i.GetId()] = connection self.Bind(wx.EVT_MENU, lambda e: self._openPrintWindowForConnection(e.GetEventObject().connectionMap[e.GetId()]), i) self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, _("Save GCode..."))) - self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, _("Slice engine log..."))) + self.Bind(wx.EVT_MENU, lambda e: self._showEngineLog(), menu.Append(-1, _("Slice engine log..."))) self.PopupMenu(menu) menu.Destroy() @@ -277,6 +267,7 @@ class SceneView(openglGui.glGuiPanel): connection.window = printWindow2.printWindow(connection) connection.window.Show() connection.window.Raise() + #TODO: Fix for _engine.getResult if not connection.loadFile(self._gcodeFilename): if connection.isPrinting(): self.notification.message("Cannot start print, because other print still running.") @@ -289,9 +280,10 @@ class SceneView(openglGui.glGuiPanel): if profile.getMachineSetting('gcode_flavor') == 'UltiGCode': wx.MessageBox(_("USB printing on the Ultimaker2 is not supported."), _("USB Printing Error"), wx.OK | wx.ICON_WARNING) return - self._usbPrintMonitor.loadFile(self._gcodeFilename, self._slicer.getID()) - if self._gcodeFilename == self._slicer.getGCodeFilename(): - self._slicer.submitSliceInfoOnline() + #TODO: Fix for _engine.getResult + self._usbPrintMonitor.loadFile(self._gcodeFilename, self._engine.getID()) + if self._gcodeFilename is None: + self._engine.submitInfoOnline() def showSaveGCode(self): if len(self._scene._objectList) < 1: @@ -306,34 +298,34 @@ class SceneView(openglGui.glGuiPanel): filename = dlg.GetPath() dlg.Destroy() - threading.Thread(target=self._copyFile,args=(self._gcodeFilename, filename)).start() + threading.Thread(target=self._saveGCode,args=(filename,)).start() - def _copyFile(self, fileA, fileB, allowEject = False): + def _saveGCode(self, targetFilename, ejectDrive = False): + data = self._engine.getResult().getGCode() try: - size = float(os.stat(fileA).st_size) - with open(fileA, 'rb') as fsrc: - with open(fileB, 'wb') as fdst: - while 1: - buf = fsrc.read(16*1024) - if not buf: - break - fdst.write(buf) - self.printButton.setProgressBar(float(fsrc.tell()) / size) - self._queueRefresh() + size = float(len(data)) + fsrc = StringIO.StringIO(data) + with open(targetFilename, 'wb') as fdst: + while 1: + buf = fsrc.read(16*1024) + if not buf: + break + fdst.write(buf) + self.printButton.setProgressBar(float(fsrc.tell()) / size) + self._queueRefresh() except: - import sys - print sys.exc_info() + import sys, traceback + traceback.print_exc() self.notification.message("Failed to save") else: - if allowEject: - self.notification.message("Saved as %s" % (fileB), lambda : self._doEjectSD(allowEject), 31, 'Eject') + if ejectDrive: + self.notification.message("Saved as %s" % (targetFilename), lambda : self._doEjectSD(ejectDrive), 31, 'Eject') elif explorer.hasExplorer(): - self.notification.message("Saved as %s" % (fileB), lambda : explorer.openExplorer(fileB), 4, 'Open folder') + self.notification.message("Saved as %s" % (targetFilename), lambda : explorer.openExplorer(targetFilename), 4, 'Open folder') else: - self.notification.message("Saved as %s" % (fileB)) + self.notification.message("Saved as %s" % (targetFilename)) self.printButton.setProgressBar(None) - if fileA == self._slicer.getGCodeFilename(): - self._slicer.submitSliceInfoOnline() + self._engine.getResult().submitInfoOnline() def _doEjectSD(self, drive): if removableStorage.ejectDrive(drive): @@ -341,8 +333,8 @@ class SceneView(openglGui.glGuiPanel): else: self.notification.message('Safe remove failed...') - def _showSliceLog(self): - dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE) + def _showEngineLog(self): + dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._engine.getResult().getLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE) dlg.ShowModal() dlg.Destroy() @@ -381,9 +373,6 @@ class SceneView(openglGui.glGuiPanel): def OnViewChange(self): if self.viewSelection.getValue() == 4: self.viewMode = 'gcode' - if self._gcode is not None and self._gcode.layerList is not None: - self.layerSelect.setRange(1, len(self._gcode.layerList) - 1) - self._selectObject(None) elif self.viewSelection.getValue() == 1: self.viewMode = 'overhang' elif self.viewSelection.getValue() == 2: @@ -392,7 +381,7 @@ class SceneView(openglGui.glGuiPanel): self.viewMode = 'xray' else: self.viewMode = 'normal' - self.layerSelect.setHidden(self.viewMode != 'gcode') + self._engineResultView.setEnabled(self.viewMode == 'gcode') self.QueueRefresh() def OnRotateReset(self, button): @@ -538,66 +527,45 @@ class SceneView(openglGui.glGuiPanel): def sceneUpdated(self): self._sceneUpdateTimer.Start(500, True) - self._slicer.abortSlicer() + self._engine.abortEngine() self._scene.updateSizeOffsets() self.QueueRefresh() - def _onRunSlicer(self, e): + def _onRunEngine(self, e): if self._isSimpleMode: self.GetTopLevelParent().simpleSettingsPanel.setupSlice() - self._slicer.runSlicer(self._scene) + self._engine.runEngine(self._scene) if self._isSimpleMode: profile.resetTempOverride() - def _updateSliceProgress(self, progressValue, ready): - if not ready: + def _updateEngineProgress(self, progressValue): + result = self._engine.getResult() + finished = result is not None and result.isFinished() + if not finished: if self.printButton.getProgressBar() is not None and progressValue >= 0.0 and abs(self.printButton.getProgressBar() - progressValue) < 0.01: return - self.printButton.setDisabled(not ready) + self.printButton.setDisabled(not finished) if progressValue >= 0.0: self.printButton.setProgressBar(progressValue) else: self.printButton.setProgressBar(None) - if self._gcode is not None: - self._gcode = None - for layerVBOlist in self._gcodeVBOs: - for vbo in layerVBOlist: - self.glReleaseList.append(vbo) - self._gcodeVBOs = [] - if ready: + self._engineResultView.setResult(result) + if finished: self.printButton.setProgressBar(None) - text = '%s' % (self._slicer.getPrintTime()) + text = '%s' % (result.getPrintTime()) for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))): - amount = self._slicer.getFilamentAmount(e) + amount = result.getFilamentAmount(e) if amount is None: continue text += '\n%s' % (amount) - cost = self._slicer.getFilamentCost(e) + cost = result.getFilamentCost(e) if cost is not None: text += '\n%s' % (cost) self.printButton.setBottomText(text) - self._gcode = gcodeInterpreter.gcode() - self._gcodeFilename = self._slicer.getGCodeFilename() else: self.printButton.setBottomText('') self.QueueRefresh() - def _loadGCode(self): - self._gcode.progressCallback = self._gcodeLoadCallback - self._gcode.load(self._gcodeFilename) - - def _gcodeLoadCallback(self, progress): - if not self or self._gcode is None: - return True - if len(self._gcode.layerList) % 15 == 0: - time.sleep(0.1) - if self._gcode is None: - return True - self.layerSelect.setRange(1, len(self._gcode.layerList) - 1) - if self.viewMode == 'gcode': - self._queueRefresh() - return False - def loadScene(self, fileList): for filename in fileList: try: @@ -676,72 +644,60 @@ class SceneView(openglGui.glGuiPanel): self.scaleZmmctrl.setValue(round(size[2], 2)) def OnKeyChar(self, keyCode): + if self._engineResultView.OnKeyChar(keyCode): + return if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE or (keyCode == wx.WXK_BACK and platform.system() == "Darwin"): if self._selectedObj is not None: self._deleteObject(self._selectedObj) self.QueueRefresh() - if self.viewMode == 'gcode' and (wx.GetKeyState(wx.WXK_SHIFT) or wx.GetKeyState(wx.WXK_CONTROL)): - if keyCode == wx.WXK_UP: - self.layerSelect.setValue(self.layerSelect.getValue() + 1) - self.QueueRefresh() - elif keyCode == wx.WXK_DOWN: - self.layerSelect.setValue(self.layerSelect.getValue() - 1) - self.QueueRefresh() - elif keyCode == wx.WXK_PAGEUP: - self.layerSelect.setValue(self.layerSelect.getValue() + 10) - self.QueueRefresh() - elif keyCode == wx.WXK_PAGEDOWN: - self.layerSelect.setValue(self.layerSelect.getValue() - 10) - self.QueueRefresh() - else: - if keyCode == wx.WXK_UP: - if wx.GetKeyState(wx.WXK_SHIFT): - self._zoom /= 1.2 - if self._zoom < 1: - self._zoom = 1 - else: - self._pitch -= 15 - self.QueueRefresh() - elif keyCode == wx.WXK_DOWN: - if wx.GetKeyState(wx.WXK_SHIFT): - self._zoom *= 1.2 - if self._zoom > numpy.max(self._machineSize) * 3: - self._zoom = numpy.max(self._machineSize) * 3 - else: - self._pitch += 15 - self.QueueRefresh() - elif keyCode == wx.WXK_LEFT: - self._yaw -= 15 - self.QueueRefresh() - elif keyCode == wx.WXK_RIGHT: - self._yaw += 15 - self.QueueRefresh() - elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='): + if keyCode == wx.WXK_UP: + if wx.GetKeyState(wx.WXK_SHIFT): self._zoom /= 1.2 if self._zoom < 1: self._zoom = 1 - self.QueueRefresh() - elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'): + else: + self._pitch -= 15 + self.QueueRefresh() + elif keyCode == wx.WXK_DOWN: + if wx.GetKeyState(wx.WXK_SHIFT): self._zoom *= 1.2 if self._zoom > numpy.max(self._machineSize) * 3: self._zoom = numpy.max(self._machineSize) * 3 - self.QueueRefresh() - elif keyCode == wx.WXK_HOME: - self._yaw = 30 - self._pitch = 60 - self.QueueRefresh() - elif keyCode == wx.WXK_PAGEUP: - self._yaw = 0 - self._pitch = 0 - self.QueueRefresh() - elif keyCode == wx.WXK_PAGEDOWN: - self._yaw = 0 - self._pitch = 90 - self.QueueRefresh() - elif keyCode == wx.WXK_END: - self._yaw = 90 - self._pitch = 90 - self.QueueRefresh() + else: + self._pitch += 15 + self.QueueRefresh() + elif keyCode == wx.WXK_LEFT: + self._yaw -= 15 + self.QueueRefresh() + elif keyCode == wx.WXK_RIGHT: + self._yaw += 15 + self.QueueRefresh() + elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='): + self._zoom /= 1.2 + if self._zoom < 1: + self._zoom = 1 + self.QueueRefresh() + elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'): + self._zoom *= 1.2 + if self._zoom > numpy.max(self._machineSize) * 3: + self._zoom = numpy.max(self._machineSize) * 3 + self.QueueRefresh() + elif keyCode == wx.WXK_HOME: + self._yaw = 30 + self._pitch = 60 + self.QueueRefresh() + elif keyCode == wx.WXK_PAGEUP: + self._yaw = 0 + self._pitch = 0 + self.QueueRefresh() + elif keyCode == wx.WXK_PAGEDOWN: + self._yaw = 0 + self._pitch = 90 + self.QueueRefresh() + elif keyCode == wx.WXK_END: + self._yaw = 90 + self._pitch = 90 + self.QueueRefresh() if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT): shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader()) @@ -948,11 +904,6 @@ class SceneView(openglGui.glGuiPanel): self._zoom = self._animZoom.getPosition() if self._animZoom.isDone(): self._animZoom = None - if self.viewMode == 'gcode' and self._gcode is not None: - try: - self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2] - except: - pass if self._objectShader is None: if opengl.hasShaderSupport(): self._objectShader = opengl.GLShader(""" @@ -1070,66 +1021,9 @@ void main(void) glRotate(self._yaw, 0,0,1) glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2]) - if self.viewMode == 'gcode': - if self._gcode is not None and self._gcode.layerList is None: - self._gcodeLoadThread = threading.Thread(target=self._loadGCode) - self._gcodeLoadThread.daemon = True - self._gcodeLoadThread.start() - if self._gcode is not None and self._gcode.layerList is not None: - glPushMatrix() - if profile.getMachineSetting('machine_center_is_zero') != 'True': - glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0) - t = time.time() - drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1) - for n in xrange(0, drawUpTill): - c = 1.0 - float(drawUpTill - n) / 15 - c = max(0.3, c) - if len(self._gcodeVBOs) < n + 1: - self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n])) - if time.time() - t > 0.5: - self.QueueRefresh() - break - #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT'] - if n == drawUpTill - 1: - if len(self._gcodeVBOs[n]) < 9: - self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n]) - glColor3f(c, 0, 0) - self._gcodeVBOs[n][8].render(GL_QUADS) - glColor3f(c/2, 0, c) - self._gcodeVBOs[n][9].render(GL_QUADS) - glColor3f(0, c, c/2) - self._gcodeVBOs[n][10].render(GL_QUADS) - glColor3f(c, 0, 0) - self._gcodeVBOs[n][11].render(GL_QUADS) - - glColor3f(0, c, 0) - self._gcodeVBOs[n][12].render(GL_QUADS) - glColor3f(c/2, c/2, 0.0) - self._gcodeVBOs[n][13].render(GL_QUADS) - glColor3f(0, c, c) - self._gcodeVBOs[n][14].render(GL_QUADS) - self._gcodeVBOs[n][15].render(GL_QUADS) - glColor3f(0, 0, c) - self._gcodeVBOs[n][16].render(GL_LINES) - else: - glColor3f(c, 0, 0) - self._gcodeVBOs[n][0].render(GL_LINES) - glColor3f(c/2, 0, c) - self._gcodeVBOs[n][1].render(GL_LINES) - glColor3f(0, c, c/2) - self._gcodeVBOs[n][2].render(GL_LINES) - glColor3f(c, 0, 0) - self._gcodeVBOs[n][3].render(GL_LINES) - - glColor3f(0, c, 0) - self._gcodeVBOs[n][4].render(GL_LINES) - glColor3f(c/2, c/2, 0.0) - self._gcodeVBOs[n][5].render(GL_LINES) - glColor3f(0, c, c) - self._gcodeVBOs[n][6].render(GL_LINES) - self._gcodeVBOs[n][7].render(GL_LINES) - glPopMatrix() - else: + self._objectShader.unbind() + self._engineResultView.OnDraw() + if self.viewMode != 'gcode': glStencilFunc(GL_ALWAYS, 1, 1) glStencilOp(GL_INCR, GL_INCR, GL_INCR) @@ -1226,7 +1120,7 @@ void main(void) self._drawMachine() - if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID(): + if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._engine.getID(): z = self._usbPrintMonitor.getZ() if self.viewMode == 'gcode': layer_height = profile.getProfileSettingFloat('layer_height') @@ -1250,16 +1144,7 @@ void main(void) glVertex3f(-size[0]/2, size[1]/2, z) glEnd() - if self.viewMode == 'gcode': - if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive(): - glDisable(GL_DEPTH_TEST) - glPushMatrix() - glLoadIdentity() - glTranslate(0,-4,-10) - glColor4ub(60,60,60,255) - opengl.glDrawStringCenter(_("Loading toolpath for visualization...")) - glPopMatrix() - else: + if self.viewMode != 'gcode': #Draw the object box-shadow, so you can see where it will collide with other objects. if self._selectedObj is not None: glEnable(GL_BLEND) @@ -1344,7 +1229,7 @@ void main(void) n = 0 for m in obj._meshList: if m.vbo is None: - m.vbo = opengl.GLVBO(m.vertexes, m.normal) + m.vbo = opengl.GLVBO(GL_TRIANGLES, m.vertexes, m.normal) if brightness: glColor4fv(map(lambda n: n * brightness, self._objColors[n])) n += 1 @@ -1476,106 +1361,6 @@ void main(void) glDisable(GL_BLEND) glDisable(GL_CULL_FACE) - def _generateGCodeVBOs(self, layer): - ret = [] - for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']: - if ':' in extrudeType: - extruder = int(extrudeType[extrudeType.find(':')+1:]) - extrudeType = extrudeType[0:extrudeType.find(':')] - else: - extruder = None - pointList = numpy.zeros((0,3), numpy.float32) - for path in layer: - if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder): - a = path['points'] - a = numpy.concatenate((a[:-1], a[1:]), 1) - a = a.reshape((len(a) * 2, 3)) - pointList = numpy.concatenate((pointList, a)) - ret.append(opengl.GLVBO(pointList)) - return ret - - def _generateGCodeVBOs2(self, layer): - filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2 - filamentArea = math.pi * filamentRadius * filamentRadius - useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode' - - ret = [] - for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']: - if ':' in extrudeType: - extruder = int(extrudeType[extrudeType.find(':')+1:]) - extrudeType = extrudeType[0:extrudeType.find(':')] - else: - extruder = None - pointList = numpy.zeros((0,3), numpy.float32) - for path in layer: - if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder): - a = path['points'] - if extrudeType == 'FILL': - a[:,2] += 0.01 - - normal = a[1:] - a[:-1] - lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2) - normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens - normal[:,2] /= lens - - ePerDist = path['extrusion'][1:] / lens - if useFilamentArea: - lineWidth = ePerDist / path['layerThickness'] / 2.0 - else: - lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2) - - normal[:,0] *= lineWidth - normal[:,1] *= lineWidth - - b = numpy.zeros((len(a)-1, 0), numpy.float32) - b = numpy.concatenate((b, a[1:] + normal), 1) - b = numpy.concatenate((b, a[1:] - normal), 1) - b = numpy.concatenate((b, a[:-1] - normal), 1) - b = numpy.concatenate((b, a[:-1] + normal), 1) - b = b.reshape((len(b) * 4, 3)) - - if len(a) > 2: - normal2 = normal[:-1] + normal[1:] - lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2) - normal2[:,0] /= lens2 - normal2[:,1] /= lens2 - normal2[:,0] *= lineWidth[:-1] - normal2[:,1] *= lineWidth[:-1] - - c = numpy.zeros((len(a)-2, 0), numpy.float32) - c = numpy.concatenate((c, a[1:-1]), 1) - c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1) - c = numpy.concatenate((c, a[1:-1]+normal2), 1) - c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1) - - c = numpy.concatenate((c, a[1:-1]), 1) - c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1) - c = numpy.concatenate((c, a[1:-1]-normal2), 1) - c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1) - - c = c.reshape((len(c) * 8, 3)) - - pointList = numpy.concatenate((pointList, b, c)) - else: - pointList = numpy.concatenate((pointList, b)) - ret.append(opengl.GLVBO(pointList)) - - pointList = numpy.zeros((0,3), numpy.float32) - for path in layer: - if path['type'] == 'move': - a = path['points'] + numpy.array([0,0,0.01], numpy.float32) - a = numpy.concatenate((a[:-1], a[1:]), 1) - a = a.reshape((len(a) * 2, 3)) - pointList = numpy.concatenate((pointList, a)) - if path['type'] == 'retract': - a = path['points'] + numpy.array([0,0,0.01], numpy.float32) - a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1) - a = a.reshape((len(a) * 2, 3)) - pointList = numpy.concatenate((pointList, a)) - ret.append(opengl.GLVBO(pointList)) - - return ret - def getObjectCenterPos(self): if self._selectedObj is None: return [0.0, 0.0, 0.0]