chiark / gitweb /
Merge pull request #1 from daid/SteamEngine
authorDim3nsioneer <Dim3nsioneer@users.noreply.github.com>
Wed, 29 Jan 2014 16:34:05 +0000 (08:34 -0800)
committerDim3nsioneer <Dim3nsioneer@users.noreply.github.com>
Wed, 29 Jan 2014 16:34:05 +0000 (08:34 -0800)
Update on 140129

14 files changed:
Cura/gui/app.py
Cura/gui/configWizard.py
Cura/gui/mainWindow.py
Cura/gui/printWindow.py
Cura/gui/sceneView.py
Cura/gui/util/engineResultView.py [new file with mode: 0644]
Cura/gui/util/opengl.py
Cura/gui/util/openglGui.py
Cura/gui/util/previewTools.py
Cura/util/gcodeInterpreter.py
Cura/util/profile.py
Cura/util/sliceEngine.py
README.md
package.sh

index dffa855ebbdef70fa711efba10f7b0ef5232511e..47932c60c5e163b1415a7f1536cd9a15ba8af560 100644 (file)
@@ -63,11 +63,14 @@ class CuraApp(wx.App):
 
        def Win32SocketListener(self, port):
                import socket
-               sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-               sock.bind(("127.0.0.1", port))
-               while True:
-                       data, addr = sock.recvfrom(2048)
-                       self.mainWindow.OnDropFiles(data.split('\0'))
+               try:
+                       sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+                       sock.bind(("127.0.0.1", port))
+                       while True:
+                               data, addr = sock.recvfrom(2048)
+                               self.mainWindow.OnDropFiles(data.split('\0'))
+               except:
+                       pass
 
        def afterSplashCallback(self):
                #These imports take most of the time and thus should be done after showing the splashscreen
index 4e45d5ac63afc9169d8041f7f97b6eb35b7c3ea1..d0273bc474637844f65c5310dc29405dea286129 100644 (file)
@@ -282,7 +282,7 @@ class CustomRepRapInfoPage(InfoPage):
                self.machineName = self.AddLabelTextCtrl(_("Machine name"), "RepRap")
                self.machineWidth = self.AddLabelTextCtrl(_("Machine width (mm)"), "80")
                self.machineDepth = self.AddLabelTextCtrl(_("Machine depth (mm)"), "80")
-               self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "60")
+               self.machineHeight = self.AddLabelTextCtrl(_("Machine height (mm)"), "55")
                self.nozzleSize = self.AddLabelTextCtrl(_("Nozzle size (mm)"), "0.5")
                self.heatedBed = self.AddCheckbox(_("Heated bed"))
                self.HomeAtCenter = self.AddCheckbox(_("Bed center is 0,0,0 (RoStock)"))
@@ -368,7 +368,7 @@ class MachineSelectPage(InfoPage):
                        profile.putMachineSetting('extruder_head_size_min_y', '18.0')
                        profile.putMachineSetting('extruder_head_size_max_x', '18.0')
                        profile.putMachineSetting('extruder_head_size_max_y', '35.0')
-                       profile.putMachineSetting('extruder_head_size_height', '60.0')
+                       profile.putMachineSetting('extruder_head_size_height', '55.0')
                else:
                        profile.putMachineSetting('machine_width', '80')
                        profile.putMachineSetting('machine_depth', '80')
index 95903813f297069dc4b4f3d349cc420e5bb8ecd4..590252a53d3bc4adfbe1d1751e5894bcd36ce187 100644 (file)
@@ -575,7 +575,7 @@ class mainWindow(wx.Frame):
                #HACK: Set the paint function of the glCanvas to nothing so it won't keep refreshing. Which can keep wxWidgets from quiting.
                print "Closing down"
                self.scene.OnPaint = lambda e : e
-               self.scene._slicer.cleanup()
+               self.scene._engine.cleanup()
                self.Destroy()
 
        def OnQuit(self, e):
index 943ada16e7a6a9b30516bcc7222836458ea540ac..1a0e2cbe116c63a3b67bb6a8ac49c121a8a23609 100644 (file)
@@ -602,7 +602,7 @@ class printWindow(wx.Frame):
                                        gcodeList.append(line)
                                prevLineType = lineType
                gcode = gcodeInterpreter.gcode()
-               gcode.loadList(gcodeList)
+               gcode.load(gcodeList)
                #print "Loaded: %s (%d)" % (filename, len(gcodeList))
                self.filename = filename
                self.gcode = gcode
index ebf28566e3d8c15d0a354e6b544b475effdfc9cd..337a18835306c54f4c2ba590ac2cbcabc99519b5 100644 (file)
@@ -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]
diff --git a/Cura/gui/util/engineResultView.py b/Cura/gui/util/engineResultView.py
new file mode 100644 (file)
index 0000000..8786afc
--- /dev/null
@@ -0,0 +1,491 @@
+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
+
+import wx
+import numpy
+import math
+
+import OpenGL
+#OpenGL.ERROR_CHECKING = False
+from OpenGL.GLU import *
+from OpenGL.GL import *
+
+from Cura.util import profile
+from Cura.gui.util import opengl
+from Cura.gui.util import openglGui
+
+class engineResultView(object):
+       def __init__(self, parent):
+               self._parent = parent
+               self._result = None
+               self._enabled = False
+               self._gcodeLoadProgress = 0
+               self._layerVBOs = []
+               self._layer20VBOs = []
+
+               self.layerSelect = openglGui.glSlider(self._parent, 10000, 0, 1, (-1,-2), lambda : self._parent.QueueRefresh())
+
+       def setResult(self, result):
+               if self._result == result:
+                       return
+
+               self._result = result
+
+               #Clean the saved VBO's
+               for layer in self._layerVBOs:
+                       for typeName in layer.keys():
+                               self._parent.glReleaseList.append(layer[typeName])
+               for layer in self._layer20VBOs:
+                       for typeName in layer.keys():
+                               self._parent.glReleaseList.append(layer[typeName])
+               self._layerVBOs = []
+               self._layer20VBOs = []
+
+       def setEnabled(self, enabled):
+               self._enabled = enabled
+               self.layerSelect.setHidden(not enabled)
+
+       def _gcodeLoadCallback(self, result, progress):
+               if result != self._result:
+                       #Abort loading from this thread.
+                       return True
+               self._gcodeLoadProgress = progress
+               self._parent._queueRefresh()
+               return False
+
+       def OnDraw(self):
+               if not self._enabled:
+                       return
+
+               result = self._result
+               if result is not None and result._polygons is not None:
+                       self.layerSelect.setRange(1, len(result._polygons))
+               if result is not None:
+                       gcodeLayers = result.getGCodeLayers(self._gcodeLoadCallback)
+               else:
+                       gcodeLayers = None
+
+               glPushMatrix()
+               glEnable(GL_BLEND)
+               if profile.getMachineSetting('machine_center_is_zero') != 'True':
+                       glTranslate(-profile.getMachineSettingFloat('machine_width') / 2, -profile.getMachineSettingFloat('machine_depth') / 2, 0)
+               glLineWidth(2)
+
+               layerNr = self.layerSelect.getValue()
+               if layerNr == self.layerSelect.getMaxValue():
+                       layerNr = max(layerNr, len(result._polygons))
+               viewZ = (layerNr - 1) * profile.getProfileSettingFloat('layer_height') + profile.getProfileSettingFloat('bottom_thickness')
+               self._parent._viewTarget[2] = viewZ
+               msize = max(profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'))
+               lineTypeList = [
+                       ('inset0',     'WALL-OUTER', [1,0,0,1]),
+                       ('insetx',     'WALL-INNER', [0,1,0,1]),
+                       ('openoutline', None,        [1,0,0,1]),
+                       ('skin',       'FILL',       [1,1,0,1]),
+                       ('infill',      None,        [1,1,0,1]),
+                       ('support',    'SUPPORT',    [0,1,1,1]),
+                       ('skirt',      'SKIRT',      [0,1,1,1]),
+                       ('outline',     None,        [0,0,0,1])
+               ]
+               n = layerNr - 1
+               generatedVBO = False
+               while n >= 0:
+                       if layerNr - n > 30 and n % 20 == 0:
+                               idx = n / 20
+                               while len(self._layer20VBOs) < idx + 1:
+                                       self._layer20VBOs.append({})
+                               if result is not None and result._polygons is not None and n + 20 < len(result._polygons):
+                                       layerVBOs = self._layer20VBOs[idx]
+                                       for typeName, typeNameGCode, color in lineTypeList:
+                                               if (typeName in result._polygons[n + 19]) or (typeName == 'skirt' and typeName in result._polygons[n]):
+                                                       if typeName not in layerVBOs:
+                                                               if generatedVBO:
+                                                                       continue
+                                                               polygons = []
+                                                               for i in xrange(0, 20):
+                                                                       if typeName in result._polygons[n + i]:
+                                                                               polygons += result._polygons[n + i][typeName]
+                                                               layerVBOs[typeName] = self._polygonsToVBO_lines(polygons)
+                                                               generatedVBO = True
+                                                       glColor4f(color[0]*0.5,color[1]*0.5,color[2]*0.5,color[3])
+                                                       layerVBOs[typeName].render()
+                               n -= 20
+                       else:
+                               c = 1.0 - ((layerNr - n) - 1) * 0.05
+                               c = max(0.5, c)
+                               while len(self._layerVBOs) < n + 1:
+                                       self._layerVBOs.append({})
+                               layerVBOs = self._layerVBOs[n]
+                               if gcodeLayers is not None and layerNr - 10 < n < (len(gcodeLayers) - 1):
+                                       for typeNamePolygons, typeName, color in lineTypeList:
+                                               if typeName is None:
+                                                       continue
+                                               if 'GCODE-' + typeName not in layerVBOs:
+                                                       layerVBOs['GCODE-' + typeName] = self._gcodeToVBO_quads(gcodeLayers[n+1:n+2], typeName)
+                                               glColor4f(color[0]*c,color[1]*c,color[2]*c,color[3])
+                                               layerVBOs['GCODE-' + typeName].render()
+
+                                       if n == layerNr - 1:
+                                               if 'GCODE-MOVE' not in layerVBOs:
+                                                       layerVBOs['GCODE-MOVE'] = self._gcodeToVBO_lines(gcodeLayers[n+1:n+2])
+                                               glColor4f(0,0,c,1)
+                                               layerVBOs['GCODE-MOVE'].render()
+                               elif result is not None and result._polygons is not None and n < len(result._polygons):
+                                       polygons = result._polygons[n]
+                                       for typeName, typeNameGCode, color in lineTypeList:
+                                               if typeName in polygons:
+                                                       if typeName not in layerVBOs:
+                                                               layerVBOs[typeName] = self._polygonsToVBO_lines(polygons[typeName])
+                                                       glColor4f(color[0]*c,color[1]*c,color[2]*c,color[3])
+                                                       layerVBOs[typeName].render()
+                               n -= 1
+               glPopMatrix()
+               if generatedVBO:
+                       self._parent._queueRefresh()
+
+               if gcodeLayers is not None and self._gcodeLoadProgress != 0.0 and self._gcodeLoadProgress != 1.0:
+                       glPushMatrix()
+                       glLoadIdentity()
+                       glTranslate(0,-0.8,-2)
+                       glColor4ub(60,60,60,255)
+                       opengl.glDrawStringCenter(_("Loading toolpath for visualization (%d%%)") % (self._gcodeLoadProgress * 100))
+                       glPopMatrix()
+
+       def _polygonsToVBO_lines(self, polygons):
+               verts = numpy.zeros((0, 3), numpy.float32)
+               indices = numpy.zeros((0), numpy.uint32)
+               for poly in polygons:
+                       if len(poly) > 2:
+                               i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
+                               i[-1] = len(verts)
+                               i = numpy.dstack((i[0:-1],i[1:])).flatten()
+                       else:
+                               i = numpy.arange(len(verts), len(verts) + len(poly), 1, numpy.uint32)
+                       indices = numpy.concatenate((indices, i), 0)
+                       verts = numpy.concatenate((verts, poly), 0)
+               return opengl.GLVBO(GL_LINES, verts, indicesArray=indices)
+
+       def _polygonsToVBO_quads(self, polygons):
+               verts = numpy.zeros((0, 3), numpy.float32)
+               indices = numpy.zeros((0), numpy.uint32)
+               for poly in polygons:
+                       i = numpy.arange(len(verts), len(verts) + len(poly) + 1, 1, numpy.uint32)
+                       i2 = numpy.arange(len(verts) + len(poly), len(verts) + len(poly) + len(poly) + 1, 1, numpy.uint32)
+                       i[-1] = len(verts)
+                       i2[-1] = len(verts) + len(poly)
+                       i = numpy.dstack((i[0:-1],i2[0:-1],i2[1:],i[1:])).flatten()
+                       indices = numpy.concatenate((indices, i), 0)
+                       verts = numpy.concatenate((verts, poly), 0)
+                       verts = numpy.concatenate((verts, poly * numpy.array([1,0,1],numpy.float32) + numpy.array([0,-100,0],numpy.float32)), 0)
+               return opengl.GLVBO(GL_QUADS, verts, indicesArray=indices)
+
+       def _gcodeToVBO_lines(self, gcodeLayers, extrudeType):
+               if ':' in extrudeType:
+                       extruder = int(extrudeType[extrudeType.find(':')+1:])
+                       extrudeType = extrudeType[0:extrudeType.find(':')]
+               else:
+                       extruder = None
+               verts = numpy.zeros((0, 3), numpy.float32)
+               indices = numpy.zeros((0), numpy.uint32)
+               for layer in gcodeLayers:
+                       for path in layer:
+                               if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
+                                       i = numpy.arange(len(verts), len(verts) + len(path['points']), 1, numpy.uint32)
+                                       i = numpy.dstack((i[0:-1],i[1:])).flatten()
+                                       indices = numpy.concatenate((indices, i), 0)
+                                       verts = numpy.concatenate((verts, path['points']))
+               return opengl.GLVBO(GL_LINES, verts, indicesArray=indices)
+
+       def _gcodeToVBO_quads(self, gcodeLayers, extrudeType):
+               useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
+               filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
+               filamentArea = math.pi * filamentRadius * filamentRadius
+
+               if ':' in extrudeType:
+                       extruder = int(extrudeType[extrudeType.find(':')+1:])
+                       extrudeType = extrudeType[0:extrudeType.find(':')]
+               else:
+                       extruder = None
+
+               verts = numpy.zeros((0, 3), numpy.float32)
+               indices = numpy.zeros((0), numpy.uint32)
+               for layer in gcodeLayers:
+                       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
+
+                                       #Construct the normals of each line 90deg rotated on the X/Y plane
+                                       normals = a[1:] - a[:-1]
+                                       lengths = numpy.sqrt(normals[:,0]**2 + normals[:,1]**2)
+                                       normals[:,0], normals[:,1] = -normals[:,1] / lengths, normals[:,0] / lengths
+                                       normals[:,2] /= lengths
+
+                                       ePerDist = path['extrusion'][1:] / lengths
+                                       if useFilamentArea:
+                                               lineWidth = ePerDist / path['layerThickness'] / 2.0
+                                       else:
+                                               lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
+
+                                       normals[:,0] *= lineWidth
+                                       normals[:,1] *= lineWidth
+
+                                       b = numpy.zeros((len(a)-1, 0), numpy.float32)
+                                       b = numpy.concatenate((b, a[1:] + normals), 1)
+                                       b = numpy.concatenate((b, a[1:] - normals), 1)
+                                       b = numpy.concatenate((b, a[:-1] - normals), 1)
+                                       b = numpy.concatenate((b, a[:-1] + normals), 1)
+                                       b = b.reshape((len(b) * 4, 3))
+
+                                       i = numpy.arange(len(verts), len(verts) + len(b), 1, numpy.uint32)
+
+                                       verts = numpy.concatenate((verts, b))
+                                       indices = numpy.concatenate((indices, i))
+               return opengl.GLVBO(GL_QUADS, verts, indicesArray=indices)
+
+       def _gcodeToVBO_lines(self, gcodeLayers):
+               verts = numpy.zeros((0,3), numpy.float32)
+               indices = numpy.zeros((0), numpy.uint32)
+               for layer in gcodeLayers:
+                       for path in layer:
+                               if path['type'] == 'move':
+                                       a = path['points'] + numpy.array([0,0,0.02], numpy.float32)
+                                       i = numpy.arange(len(verts), len(verts) + len(a), 1, numpy.uint32)
+                                       i = numpy.dstack((i[0:-1],i[1:])).flatten()
+                                       verts = numpy.concatenate((verts, a))
+                                       indices = numpy.concatenate((indices, i))
+                               if path['type'] == 'retract':
+                                       a = path['points'] + numpy.array([0,0,0.02], numpy.float32)
+                                       a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
+                                       a = a.reshape((len(a) * 2, 3))
+                                       i = numpy.arange(len(verts), len(verts) + len(a), 1, numpy.uint32)
+                                       verts = numpy.concatenate((verts, a))
+                                       indices = numpy.concatenate((indices, i))
+               return opengl.GLVBO(GL_LINES, verts, indicesArray=indices)
+
+       def OnKeyChar(self, keyCode):
+               if not self._enabled:
+                       return
+
+               if wx.GetKeyState(wx.WXK_SHIFT) or wx.GetKeyState(wx.WXK_CONTROL):
+                       if keyCode == wx.WXK_UP:
+                               self.layerSelect.setValue(self.layerSelect.getValue() + 1)
+                               self._parent.QueueRefresh()
+                               return True
+                       elif keyCode == wx.WXK_DOWN:
+                               self.layerSelect.setValue(self.layerSelect.getValue() - 1)
+                               self._parent.QueueRefresh()
+                               return True
+                       elif keyCode == wx.WXK_PAGEUP:
+                               self.layerSelect.setValue(self.layerSelect.getValue() + 10)
+                               self._parent.QueueRefresh()
+                               return True
+                       elif keyCode == wx.WXK_PAGEDOWN:
+                               self.layerSelect.setValue(self.layerSelect.getValue() - 10)
+                               self._parent.QueueRefresh()
+                               return True
+               return False
+
+               # 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
+
+       # def _loadGCode(self):
+       #       self._gcode.progressCallback = self._gcodeLoadCallback
+       #       if self._gcodeFilename is not None:
+       #               self._gcode.load(self._gcodeFilename)
+       #       else:
+       #               self._gcode.load(self._gcodeData)
+       #
+       # 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
+
+                       # 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()
+
+
+# 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 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()
+       #
+       # 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
index 0bde41bebea8e733599c00cc4600cf4345467b74..7cf19b3d76fdab682e193566b586027d115c643c 100644 (file)
@@ -6,14 +6,11 @@ import numpy
 import wx
 import time
 
-from Cura.util import meshLoader
-from Cura.util import util3d
-from Cura.util import profile
-from Cura.util.resources import getPathForMesh, getPathForImage
+from Cura.util.resources import getPathForImage
 
 import OpenGL
 
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
 from OpenGL.GLUT import *
 from OpenGL.GLU import *
 from OpenGL.GL import *
@@ -131,26 +128,35 @@ class GLFakeShader(GLReferenceCounter):
                return ''
 
 class GLVBO(GLReferenceCounter):
-       def __init__(self, vertexArray, normalArray = None):
+       def __init__(self, renderType, vertexArray, normalArray = None, indicesArray = None):
                super(GLVBO, self).__init__()
+               self._renderType = renderType
                if not bool(glGenBuffers):
                        self._vertexArray = vertexArray
                        self._normalArray = normalArray
+                       self._indicesArray = indicesArray
                        self._size = len(vertexArray)
                        self._buffer = None
                        self._hasNormals = self._normalArray is not None
+                       self._hasIndices = self._indicesArray is not None
                else:
                        self._buffer = glGenBuffers(1)
                        self._size = len(vertexArray)
                        self._hasNormals = normalArray is not None
+                       self._hasIndices = indicesArray is not None
                        glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
                        if self._hasNormals:
                                glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
                        else:
                                glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
                        glBindBuffer(GL_ARRAY_BUFFER, 0)
+                       if self._hasIndices:
+                               self._size = len(indicesArray)
+                               self._bufferIndices = glGenBuffers(1)
+                               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
+                               glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
 
-       def render(self, render_type = GL_TRIANGLES):
+       def render(self):
                glEnableClientState(GL_VERTEX_ARRAY)
                if self._buffer is None:
                        glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
@@ -165,16 +171,23 @@ class GLVBO(GLReferenceCounter):
                                glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
                        else:
                                glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
+                       if self._hasIndices:
+                               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
 
-               batchSize = 996    #Warning, batchSize needs to be dividable by 4, 3 and 2
-               extraStartPos = int(self._size / batchSize) * batchSize
-               extraCount = self._size - extraStartPos
+               if self._hasIndices:
+                       glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
+               else:
+                       batchSize = 996    #Warning, batchSize needs to be dividable by 4, 3 and 2
+                       extraStartPos = int(self._size / batchSize) * batchSize
+                       extraCount = self._size - extraStartPos
+                       for i in xrange(0, int(self._size / batchSize)):
+                               glDrawArrays(self._renderType, i * batchSize, batchSize)
+                       glDrawArrays(self._renderType, extraStartPos, extraCount)
 
-               for i in xrange(0, int(self._size / batchSize)):
-                       glDrawArrays(render_type, i * batchSize, batchSize)
-               glDrawArrays(render_type, extraStartPos, extraCount)
                if self._buffer is not None:
                        glBindBuffer(GL_ARRAY_BUFFER, 0)
+               if self._hasIndices:
+                       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
 
                glDisableClientState(GL_VERTEX_ARRAY)
                if self._hasNormals:
@@ -545,106 +558,3 @@ def DrawMeshSteep(mesh, matrix, angle):
                        glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
                        glEnd()
        glDepthFunc(GL_LESS)
-
-def DrawGCodeLayer(layer, drawQuick = True):
-       filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
-       filamentArea = math.pi * filamentRadius * filamentRadius
-       lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
-
-       fillCycle = 0
-       fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
-       moveColor = [0, 0, 1, 0.5]
-       retractColor = [1, 0, 0.5, 0.5]
-       supportColor = [0, 1, 1, 1]
-       extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
-       innerWallColor = [0, 1, 0, 1]
-       skirtColor = [0, 0.5, 0.5, 1]
-       prevPathWasRetract = False
-
-       glDisable(GL_CULL_FACE)
-       for path in layer:
-               if path.type == 'move':
-                       if prevPathWasRetract:
-                               c = retractColor
-                       else:
-                               c = moveColor
-                       if drawQuick:
-                               continue
-               zOffset = 0.01
-               if path.type == 'extrude':
-                       if path.pathType == 'FILL':
-                               c = fillColorCycle[fillCycle]
-                               fillCycle = (fillCycle + 1) % len(fillColorCycle)
-                       elif path.pathType == 'WALL-INNER':
-                               c = innerWallColor
-                               zOffset = 0.02
-                       elif path.pathType == 'SUPPORT':
-                               c = supportColor
-                       elif path.pathType == 'SKIRT':
-                               c = skirtColor
-                       else:
-                               c = extrudeColor[path.extruder]
-               if path.type == 'retract':
-                       c = retractColor
-               if path.type == 'extrude' and not drawQuick:
-                       drawLength = 0.0
-                       prevNormal = None
-                       for i in xrange(0, len(path.points) - 1):
-                               v0 = path.points[i]
-                               v1 = path.points[i + 1]
-
-                               # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
-                               dist = (v0 - v1).vsize()
-                               if dist > 0 and path.layerThickness > 0:
-                                       extrusionMMperDist = (v1.e - v0.e) / dist
-                                       lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
-
-                               drawLength += (v0 - v1).vsize()
-                               normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
-                               normal.normalize()
-
-                               vv2 = v0 + normal * lineWidth
-                               vv3 = v1 + normal * lineWidth
-                               vv0 = v0 - normal * lineWidth
-                               vv1 = v1 - normal * lineWidth
-
-                               glBegin(GL_QUADS)
-                               glColor4fv(c)
-                               glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
-                               glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
-                               glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
-                               glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
-                               glEnd()
-                               if prevNormal is not None:
-                                       n = (normal + prevNormal)
-                                       n.normalize()
-                                       vv4 = v0 + n * lineWidth
-                                       vv5 = v0 - n * lineWidth
-                                       glBegin(GL_QUADS)
-                                       glColor4fv(c)
-                                       glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
-                                       glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
-                                       glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
-                                       glVertex3f(v0.x, v0.y, v0.z - zOffset)
-
-                                       glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
-                                       glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
-                                       glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
-                                       glVertex3f(v0.x, v0.y, v0.z - zOffset)
-                                       glEnd()
-
-                               prevNormal = normal
-                               prevVv1 = vv1
-                               prevVv3 = vv3
-               else:
-                       glColor4fv(c)
-                       glBegin(GL_TRIANGLES)
-                       for v in path.points:
-                               glVertex3f(v[0], v[1], v[2])
-                       glEnd()
-
-               if not path.type == 'move':
-                       prevPathWasRetract = False
-               #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
-               #       prevPathWasRetract = True
-       glEnable(GL_CULL_FACE)
index 48e216de38b26e193bf574597d11690212761ede..c9b0eeebe684408fc0d1573e2f3cf0e14a7879dd 100644 (file)
@@ -10,7 +10,7 @@ import time
 
 from wx import glcanvas
 import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
 from OpenGL.GL import *
 
 from Cura.util import version
@@ -245,6 +245,7 @@ class glGuiPanel(glcanvas.GLCanvas):
                                locationInfo = tb[n]
                                errStr += "\n @ %s:%s:%d" % (os.path.basename(locationInfo[0]), locationInfo[2], locationInfo[1])
                        if not self._shownError:
+                               traceback.print_exc()
                                wx.CallAfter(wx.MessageBox, errStr, _("3D window error"), wx.OK | wx.ICON_EXCLAMATION)
                                self._shownError = True
 
@@ -287,7 +288,7 @@ class glGuiPanel(glcanvas.GLCanvas):
                # glVertex2f(0, 0)
                # glEnd()
                # glDisable(GL_TEXTURE_2D)
-               glPopMatrix()
+               glPopMatrix()
 
        def _OnEraseBackground(self,event):
                #Workaround for windows background redraw flicker.
index dad34622a94792da63eb12b7428ec85253896f64..372d9cf2ff039bc3a3f6d16d4812ba043257665a 100644 (file)
@@ -6,7 +6,7 @@ import wx
 import numpy
 
 import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
 from OpenGL.GLU import *
 from OpenGL.GL import *
 
index 2d67464153f7a856e00ea65357888bf1a797d0fe..b86078cb41b82a5b28f0201326f79b703a25daec 100644 (file)
@@ -6,16 +6,11 @@ import math
 import os
 import time
 import numpy
+import types
+import cStringIO as StringIO
 
 from Cura.util import profile
 
-#class gcodePath(object):
-#      def __init__(self, newType, pathType, layerThickness, startPoint):
-#              self.type = newType
-#              self.pathType = pathType
-#              self.layerThickness = layerThickness
-#              self.points = [startPoint]
-#              self.extrusion = [0.0]
 def gcodePath(newType, pathType, layerThickness, startPoint):
        return {'type': newType,
                        'pathType': pathType,
@@ -28,22 +23,24 @@ class gcode(object):
                self.regMatch = {}
                self.layerList = None
                self.extrusionAmount = 0
-               self.totalMoveTimeMinute = 0
                self.filename = None
                self.progressCallback = None
        
-       def load(self, filename):
-               if os.path.isfile(filename):
-                       self.filename = filename
-                       self._fileSize = os.stat(filename).st_size
-                       gcodeFile = open(filename, 'r')
+       def load(self, data):
+               self.filename = None
+               if type(data) in types.StringTypes and os.path.isfile(data):
+                       self.filename = data
+                       self._fileSize = os.stat(data).st_size
+                       gcodeFile = open(data, 'r')
                        self._load(gcodeFile)
                        gcodeFile.close()
-       
-       def loadList(self, l):
-               self.filename = None
-               self._load(l)
-       
+               elif type(data) is list:
+                       self._load(data)
+               else:
+                       data = data.getvalue()
+                       self._fileSize = len(data)
+                       self._load(StringIO.StringIO(data))
+
        def calculateWeight(self):
                #Calculates the weight of the filament in kg
                radius = float(profile.getProfileSetting('filament_diameter')) / 2
@@ -66,11 +63,8 @@ class gcode(object):
                pos = [0.0,0.0,0.0]
                posOffset = [0.0, 0.0, 0.0]
                currentE = 0.0
-               totalExtrusion = 0.0
-               maxExtrusion = 0.0
                currentExtruder = 0
                extrudeAmountMultiply = 1.0
-               totalMoveTimeMinute = 0.0
                absoluteE = True
                scale = 1.0
                posAbs = True
@@ -148,12 +142,6 @@ class gcode(object):
                                                        pos[1] += y * scale
                                                if z is not None:
                                                        pos[2] += z * scale
-                                       #if f is not None:
-                                       #       feedRate = f
-                                       #if x is not None or y is not None or z is not None:
-                                       #       diffX = oldPos[0] - pos[0]
-                                       #       diffY = oldPos[1] - pos[1]
-                                       #       totalMoveTimeMinute += math.sqrt(diffX * diffX + diffY * diffY) / feedRate
                                        moveType = 'move'
                                        if e is not None:
                                                if absoluteE:
@@ -162,10 +150,7 @@ class gcode(object):
                                                        moveType = 'extrude'
                                                if e < 0.0:
                                                        moveType = 'retract'
-                                               totalExtrusion += e
                                                currentE += e
-                                               if totalExtrusion > maxExtrusion:
-                                                       maxExtrusion = totalExtrusion
                                        else:
                                                e = 0.0
                                        if moveType == 'move' and oldPos[2] != pos[2]:
@@ -181,11 +166,7 @@ class gcode(object):
                                        currentPath['extrusion'].append(e * extrudeAmountMultiply)
                                elif G == 4:    #Delay
                                        S = getCodeFloat(line, 'S')
-                                       if S is not None:
-                                               totalMoveTimeMinute += S / 60.0
                                        P = getCodeFloat(line, 'P')
-                                       if P is not None:
-                                               totalMoveTimeMinute += P / 60.0 / 1000.0
                                elif G == 10:   #Retract
                                        currentPath = gcodePath('retract', pathType, layerThickness, currentPath['points'][-1])
                                        currentPath['extruder'] = currentExtruder
@@ -290,10 +271,6 @@ class gcode(object):
                self.layerList.append(currentLayer)
                if self.progressCallback is not None and self._fileSize > 0:
                        self.progressCallback(float(gcodeFile.tell()) / float(self._fileSize))
-               self.extrusionAmount = maxExtrusion
-               self.totalMoveTimeMinute = totalMoveTimeMinute
-               #print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
-               #print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
 
 def getCodeInt(line, code):
        n = line.find(code) + 1
@@ -324,6 +301,5 @@ if __name__ == '__main__':
        for filename in sys.argv[1:]:
                g = gcode()
                g.load(filename)
-               print g.totalMoveTimeMinute
        print time.time() - t
 
index 414699758b1dc441762ddae6e0c59c561a8fe481..f53432dea1c2478165bda64376bf15b698537022 100644 (file)
@@ -186,7 +186,9 @@ setting('object_sink',               0.0, float, 'advanced', _('Quality')).setLa
 setting('overlap_dual',             0.15, float, 'advanced', _('Quality')).setLabel(_("Dual extrusion overlap (mm)"), _("Add a certain amount of overlapping extrusion on dual-extrusion prints. This bonds the different colors better together."))
 setting('travel_speed',            150.0, float, 'advanced', _('Speed')).setRange(0.1).setLabel(_("Travel speed (mm/s)"), _("Speed at which travel moves are done, a high quality build Ultimaker can reach speeds of 250mm/s. But some machines might miss steps then."))
 setting('bottom_layer_speed',         20, float, 'advanced', _('Speed')).setRange(0.1).setLabel(_("Bottom layer speed (mm/s)"), _("Print speed for the bottom layer, you want to print the first layer slower so it sticks better to the printer bed."))
-setting('infill_speed',              0.0, float, 'advanced', _('Speed')).setRange(0.0).setLabel(_("Infill speed (mm/s)"), _("Speed at which infill parts are printed. If set to 0 then the print speed is used for the infill. Printing the infill faster can greatly reduce printing, but this can negatively effect print quality.."))
+setting('infill_speed',              0.0, float, 'advanced', _('Speed')).setRange(0.0).setLabel(_("Infill speed (mm/s)"), _("Speed at which infill parts are printed. If set to 0 then the print speed is used for the infill. Printing the infill faster can greatly reduce printing, but this can negatively effect print quality."))
+setting('inset0_speed',              0.0, float, 'advanced', _('Speed')).setRange(0.0).setLabel(_("Outser shell speed (mm/s)"), _("Speed at which outer shell is printed. If set to 0 then the print speed is used. Printing the outer shell at a lower speed improves the final skin quality. However, having a large difference between the inner shell speed and the outer shell speed will effect quality in a negative way."))
+setting('insetx_speed',              0.0, float, 'advanced', _('Speed')).setRange(0.0).setLabel(_("Innser shell speed (mm/s)"), _("Speed at which inner shells are printed. If set to 0 then the print speed is used. Printing the inner shell faster then the outer shell will reduce printing time. It is good to set this somewhere in between the outer shell speed and the infill/printing speed."))
 setting('cool_min_layer_time',         5, float, 'advanced', _('Cool')).setRange(0).setLabel(_("Minimal layer time (sec)"), _("Minimum time spend in a layer, gives the layer time to cool down before the next layer is put on top. If the layer will be placed down too fast the printer will slow down to make sure it has spend at least this amount of seconds printing this layer."))
 setting('fan_enabled',              True, bool,  'advanced', _('Cool')).setLabel(_("Enable cooling fan"), _("Enable the cooling fan during the print. The extra cooling from the cooling fan is essential during faster prints."))
 
@@ -344,10 +346,10 @@ setting('filament_physical_density', '1240', float, 'preference', 'hidden').setR
 setting('language', 'English', str, 'preference', 'hidden').setLabel(_('Language'), _('Change the language in which Cura runs. Switching language requires a restart of Cura'))
 setting('active_machine', '0', int, 'preference', 'hidden')
 
-setting('model_colour', '#FFC924', str, 'preference', 'hidden').setLabel(_('Model colour'))
-setting('model_colour2', '#CB3030', str, 'preference', 'hidden').setLabel(_('Model colour (2)'))
-setting('model_colour3', '#DDD93C', str, 'preference', 'hidden').setLabel(_('Model colour (3)'))
-setting('model_colour4', '#4550D3', str, 'preference', 'hidden').setLabel(_('Model colour (4)'))
+setting('model_colour', '#FFC924', str, 'preference', 'hidden').setLabel(_('Model colour'), _('Display color for first extruder'))
+setting('model_colour2', '#CB3030', str, 'preference', 'hidden').setLabel(_('Model colour (2)'), _('Display color for second extruder'))
+setting('model_colour3', '#DDD93C', str, 'preference', 'hidden').setLabel(_('Model colour (3)'), _('Display color for third extruder'))
+setting('model_colour4', '#4550D3', str, 'preference', 'hidden').setLabel(_('Model colour (4)'), _('Display color for forth extruder'))
 
 setting('window_maximized', 'True', bool, 'preference', 'hidden')
 setting('window_pos_x', '-1', float, 'preference', 'hidden')
@@ -963,8 +965,8 @@ def replaceGCodeTags(filename, gcodeInt):
 def replaceGCodeTagsFromSlicer(filename, slicerInt):
        f = open(filename, 'r+')
        data = f.read(2048)
-       data = data.replace('#P_TIME#', slicerInt.getPrintTime())
-       data = data.replace('#F_AMNT#', slicerInt.getFilamentAmount())
+       data = data.replace('#P_TIME#', ('%8.2f' % (int(slicerInt._printTimeSeconds)))[-8:])
+       data = data.replace('#F_AMNT#', ('%8.2f' % (slicerInt._filamentMM[0]))[-8:])
        data = data.replace('#F_WGHT#', ('%8.2f' % (float(slicerInt.getFilamentWeight()) * 1000))[-8:])
        cost = slicerInt.getFilamentCost()
        if cost is None:
index f72d09626ed5b2f7e1113053a794b8e9efe1ec38..16bd664b212fa5d60d29963441004add5a79e345 100644 (file)
@@ -12,9 +12,13 @@ import sys
 import urllib
 import urllib2
 import hashlib
+import socket
+import struct
+import cStringIO as StringIO
 
 from Cura.util import profile
 from Cura.util import version
+from Cura.util import gcodeInterpreter
 
 def getEngineFilename():
        if platform.system() == 'Windows':
@@ -35,53 +39,20 @@ def getTempFilename():
        warnings.simplefilter('default')
        return ret
 
-class Slicer(object):
-       def __init__(self, progressCallback):
-               self._process = None
-               self._thread = None
-               self._callback = progressCallback
-               self._binaryStorageFilename = getTempFilename()
-               self._exportFilename = getTempFilename()
-               self._progressSteps = ['inset', 'skin', 'export']
-               self._objCount = 0
-               self._sliceLog = []
+class EngineResult(object):
+       def __init__(self):
+               self._engineLog = []
+               self._gcodeData = StringIO.StringIO()
+               self._polygons = []
+               self._success = False
                self._printTimeSeconds = None
-               self._filamentMM = [0.0, 0.0]
+               self._filamentMM = [0.0] * 4
                self._modelHash = None
-               self._id = 0
-
-       def cleanup(self):
-               self.abortSlicer()
-               try:
-                       os.remove(self._binaryStorageFilename)
-               except:
-                       pass
-               try:
-                       os.remove(self._exportFilename)
-               except:
-                       pass
-
-       def abortSlicer(self):
-               if self._process is not None:
-                       try:
-                               self._process.terminate()
-                       except:
-                               pass
-                       self._thread.join()
-               self._thread = None
-
-       def wait(self):
-               if self._thread is not None:
-                       self._thread.join()
-
-       def getGCodeFilename(self):
-               return self._exportFilename
-
-       def getSliceLog(self):
-               return self._sliceLog
-
-       def getID(self):
-               return self._id
+               self._profileString = profile.getProfileString()
+               self._preferencesString = profile.getPreferencesString()
+               self._gcodeInterpreter = gcodeInterpreter.gcode()
+               self._gcodeLoadThread = None
+               self._finished = False
 
        def getFilamentWeight(self, e=0):
                #Calculates the weight of the filament in kg
@@ -112,7 +83,165 @@ class Slicer(object):
                        return None
                return '%0.2f meter %0.0f gram' % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
 
-       def runSlicer(self, scene):
+       def getLog(self):
+               return self._engineLog
+
+       def getGCode(self):
+               return self._gcodeData.getvalue()
+
+       def addLog(self, line):
+               self._engineLog.append(line)
+
+       def setHash(self, hash):
+               self._modelHash = hash
+
+       def setFinished(self, result):
+               self._finished = result
+
+       def isFinished(self):
+               return self._finished
+
+       def getGCodeLayers(self, loadCallback):
+               if not self._finished:
+                       return None
+               if self._gcodeInterpreter.layerList is None and self._gcodeLoadThread is None:
+                       self._gcodeInterpreter.progressCallback = self._gcodeInterpreterCallback
+                       self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData))
+                       self._gcodeLoadCallback = loadCallback
+                       self._gcodeLoadThread.daemon = True
+                       self._gcodeLoadThread.start()
+               return self._gcodeInterpreter.layerList
+
+       def _gcodeInterpreterCallback(self, progress):
+               if len(self._gcodeInterpreter.layerList) % 5 == 0:
+                       time.sleep(0.1)
+               return self._gcodeLoadCallback(self, progress)
+
+       def submitInfoOnline(self):
+               if profile.getPreference('submit_slice_information') != 'True':
+                       return
+               if version.isDevVersion():
+                       return
+               data = {
+                       'processor': platform.processor(),
+                       'machine': platform.machine(),
+                       'platform': platform.platform(),
+                       'profile': self._profileString,
+                       'preferences': self._preferencesString,
+                       'modelhash': self._modelHash,
+                       'version': version.getVersion(),
+               }
+               try:
+                       f = urllib2.urlopen("http://www.youmagine.com/curastats/", data = urllib.urlencode(data), timeout = 1)
+                       f.read()
+                       f.close()
+               except:
+                       pass
+
+class Engine(object):
+       GUI_CMD_REQUEST_MESH = 0x01
+       GUI_CMD_SEND_POLYGONS = 0x02
+
+       def __init__(self, progressCallback):
+               self._process = None
+               self._thread = None
+               self._callback = progressCallback
+               self._progressSteps = ['inset', 'skin', 'export']
+               self._objCount = 0
+               self._result = None
+
+               self._serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+               self._serverPortNr = 0xC20A
+               while True:
+                       try:
+                               self._serversocket.bind(('127.0.0.1', self._serverPortNr))
+                       except:
+                               print "Failed to listen on port: %d" % (self._serverPortNr)
+                               self._serverPortNr += 1
+                               if self._serverPortNr > 0xFFFF:
+                                       print "Failed to listen on any port..."
+                                       break
+                       else:
+                               break
+               print 'Listening for engine communications on %d' % (self._serverPortNr)
+               self._serversocket.listen(1)
+               thread = threading.Thread(target=self._socketListenThread)
+               thread.daemon = True
+               thread.start()
+
+       def _socketListenThread(self):
+               while True:
+                       sock, _ = self._serversocket.accept()
+                       thread = threading.Thread(target=self._socketConnectionThread, args=(sock,))
+                       thread.daemon = True
+                       thread.start()
+
+       def _socketConnectionThread(self, sock):
+               while True:
+                       try:
+                               data = sock.recv(4)
+                       except:
+                               data = ''
+                       if len(data) == 0:
+                               sock.close()
+                               return
+                       cmd = struct.unpack('@i', data)[0]
+                       if cmd == self.GUI_CMD_REQUEST_MESH:
+                               meshInfo = self._modelData[0]
+                               self._modelData = self._modelData[1:]
+                               sock.sendall(struct.pack('@i', meshInfo[0]))
+                               sock.sendall(meshInfo[1].tostring())
+                       elif cmd == self.GUI_CMD_SEND_POLYGONS:
+                               cnt = struct.unpack('@i', sock.recv(4))[0]
+                               layerNr = struct.unpack('@i', sock.recv(4))[0]
+                               z = struct.unpack('@i', sock.recv(4))[0]
+                               z = float(z) / 1000.0
+                               typeNameLen = struct.unpack('@i', sock.recv(4))[0]
+                               typeName = sock.recv(typeNameLen)
+                               while len(self._result._polygons) < layerNr + 1:
+                                       self._result._polygons.append({})
+                               polygons = self._result._polygons[layerNr]
+                               if typeName not in polygons:
+                                       polygons[typeName] = []
+                               for n in xrange(0, cnt):
+                                       length = struct.unpack('@i', sock.recv(4))[0]
+                                       data = ''
+                                       while len(data) < length * 8 * 2:
+                                               recvData = sock.recv(length * 8 * 2 - len(data))
+                                               if len(recvData) < 1:
+                                                       return
+                                               data += recvData
+                                       polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0
+                                       polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
+                                       polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
+                                       polygon[:,:-1] = polygon2d
+                                       polygon[:,2] = z
+                                       polygons[typeName].append(polygon)
+                       else:
+                               print "Unknown command on socket: %x" % (cmd)
+
+       def cleanup(self):
+               self.abortEngine()
+               self._serversocket.close()
+
+       def abortEngine(self):
+               if self._process is not None:
+                       try:
+                               self._process.terminate()
+                       except:
+                               pass
+               if self._thread is not None:
+                       self._thread.join()
+               self._thread = None
+
+       def wait(self):
+               if self._thread is not None:
+                       self._thread.join()
+
+       def getResult(self):
+               return self._result
+
+       def runEngine(self, scene):
                if len(scene.objects()) < 1:
                        return
                extruderCount = 1
@@ -122,97 +251,122 @@ class Slicer(object):
 
                extruderCount = max(extruderCount, profile.minimalExtruderCount())
 
-               commandList = [getEngineFilename(), '-vv']
+               commandList = [getEngineFilename(), '-vvv']
                for k, v in self._engineSettings(extruderCount).iteritems():
                        commandList += ['-s', '%s=%s' % (k, str(v))]
-               commandList += ['-o', self._exportFilename]
-               commandList += ['-b', self._binaryStorageFilename]
+               commandList += ['-g', '%d' % self._serverPortNr]
                self._objCount = 0
-               with open(self._binaryStorageFilename, "wb") as f:
-                       hash = hashlib.sha512()
-                       order = scene.printOrder()
-                       if order is None:
-                               pos = numpy.array(profile.getMachineCenterCoords()) * 1000
-                               objMin = None
-                               objMax = None
-                               for obj in scene.objects():
-                                       if scene.checkPlatform(obj):
-                                               oMin = obj.getMinimum()[0:2] + obj.getPosition()
-                                               oMax = obj.getMaximum()[0:2] + obj.getPosition()
-                                               if objMin is None:
-                                                       objMin = oMin
-                                                       objMax = oMax
-                                               else:
-                                                       objMin[0] = min(oMin[0], objMin[0])
-                                                       objMin[1] = min(oMin[1], objMin[1])
-                                                       objMax[0] = max(oMax[0], objMax[0])
-                                                       objMax[1] = max(oMax[1], objMax[1])
-                               pos += (objMin + objMax) / 2.0 * 1000
-                               commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
+               engineModelData = []
+               hash = hashlib.sha512()
+               order = scene.printOrder()
+               if order is None:
+                       pos = numpy.array(profile.getMachineCenterCoords()) * 1000
+                       objMin = None
+                       objMax = None
+                       for obj in scene.objects():
+                               if scene.checkPlatform(obj):
+                                       oMin = obj.getMinimum()[0:2] + obj.getPosition()
+                                       oMax = obj.getMaximum()[0:2] + obj.getPosition()
+                                       if objMin is None:
+                                               objMin = oMin
+                                               objMax = oMax
+                                       else:
+                                               objMin[0] = min(oMin[0], objMin[0])
+                                               objMin[1] = min(oMin[1], objMin[1])
+                                               objMax[0] = max(oMax[0], objMax[0])
+                                               objMax[1] = max(oMax[1], objMax[1])
+                       if objMin is None:
+                               return
+                       pos += (objMin + objMax) / 2.0 * 1000
+                       commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
+
+                       vertexTotal = [0] * 4
+                       meshMax = 1
+                       for obj in scene.objects():
+                               if scene.checkPlatform(obj):
+                                       meshMax = max(meshMax, len(obj._meshList))
+                                       for n in xrange(0, len(obj._meshList)):
+                                               vertexTotal[n] += obj._meshList[n].vertexCount
 
-                               vertexTotal = [0] * 4
-                               meshMax = 1
+                       for n in xrange(0, meshMax):
+                               verts = numpy.zeros((0, 3), numpy.float32)
                                for obj in scene.objects():
                                        if scene.checkPlatform(obj):
-                                               meshMax = max(meshMax, len(obj._meshList))
-                                               for n in xrange(0, len(obj._meshList)):
-                                                       vertexTotal[n] += obj._meshList[n].vertexCount
-
-                               for n in xrange(0, meshMax):
-                                       f.write(numpy.array([vertexTotal[n]], numpy.int32).tostring())
-                                       for obj in scene.objects():
-                                               if scene.checkPlatform(obj):
-                                                       if n < len(obj._meshList):
-                                                               vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
-                                                               vertexes -= obj._drawOffset
-                                                               vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
-                                                               f.write(vertexes.tostring())
-                                                               hash.update(obj._meshList[n].vertexes.tostring())
-
-                               commandList += ['#' * meshMax]
-                               self._objCount = 1
-                       else:
-                               for n in order:
-                                       obj = scene.objects()[n]
-                                       for mesh in obj._meshList:
-                                               f.write(numpy.array([mesh.vertexCount], numpy.int32).tostring())
-                                               s = mesh.vertexes.tostring()
-                                               f.write(s)
-                                               hash.update(s)
-                                       pos = obj.getPosition() * 1000
-                                       pos += numpy.array(profile.getMachineCenterCoords()) * 1000
-                                       commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
-                                       commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
-                                       commandList += ['#' * len(obj._meshList)]
-                                       self._objCount += 1
-                       self._modelHash = hash.hexdigest()
+                                               if n < len(obj._meshList):
+                                                       vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
+                                                       vertexes -= obj._drawOffset
+                                                       vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
+                                                       verts = numpy.concatenate((verts, vertexes))
+                                                       hash.update(obj._meshList[n].vertexes.tostring())
+                               engineModelData.append((vertexTotal[n], verts))
+
+                       commandList += ['$' * meshMax]
+                       self._objCount = 1
+               else:
+                       for n in order:
+                               obj = scene.objects()[n]
+                               for mesh in obj._meshList:
+                                       engineModelData.append((mesh.vertexCount, mesh.vertexes))
+                                       hash.update(mesh.vertexes.tostring())
+                               pos = obj.getPosition() * 1000
+                               pos += numpy.array(profile.getMachineCenterCoords()) * 1000
+                               commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
+                               commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
+                               commandList += ['$' * len(obj._meshList)]
+                               self._objCount += 1
+               modelHash = hash.hexdigest()
                if self._objCount > 0:
-                       self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread))
+                       self._modelData = engineModelData
+                       self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, modelHash))
                        self._thread.daemon = True
                        self._thread.start()
 
-       def _watchProcess(self, commandList, oldThread):
+       def _watchProcess(self, commandList, oldThread, modelHash):
                if oldThread is not None:
                        if self._process is not None:
                                self._process.terminate()
                        oldThread.join()
-               self._id += 1
-               self._callback(-1.0, False)
+               self._callback(-1.0)
                try:
-                       self._process = self._runSliceProcess(commandList)
+                       self._process = self._runEngineProcess(commandList)
                except OSError:
                        traceback.print_exc()
                        return
                if self._thread != threading.currentThread():
                        self._process.terminate()
-               self._callback(0.0, False)
-               self._sliceLog = []
-               self._printTimeSeconds = None
-               self._filamentMM = [0.0, 0.0]
 
-               line = self._process.stdout.readline()
+               self._result = EngineResult()
+               self._result.setHash(modelHash)
+               self._callback(0.0)
+
+               logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
+               logThread.daemon = True
+               logThread.start()
+
+               data = self._process.stdout.read(4096)
+               while len(data) > 0:
+                       self._result._gcodeData.write(data)
+                       data = self._process.stdout.read(4096)
+
+               returnCode = self._process.wait()
+               logThread.join()
+               if returnCode == 0:
+                       pluginError = None #profile.runPostProcessingPlugins(self._exportFilename)
+                       if pluginError is not None:
+                               print pluginError
+                               self._result.addLog(pluginError)
+                       self._result.setFinished(True)
+                       self._callback(1.0)
+               else:
+                       for line in self._result.getLog():
+                               print line
+                       self._callback(-1.0)
+               self._process = None
+
+       def _watchStderr(self, stderr):
                objectNr = 0
-               while len(line):
+               line = stderr.readline()
+               while len(line) > 0:
                        line = line.strip()
                        if line.startswith('Progress:'):
                                line = line.split(':')
@@ -226,41 +380,24 @@ class Slicer(object):
                                        progressValue /= self._objCount
                                        progressValue += 1.0 / self._objCount * objectNr
                                        try:
-                                               self._callback(progressValue, False)
+                                               self._callback(progressValue)
                                        except:
                                                pass
                        elif line.startswith('Print time:'):
-                               self._printTimeSeconds = int(line.split(':')[1].strip())
+                               self._result._printTimeSeconds = int(line.split(':')[1].strip())
                        elif line.startswith('Filament:'):
-                               self._filamentMM[0] = int(line.split(':')[1].strip())
+                               self._result._filamentMM[0] = int(line.split(':')[1].strip())
                                if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                                        radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
-                                       self._filamentMM[0] /= (math.pi * radius * radius)
+                                       self._result._filamentMM[0] /= (math.pi * radius * radius)
                        elif line.startswith('Filament2:'):
-                               self._filamentMM[1] = int(line.split(':')[1].strip())
+                               self._result._filamentMM[1] = int(line.split(':')[1].strip())
                                if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                                        radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
-                                       self._filamentMM[1] /= (math.pi * radius * radius)
+                                       self._result._filamentMM[1] /= (math.pi * radius * radius)
                        else:
-                               self._sliceLog.append(line.strip())
-                       line = self._process.stdout.readline()
-               for line in self._process.stderr:
-                       self._sliceLog.append(line.strip())
-               returnCode = self._process.wait()
-               try:
-                       if returnCode == 0:
-                               pluginError = profile.runPostProcessingPlugins(self._exportFilename)
-                               if pluginError is not None:
-                                       print pluginError
-                                       self._sliceLog.append(pluginError)
-                               self._callback(1.0, True)
-                       else:
-                               for line in self._sliceLog:
-                                       print line
-                               self._callback(-1.0, False)
-               except:
-                       pass
-               self._process = None
+                               self._result.addLog(line)
+                       line = stderr.readline()
 
        def _engineSettings(self, extruderCount):
                settings = {
@@ -277,6 +414,8 @@ class Slicer(object):
                        'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
                        'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
                        'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
+                       'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
+                       'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
                        'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
                        'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
                        'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
@@ -355,13 +494,13 @@ class Slicer(object):
                        settings['gcodeFlavor'] = 1
                if profile.getProfileSetting('spiralize') == 'True':
                        settings['spiralizeMode'] = 1
-               if profile.getProfileSetting('wipe_tower') == 'True':
+               if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
                        settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
                if profile.getProfileSetting('ooze_shield') == 'True':
                        settings['enableOozeShield'] = 1
                return settings
 
-       def _runSliceProcess(self, cmdList):
+       def _runEngineProcess(self, cmdList):
                kwargs = {}
                if subprocess.mswindows:
                        su = subprocess.STARTUPINFO()
@@ -370,24 +509,3 @@ class Slicer(object):
                        kwargs['startupinfo'] = su
                        kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
                return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
-
-       def submitSliceInfoOnline(self):
-               if profile.getPreference('submit_slice_information') != 'True':
-                       return
-               if version.isDevVersion():
-                       return
-               data = {
-                       'processor': platform.processor(),
-                       'machine': platform.machine(),
-                       'platform': platform.platform(),
-                       'profile': profile.getProfileString(),
-                       'preferences': profile.getPreferencesString(),
-                       'modelhash': self._modelHash,
-                       'version': version.getVersion(),
-               }
-               try:
-                       f = urllib2.urlopen("http://www.youmagine.com/curastats/", data = urllib.urlencode(data), timeout = 1)
-                       f.read()
-                       f.close()
-               except:
-                       pass
index 28b5e7b50d0ac7a4d292d8dbd8924ad05e5086dc..a9df5f45e6e8f59b34ac80723b92798bcf09a785 100644 (file)
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ sudo apt-get install python-setuptools
 
 cd Cura
 
-sudo ./package.sh debian
+sudo ./package.sh debian_amd64          # or debian_i386 for 32bit
 
 sudo dpkg -i ./scripts/linux/Cura*.deb
 ```
@@ -51,31 +51,31 @@ We assume you already have Apple hardware with [64bit processor](http://support.
 ###Install Python
 You'll need **non-system**, **framework-based**, **universal** with **deployment target set to 10.6** build of Python 2.7
 
-**non-system**: Output of  
-`python -c "import sys; print sys.prefix"`  
+**non-system**: Output of
+`python -c "import sys; print sys.prefix"`
 should *not* start with *"/System/Library/Frameworks/Python.framework/"*.
 
-**framework-based**: Output of  
-`python -c "import distutils.sysconfig as c; print(c.get_config_var('PYTHONFRAMEWORK'))"`  
+**framework-based**: Output of
+`python -c "import distutils.sysconfig as c; print(c.get_config_var('PYTHONFRAMEWORK'))"`
 should be non-empty string. E.g. *Python*.
 
-**universal**: Output of  
-``lipo -info `which python` ``  
+**universal**: Output of
+``lipo -info `which python` ``
 should include both i386 and x86_64. E.g *"Architectures in the fat file: /usr/local/bin/python are: i386 x86_64"*.
 
-**deployment target set to 10.6**: Output of  
-``otool -l `which python` ``  
+**deployment target set to 10.6**: Output of
+``otool -l `which python` ``
 should contain *"cmd LC_VERSION_MIN_MACOSX ... version 10.6"*.
 
-The easiest way to install it is via [Homebrew](http://mxcl.github.com/homebrew/) using the formula from Cura's repo:  
-`brew install --build-bottle --fresh Cura/scripts/darwin/python.rb --universal`  
+The easiest way to install it is via [Homebrew](http://mxcl.github.com/homebrew/) using the formula from Cura's repo:
+`brew install --build-bottle --fresh Cura/scripts/darwin/python.rb --universal`
 Note if you already have Python installed via Homebrew, you have to uninstall it first.
 
 You can also install [official build](http://www.python.org/ftp/python/2.7.3/python-2.7.3-macosx10.6.dmg).
 
 
 ###Configure Virtualenv
-Create new virtualenv. If you have [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) installed:  
+Create new virtualenv. If you have [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) installed:
 `mkvirtualenv Cura`
 
 wxPython cannot be installed via pip, we have to build it from source by specifing prefix to our virtualenv.
@@ -108,8 +108,8 @@ Assuming you have virtualenv at *~/.virtualenvs/Cura/* and [wxPython sources](ht
         --with-osx_cocoa \
         --with-zlib=builtin
 
-2. `make install`  
-    Note to speedup the process I recommend you to enable multicore build by adding the -j*cores* flag:  
+2. `make install`
+    Note to speedup the process I recommend you to enable multicore build by adding the -j*cores* flag:
     `make -j4 install`
 3. `cd` into *~/Downloads/wxPython-src-2.9.4.0/wxPython/*
 4. Build wxPython (Note `python` is the python of your virtualenv):
@@ -143,17 +143,17 @@ Assuming you have virtualenv at *~/.virtualenvs/Cura/* and [wxPython sources](ht
         export PYTHONHOME=$ENV
         exec $PYTHON "$@"
 
-At this point virtualenv is configured for wxPython development.  
+At this point virtualenv is configured for wxPython development.
 Remember to use `python` for pacakging and `pythonw` to run app for debugging.
 
 
 ###Install Python Packages
-Required python packages are specified in *requirements.txt* and *requirements_darwin.txt*  
+Required python packages are specified in *requirements.txt* and *requirements_darwin.txt*
 If you use virtualenv, installing requirements as easy as `pip install -r requirements_darwin.txt`
 
 
 ###Package Cura into application
-Ensure that virtualenv is activated, so `python` points to the python of your virtualenv (e.g. ~/.virtualenvs/Cura/bin/python).Use package.sh to build Cura:  
+Ensure that virtualenv is activated, so `python` points to the python of your virtualenv (e.g. ~/.virtualenvs/Cura/bin/python).Use package.sh to build Cura:
 `./package.sh darwin`
 
 Note that application is only guaranteed to work on Mac OS X version used to build and higher, but may not support lower versions.
index c5414c63d0d4cec7916c7908658e60db131a961e..cdecc0901d90abab2cd02d1e48bf4b3edb70740c 100755 (executable)
@@ -18,7 +18,7 @@ BUILD_TARGET=${1:-all}
 ##Do we need to create the final archive
 ARCHIVE_FOR_DISTRIBUTION=1
 ##Which version name are we appending to the final archive
-export BUILD_NAME=14.01
+export BUILD_NAME=14.02-TEST1
 TARGET_DIR=Cura-${BUILD_NAME}-${BUILD_TARGET}
 
 ##Which versions of external programs to use