import traceback
import threading
import math
-import glob
+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.gui import printWindow
+from Cura.gui import printWindow2
from Cura.util import profile
from Cura.util import meshLoader
from Cura.util import objectScene
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
class SceneView(openglGui.glGuiPanel):
def __init__(self, parent):
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._animView = None
self._animZoom = None
self._platformMesh = {}
+ self._platformTexture = None
self._isSimpleMode = True
self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh())
+ self._printerConnectionManager = printerConnectionManager.PrinterConnectionManager()
self._viewport = None
self._modelMatrix = 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)
gcodeFilename = None
if len(filenames) == 1:
filename = filenames[0]
- ext = filename[filename.rfind('.'):].lower()
+ ext = os.path.splitext(filename)[1].lower()
if ext == '.g' or ext == '.gcode':
gcodeFilename = filename
mainWindow.addToModelMRU(filename)
# directory: queue all included files and directories
filenames.extend(os.path.join(filename, f) for f in os.listdir(filename))
else:
- ext = filename[filename.rfind('.'):].lower()
+ ext = os.path.splitext(filename)[1].lower()
if ext == '.ini':
profile.loadProfile(filename)
mainWindow.addToProfileMRU(filename)
- elif ext in meshLoader.loadSupportedExtensions():
+ elif ext in meshLoader.loadSupportedExtensions() or ext in imageToMesh.supportedExtensions():
scene_filenames.append(filename)
mainWindow.addToModelMRU(filename)
else:
def showLoadModel(self, button = 1):
if button == 1:
dlg=wx.FileDialog(self, _("Open 3D model"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST|wx.FD_MULTIPLE)
- dlg.SetWildcard(meshLoader.loadWildcardFilter() + "|GCode file (*.gcode)|*.g;*.gcode;*.G;*.GCODE")
+ dlg.SetWildcard(meshLoader.loadWildcardFilter() + imageToMesh.wildcardList() + "|GCode file (*.gcode)|*.g;*.gcode;*.G;*.GCODE")
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
def OnPrintButton(self, button):
if button == 1:
+ connectionGroup = self._printerConnectionManager.getAvailableGroup()
if machineCom.machineIsConnected():
self.showPrintWindow()
- elif len(removableStorage.getPossibleSDcardDrives()) > 0:
+ elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
drives = removableStorage.getPossibleSDcardDrives()
if len(drives) > 1:
dlg = wx.SingleChoiceDialog(self, "Select SD drive", "Multiple removable drives have been found,\nplease select your SD card drive", map(lambda n: n[0], drives))
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:
+ connection = connections[0]
+ else:
+ dlg = wx.SingleChoiceDialog(self, "Select the %s connection to use" % (connectionGroup.getName()), "Multiple %s connections found" % (connectionGroup.getName()), map(lambda n: n.getName(), connections))
+ if dlg.ShowModal() != wx.ID_OK:
+ dlg.Destroy()
+ return
+ connection = connections[dlg.GetSelection()]
+ dlg.Destroy()
+ self._openPrintWindowForConnection(connection)
else:
self.showSaveGCode()
if button == 3:
menu = wx.Menu()
self.Bind(wx.EVT_MENU, lambda e: self.showPrintWindow(), menu.Append(-1, _("Print with USB")))
+ connections = self._printerConnectionManager.getAvailableConnections()
+ menu.connectionMap = {}
+ for connection in connections:
+ i = menu.Append(-1, _("Print with %s") % (connection.getName()))
+ 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()
+ def _openPrintWindowForConnection(self, connection):
+ print '_openPrintWindowForConnection', connection.getName()
+ if connection.window is None or not connection.window:
+ 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.")
+ else:
+ self.notification.message("Failed to start print...")
+
def showPrintWindow(self):
if self._gcodeFilename is None:
return
- self._usbPrintMonitor.loadFile(self._gcodeFilename, self._slicer.getID())
- if self._gcodeFilename == self._slicer.getGCodeFilename():
- self._slicer.submitSliceInfoOnline()
+ 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
+ #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:
+ return
dlg=wx.FileDialog(self, _("Save toolpath"), os.path.dirname(profile.getPreference('lastFile')), style=wx.FD_SAVE)
- filename = self._scene._objectList[0].getName()
- filename = filename[:filename.rfind('.')] + '.gcode'
+ filename = self._scene._objectList[0].getName() + '.gcode'
dlg.SetFilename(filename)
dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
if dlg.ShowModal() != wx.ID_OK:
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.notification.message('You can now eject the card.') if removableStorage.ejectDrive(allowEject) else self.notification.message('Safe remove failed...'))
+ if ejectDrive:
+ self.notification.message("Saved as %s" % (targetFilename), lambda : self._doEjectSD(ejectDrive), 31, 'Eject')
+ elif explorer.hasExplorer():
+ 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 _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 _doEjectSD(self, drive):
+ if removableStorage.ejectDrive(drive):
+ self.notification.message('You can now eject the card.')
+ else:
+ self.notification.message('Safe remove failed...')
+
+ 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):
if self._selectedObj is None:
return
self._selectedObj.resetRotation()
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.sceneUpdated()
if self._selectedObj is None:
return
self._selectedObj.layFlat()
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.sceneUpdated()
def OnScaleMax(self, button):
if self._selectedObj is None:
return
- self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
- self._scene.pushFree()
+ machine = profile.getMachineSetting('machine_type')
+ self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
+ self._scene.pushFree(self._selectedObj)
+ #self.sceneUpdated()
+ if machine == "ultimaker2":
+ #This is bad and Jaime should feel bad!
+ self._selectedObj.setPosition(numpy.array([0.0,-10.0]))
+ self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
+ self._selectedObj.setPosition(numpy.array([0.0,0.0]))
+ self._scene.pushFree(self._selectedObj)
+ else:
+ self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
+ self._scene.pushFree(self._selectedObj)
+ self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.updateProfileToControls()
self.sceneUpdated()
return
self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
self.updateProfileToControls()
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.sceneUpdated()
return
self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
self.updateProfileToControls()
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.sceneUpdated()
if self._focusObj is None:
return
obj = self._focusObj
- dlg = wx.NumberEntryDialog(self, "How many copies do you want?", "Copies", "Multiply", 1, 1, 100)
+ dlg = wx.NumberEntryDialog(self, _("How many copies do you want?"), _("Number of copies"), _("Multiply"), 1, 1, 100)
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
if self._focusObj is None:
return
self._focusObj.setPosition(numpy.array([0.0, 0.0]))
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
+ newViewPos = numpy.array([self._focusObj.getPosition()[0], self._focusObj.getPosition()[1], self._focusObj.getSize()[2] / 2])
+ self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
+ self.sceneUpdated()
def _splitCallback(self, progress):
print progress
def sceneUpdated(self):
self._sceneUpdateTimer.Start(500, True)
- self._slicer.abortSlicer()
- self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
+ 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)
- cost = self._slicer.getFilamentCost()
- if cost is not None:
- self.printButton.setBottomText('%s\n%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount(), cost))
- else:
- self.printButton.setBottomText('%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount()))
- self._gcode = gcodeInterpreter.gcode()
- self._gcodeFilename = self._slicer.getGCodeFilename()
+ text = '%s' % (result.getPrintTime())
+ for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))):
+ amount = result.getFilamentAmount(e)
+ if amount is None:
+ continue
+ text += '\n%s' % (amount)
+ cost = result.getFilamentCost(e)
+ if cost is not None:
+ text += '\n%s' % (cost)
+ self.printButton.setBottomText(text)
else:
self.printButton.setBottomText('')
self.QueueRefresh()
- def _loadGCode(self):
- self._gcode.progressCallback = self._gcodeLoadCallback
- self._gcode.load(self._gcodeFilename)
-
- def _gcodeLoadCallback(self, progress):
- if 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:
- objList = meshLoader.loadMeshes(filename)
+ ext = os.path.splitext(filename)[1].lower()
+ if ext in imageToMesh.supportedExtensions():
+ imageToMesh.convertImageDialog(self, filename).Show()
+ objList = []
+ else:
+ objList = meshLoader.loadMeshes(filename)
except:
traceback.print_exc()
else:
else:
obj._loadAnim = None
self._scene.add(obj)
- self._scene.centerAll()
+ if not self._scene.checkPlatform(obj):
+ self._scene.centerAll()
self._selectObject(obj)
if obj.getScale()[0] < 1.0:
self.notification.message("Warning: Object scaled down.")
def _selectObject(self, obj, zoom = True):
if obj != self._selectedObj:
self._selectedObj = obj
- self.updateProfileToControls()
+ self.updateModelSettingsToControls()
self.updateToolButtons()
if zoom and obj is not None:
- newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
+ newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2])
self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
newZoom = obj.getBoundaryCircle() * 6
if newZoom > numpy.max(self._machineSize) * 3:
if self._isSimpleMode != oldSimpleMode:
self._scene.arrangeAll()
self.sceneUpdated()
+ self._scene.updateSizeOffsets(True)
self._machineSize = numpy.array([profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')])
self._objColors[0] = profile.getPreferenceColour('model_colour')
self._objColors[1] = profile.getPreferenceColour('model_colour2')
self._objColors[2] = profile.getPreferenceColour('model_colour3')
self._objColors[3] = profile.getPreferenceColour('model_colour4')
- self._scene.setMachineSize(self._machineSize)
- self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
- self._scene.setHeadSize(profile.getMachineSettingFloat('extruder_head_size_min_x'), profile.getMachineSettingFloat('extruder_head_size_max_x'), profile.getMachineSettingFloat('extruder_head_size_min_y'), profile.getMachineSettingFloat('extruder_head_size_max_y'), profile.getMachineSettingFloat('extruder_head_size_height'))
+ self._scene.updateMachineDimensions()
+ self.updateModelSettingsToControls()
+ def updateModelSettingsToControls(self):
if self._selectedObj is not None:
scale = self._selectedObj.getScale()
size = self._selectedObj.getSize()
self.scaleZmmctrl.setValue(round(size[2], 2))
def OnKeyChar(self, keyCode):
- if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
+ 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 keyCode == wx.WXK_UP:
- self.layerSelect.setValue(self.layerSelect.getValue() + 1)
+ 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:
- self.layerSelect.setValue(self.layerSelect.getValue() - 1)
+ 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('='):
+ 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.layerSelect.setValue(self.layerSelect.getValue() + 10)
+ self._yaw = 0
+ self._pitch = 0
self.QueueRefresh()
elif keyCode == wx.WXK_PAGEDOWN:
- self.layerSelect.setValue(self.layerSelect.getValue() - 10)
+ 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):
self.PopupMenu(menu)
menu.Destroy()
elif self._mouseState == 'dragObject' and self._selectedObj is not None:
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self.sceneUpdated()
elif self._mouseState == 'tool':
if self.tempMatrix is not None and self._selectedObj is not None:
self._selectedObj.applyMatrix(self.tempMatrix)
- self._scene.pushFree()
+ self._scene.pushFree(self._selectedObj)
self._selectObject(self._selectedObj)
self.tempMatrix = None
self.tool.OnDragEnd()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
def OnPaint(self,e):
+ connectionGroup = self._printerConnectionManager.getAvailableGroup()
if machineCom.machineIsConnected():
self.printButton._imageID = 6
self.printButton._tooltip = _("Print")
- elif len(removableStorage.getPossibleSDcardDrives()) > 0:
+ elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
self.printButton._imageID = 2
self.printButton._tooltip = _("Toolpath to SD")
+ elif connectionGroup is not None:
+ self.printButton._imageID = connectionGroup.getIconID()
+ self.printButton._tooltip = _("Print with %s") % (connectionGroup.getName())
else:
self.printButton._imageID = 3
self.printButton._tooltip = _("Save toolpath")
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("""
gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
}
""")
- if self._objectShader == None or not self._objectShader.isValid():
+ if self._objectShader is None or not self._objectShader.isValid():
self._objectShader = opengl.GLFakeShader()
self._objectOverhangShader = opengl.GLFakeShader()
self._objectLoadShader = None
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)
if self.viewMode == 'overhang':
self._objectOverhangShader.bind()
- self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - 60)))
+ self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - profile.getProfileSettingFloat('support_angle'))))
else:
self._objectShader.bind()
for obj in self._scene.objects():
self._drawMachine()
- if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID():
- glEnable(GL_BLEND)
+ if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._engine.getID():
z = self._usbPrintMonitor.getZ()
- size = self._machineSize
- glColor4ub(255,255,0,128)
- glBegin(GL_QUADS)
- glVertex3f(-size[0]/2,-size[1]/2, z)
- glVertex3f( size[0]/2,-size[1]/2, z)
- glVertex3f( size[0]/2, size[1]/2, z)
- glVertex3f(-size[0]/2, size[1]/2, z)
- glEnd()
+ if self.viewMode == 'gcode':
+ layer_height = profile.getProfileSettingFloat('layer_height')
+ layer1_height = profile.getProfileSettingFloat('bottom_thickness')
+ if layer_height > 0:
+ if layer1_height > 0:
+ layer = int((z - layer1_height) / layer_height) + 1
+ else:
+ layer = int(z / layer_height)
+ else:
+ layer = 1
+ self.layerSelect.setValue(layer)
+ else:
+ size = self._machineSize
+ glEnable(GL_BLEND)
+ glColor4ub(255,255,0,128)
+ glBegin(GL_QUADS)
+ glVertex3f(-size[0]/2,-size[1]/2, z)
+ glVertex3f( size[0]/2,-size[1]/2, z)
+ glVertex3f( size[0]/2, size[1]/2, z)
+ 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 and len(self._scene.objects()) > 1:
- size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
- glPushMatrix()
- glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+ if self._selectedObj is not None:
glEnable(GL_BLEND)
glEnable(GL_CULL_FACE)
- glColor4f(0,0,0,0.12)
- glBegin(GL_QUADS)
- glVertex3f(-size[0], size[1], 0.1)
- glVertex3f(-size[0], -size[1], 0.1)
- glVertex3f( size[0], -size[1], 0.1)
- glVertex3f( size[0], size[1], 0.1)
- glEnd()
+ glColor4f(0,0,0,0.16)
+ glDepthMask(False)
+ for obj in self._scene.objects():
+ glPushMatrix()
+ glTranslatef(obj.getPosition()[0], obj.getPosition()[1], 0)
+ glBegin(GL_TRIANGLE_FAN)
+ for p in obj._boundaryHull[::-1]:
+ glVertex3f(p[0], p[1], 0)
+ glEnd()
+ glPopMatrix()
+ if self._scene.isOneAtATime():
+ glPushMatrix()
+ glColor4f(0,0,0,0.06)
+ glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+ glBegin(GL_TRIANGLE_FAN)
+ for p in self._selectedObj._printAreaHull[::-1]:
+ glVertex3f(p[0], p[1], 0)
+ glEnd()
+ glBegin(GL_TRIANGLE_FAN)
+ for p in self._selectedObj._headAreaMinHull[::-1]:
+ glVertex3f(p[0], p[1], 0)
+ glEnd()
+ glPopMatrix()
+ glDepthMask(True)
glDisable(GL_CULL_FACE)
- glPopMatrix()
#Draw the outline of the selected object, on top of everything else except the GUI.
if self._selectedObj is not None and self._selectedObj._loadAnim is None:
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
size = [profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')]
machine = profile.getMachineSetting('machine_type')
- if profile.getMachineSetting('machine_type').startswith('ultimaker'):
+ if machine.startswith('ultimaker'):
if machine not in self._platformMesh:
meshes = meshLoader.loadMeshes(resources.getPathForMesh(machine + '_platform.stl'))
if len(meshes) > 0:
glVertex3f(-size[0] / 2, -size[1] / 2+10, 0)
glEnd()
- v0 = [ size[0] / 2, size[1] / 2, size[2]]
- v1 = [ size[0] / 2,-size[1] / 2, size[2]]
- v2 = [-size[0] / 2, size[1] / 2, size[2]]
- v3 = [-size[0] / 2,-size[1] / 2, size[2]]
- v4 = [ size[0] / 2, size[1] / 2, 0]
- v5 = [ size[0] / 2,-size[1] / 2, 0]
- v6 = [-size[0] / 2, size[1] / 2, 0]
- v7 = [-size[0] / 2,-size[1] / 2, 0]
-
- vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
- glEnableClientState(GL_VERTEX_ARRAY)
- glVertexPointer(3, GL_FLOAT, 3*4, vList)
-
- glColor4ub(5, 171, 231, 64)
- glDrawArrays(GL_QUADS, 0, 4)
- glColor4ub(5, 171, 231, 96)
- glDrawArrays(GL_QUADS, 4, 8)
- glColor4ub(5, 171, 231, 128)
- glDrawArrays(GL_QUADS, 12, 8)
- glDisableClientState(GL_VERTEX_ARRAY)
-
- sx = self._machineSize[0]
- sy = self._machineSize[1]
- for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
- for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
- x1 = x * 10
- x2 = x1 + 10
- y1 = y * 10
- y2 = y1 + 10
- x1 = max(min(x1, sx/2), -sx/2)
- y1 = max(min(y1, sy/2), -sy/2)
- x2 = max(min(x2, sx/2), -sx/2)
- y2 = max(min(y2, sy/2), -sy/2)
- if (x & 1) == (y & 1):
- glColor4ub(5, 171, 231, 127)
+ glDepthMask(False)
+
+ polys = profile.getMachineSizePolygons()
+ height = profile.getMachineSettingFloat('machine_height')
+ circular = profile.getMachineSetting('machine_shape') == 'Circular'
+ glBegin(GL_QUADS)
+ for n in xrange(0, len(polys[0])):
+ if not circular:
+ if n % 2 == 0:
+ glColor4ub(5, 171, 231, 96)
else:
- glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
- glBegin(GL_QUADS)
- glVertex3f(x1, y1, -0.02)
- glVertex3f(x2, y1, -0.02)
- glVertex3f(x2, y2, -0.02)
- glVertex3f(x1, y2, -0.02)
- glEnd()
+ glColor4ub(5, 171, 231, 64)
+ else:
+ glColor4ub(5, 171, 231, 96)
+ glVertex3f(polys[0][n][0], polys[0][n][1], height)
+ glVertex3f(polys[0][n][0], polys[0][n][1], 0)
+ glVertex3f(polys[0][n-1][0], polys[0][n-1][1], 0)
+ glVertex3f(polys[0][n-1][0], polys[0][n-1][1], height)
+ glEnd()
+ glColor4ub(5, 171, 231, 128)
+ glBegin(GL_TRIANGLE_FAN)
+ for p in polys[0][::-1]:
+ glVertex3f(p[0], p[1], height)
+ glEnd()
+
+ #Draw checkerboard
+ if self._platformTexture is None:
+ self._platformTexture = opengl.loadGLTexture('checkerboard.png')
+ glBindTexture(GL_TEXTURE_2D, self._platformTexture)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
+ glColor4f(1,1,1,0.5)
+ glBindTexture(GL_TEXTURE_2D, self._platformTexture)
+ glEnable(GL_TEXTURE_2D)
+ glBegin(GL_TRIANGLE_FAN)
+ for p in polys[0]:
+ glTexCoord2f(p[0]/20, p[1]/20)
+ glVertex3f(p[0], p[1], 0)
+ glEnd()
+ glDisable(GL_TEXTURE_2D)
+ glColor4ub(127, 127, 127, 200)
+ for poly in polys[1:]:
+ glBegin(GL_TRIANGLE_FAN)
+ for p in poly:
+ glTexCoord2f(p[0]/20, p[1]/20)
+ glVertex3f(p[0], p[1], 0)
+ glEnd()
+
+ glDepthMask(True)
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]