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
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)"))
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')
#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):
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
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 *
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
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
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)
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)
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:
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()
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.")
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:
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):
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()
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:
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):
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:
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())
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("""
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)
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')
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)
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
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]
--- /dev/null
+__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
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 *
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)
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:
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)
from wx import glcanvas
import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
from OpenGL.GL import *
from Cura.util import version
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
# glVertex2f(0, 0)
# glEnd()
# glDisable(GL_TEXTURE_2D)
- glPopMatrix()
+ # glPopMatrix()
def _OnEraseBackground(self,event):
#Workaround for windows background redraw flicker.
import numpy
import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
from OpenGL.GLU import *
from OpenGL.GL import *
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,
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
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
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:
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]:
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
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
for filename in sys.argv[1:]:
g = gcode()
g.load(filename)
- print g.totalMoveTimeMinute
print time.time() - t
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."))
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')
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:
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':
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
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
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(':')
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 = {
'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,
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()
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
cd Cura
-sudo ./package.sh debian
+sudo ./package.sh debian_amd64 # or debian_i386 for 32bit
sudo dpkg -i ./scripts/linux/Cura*.deb
```
###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.
--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):
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.
##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