import traceback
import threading
import math
+import platform
import OpenGL
OpenGL.ERROR_CHECKING = False
from Cura.gui.util import previewTools
from Cura.gui.util import opengl
from Cura.gui.util import openglGui
+from Cura.gui.tools import youmagineGui
+from Cura.gui.tools import imageToMesh
class SceneView(openglGui.glGuiPanel):
def __init__(self, parent):
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._selectedObj = None
self._objColors = [None,None,None,None]
self._viewTarget = numpy.array([0,0,0], numpy.float32)
self._animView = None
self._animZoom = None
- self._platformMesh = meshLoader.loadMeshes(resources.getPathForMesh('ultimaker_platform.stl'))[0]
- self._platformMesh._drawOffset = numpy.array([0,0,2.5], numpy.float32)
+ self._platformMesh = {}
self._isSimpleMode = True
+ self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh())
self._viewport = None
self._modelMatrix = None
self._projMatrix = None
self.tempMatrix = None
- self.openFileButton = openglGui.glButton(self, 4, 'Load', (0,0), self.showLoadModel)
- self.printButton = openglGui.glButton(self, 6, 'Print', (1,0), self.showPrintWindow)
+ self.openFileButton = openglGui.glButton(self, 4, _("Load"), (0,0), self.showLoadModel)
+ self.printButton = openglGui.glButton(self, 6, _("Print"), (1,0), self.OnPrintButton)
self.printButton.setDisabled(True)
group = []
- self.rotateToolButton = openglGui.glRadioButton(self, 8, 'Rotate', (0,-1), group, self.OnToolSelect)
- self.scaleToolButton = openglGui.glRadioButton(self, 9, 'Scale', (1,-1), group, self.OnToolSelect)
- self.mirrorToolButton = openglGui.glRadioButton(self, 10, 'Mirror', (2,-1), group, self.OnToolSelect)
+ self.rotateToolButton = openglGui.glRadioButton(self, 8, _("Rotate"), (0,-1), group, self.OnToolSelect)
+ self.scaleToolButton = openglGui.glRadioButton(self, 9, _("Scale"), (1,-1), group, self.OnToolSelect)
+ self.mirrorToolButton = openglGui.glRadioButton(self, 10, _("Mirror"), (2,-1), group, self.OnToolSelect)
- self.resetRotationButton = openglGui.glButton(self, 12, 'Reset', (0,-2), self.OnRotateReset)
- self.layFlatButton = openglGui.glButton(self, 16, 'Lay flat', (0,-3), self.OnLayFlat)
+ self.resetRotationButton = openglGui.glButton(self, 12, _("Reset"), (0,-2), self.OnRotateReset)
+ self.layFlatButton = openglGui.glButton(self, 16, _("Lay flat"), (0,-3), self.OnLayFlat)
- self.resetScaleButton = openglGui.glButton(self, 13, 'Reset', (1,-2), self.OnScaleReset)
- self.scaleMaxButton = openglGui.glButton(self, 17, 'To max', (1,-3), self.OnScaleMax)
+ self.resetScaleButton = openglGui.glButton(self, 13, _("Reset"), (1,-2), self.OnScaleReset)
+ self.scaleMaxButton = openglGui.glButton(self, 17, _("To max"), (1,-3), self.OnScaleMax)
- self.mirrorXButton = openglGui.glButton(self, 14, 'Mirror X', (2,-2), lambda button: self.OnMirror(0))
- self.mirrorYButton = openglGui.glButton(self, 18, 'Mirror Y', (2,-3), lambda button: self.OnMirror(1))
- self.mirrorZButton = openglGui.glButton(self, 22, 'Mirror Z', (2,-4), lambda button: self.OnMirror(2))
+ self.mirrorXButton = openglGui.glButton(self, 14, _("Mirror X"), (2,-2), lambda button: self.OnMirror(0))
+ self.mirrorYButton = openglGui.glButton(self, 18, _("Mirror Y"), (2,-3), lambda button: self.OnMirror(1))
+ self.mirrorZButton = openglGui.glButton(self, 22, _("Mirror Z"), (2,-4), lambda button: self.OnMirror(2))
self.rotateToolButton.setExpandArrow(True)
self.scaleToolButton.setExpandArrow(True)
self.scaleForm = openglGui.glFrame(self, (2, -2))
openglGui.glGuiLayoutGrid(self.scaleForm)
- openglGui.glLabel(self.scaleForm, 'Scale X', (0,0))
+ openglGui.glLabel(self.scaleForm, _("Scale X"), (0,0))
self.scaleXctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,0), lambda value: self.OnScaleEntry(value, 0))
- openglGui.glLabel(self.scaleForm, 'Scale Y', (0,1))
+ openglGui.glLabel(self.scaleForm, _("Scale Y"), (0,1))
self.scaleYctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,1), lambda value: self.OnScaleEntry(value, 1))
- openglGui.glLabel(self.scaleForm, 'Scale Z', (0,2))
+ openglGui.glLabel(self.scaleForm, _("Scale Z"), (0,2))
self.scaleZctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,2), lambda value: self.OnScaleEntry(value, 2))
- openglGui.glLabel(self.scaleForm, 'Size X (mm)', (0,4))
+ openglGui.glLabel(self.scaleForm, _("Size X (mm)"), (0,4))
self.scaleXmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,4), lambda value: self.OnScaleEntryMM(value, 0))
- openglGui.glLabel(self.scaleForm, 'Size Y (mm)', (0,5))
+ openglGui.glLabel(self.scaleForm, _("Size Y (mm)"), (0,5))
self.scaleYmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,5), lambda value: self.OnScaleEntryMM(value, 1))
- openglGui.glLabel(self.scaleForm, 'Size Z (mm)', (0,6))
+ openglGui.glLabel(self.scaleForm, _("Size Z (mm)"), (0,6))
self.scaleZmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,6), lambda value: self.OnScaleEntryMM(value, 2))
- openglGui.glLabel(self.scaleForm, 'Uniform scale', (0,8))
+ openglGui.glLabel(self.scaleForm, _("Uniform scale"), (0,8))
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, 100, 0, 100, (-1,-2), lambda : self.QueueRefresh())
+ 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.updateToolButtons()
self.updateProfileToControls()
+ 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
+ self.printButton.setBottomText('')
+ self.viewSelection.setValue(4)
+ self.printButton.setDisabled(False)
+ self.youMagineButton.setDisabled(True)
+ self.OnViewChange()
+
+ def loadSceneFiles(self, filenames):
+ self.youMagineButton.setDisabled(False)
+ #if self.viewSelection.getValue() == 4:
+ # self.viewSelection.setValue(0)
+ # self.OnViewChange()
+ self.loadScene(filenames)
+
+ def loadFiles(self, filenames):
+ mainWindow = self.GetParent().GetParent().GetParent()
+ # only one GCODE file can be active
+ # so if single gcode file, process this
+ # otherwise ignore all gcode files
+ gcodeFilename = None
+ if len(filenames) == 1:
+ filename = filenames[0]
+ ext = os.path.splitext(filename)[1].lower()
+ if ext == '.g' or ext == '.gcode':
+ gcodeFilename = filename
+ mainWindow.addToModelMRU(filename)
+ if gcodeFilename is not None:
+ self.loadGCodeFile(gcodeFilename)
+ else:
+ # process directories and special file types
+ # and keep scene files for later processing
+ scene_filenames = []
+ ignored_types = dict()
+ # use file list as queue
+ # pop first entry for processing and append new files at end
+ while filenames:
+ filename = filenames.pop(0)
+ if os.path.isdir(filename):
+ # directory: queue all included files and directories
+ filenames.extend(os.path.join(filename, f) for f in os.listdir(filename))
+ else:
+ ext = os.path.splitext(filename)[1].lower()
+ if ext == '.ini':
+ profile.loadProfile(filename)
+ mainWindow.addToProfileMRU(filename)
+ elif ext in meshLoader.loadSupportedExtensions() or ext in imageToMesh.supportedExtensions():
+ scene_filenames.append(filename)
+ mainWindow.addToModelMRU(filename)
+ else:
+ ignored_types[ext] = 1
+ if ignored_types:
+ ignored_types = ignored_types.keys()
+ ignored_types.sort()
+ self.notification.message("ignored: " + " ".join("*" + type for type in ignored_types))
+ mainWindow.updateProfileToAllControls()
+ # now process all the scene files
+ if scene_filenames:
+ self.loadSceneFiles(scene_filenames)
+ self._selectObject(None)
+ self.sceneUpdated()
+ newZoom = numpy.max(self._machineSize)
+ self._animView = openglGui.animation(self, self._viewTarget.copy(), numpy.array([0,0,0], numpy.float32), 0.5)
+ self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
+
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=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() + imageToMesh.wildcardList() + "|GCode file (*.gcode)|*.g;*.gcode;*.G;*.GCODE")
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
if len(filenames) < 1:
return False
profile.putPreference('lastFile', filenames[0])
- gcodeFilename = None
- for filename in filenames:
- self.GetParent().GetParent().GetParent().addToModelMRU(filename)
- ext = filename[filename.rfind('.')+1:].upper()
- if ext == 'G' or ext == 'GCODE':
- gcodeFilename = filename
- if gcodeFilename is not 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 = gcodeFilename
- self.printButton.setBottomText('')
- self.viewSelection.setValue(4)
- self.printButton.setDisabled(False)
- self.OnViewChange()
- else:
- if self.viewSelection.getValue() == 4:
- self.viewSelection.setValue(0)
- self.OnViewChange()
- self.loadScene(filenames)
+ self.loadFiles(filenames)
def showSaveModel(self):
if len(self._scene.objects()) < 1:
return
- dlg=wx.FileDialog(self, 'Save 3D model', os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
+ dlg=wx.FileDialog(self, _("Save 3D model"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
dlg.SetWildcard(meshLoader.saveWildcardFilter())
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
dlg.Destroy()
meshLoader.saveMeshes(filename, self._scene.objects())
- def showPrintWindow(self, button):
+ def OnPrintButton(self, button):
if button == 1:
if machineCom.machineIsConnected():
- printWindow.printFile(self._gcodeFilename)
- if self._gcodeFilename == self._slicer.getGCodeFilename():
- self._slicer.submitSliceInfoOnline()
+ self.showPrintWindow()
elif len(removableStorage.getPossibleSDcardDrives()) > 0:
drives = removableStorage.getPossibleSDcardDrives()
if len(drives) > 1:
self.showSaveGCode()
if button == 3:
menu = wx.Menu()
- self.Bind(wx.EVT_MENU, lambda e: printWindow.printFile(self._gcodeFilename), menu.Append(-1, 'Print with USB'))
- 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.showPrintWindow(), menu.Append(-1, _("Print with USB")))
+ 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.PopupMenu(menu)
menu.Destroy()
+ 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()
+
def showSaveGCode(self):
- defPath = profile.getPreference('lastFile')
- defPath = defPath[0:defPath.rfind('.')] + '.gcode'
- dlg=wx.FileDialog(self, 'Save toolpath', defPath, style=wx.FD_SAVE)
- dlg.SetFilename(self._scene._objectList[0].getName())
+ 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() + '.gcode'
+ dlg.SetFilename(filename)
dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
self._slicer.submitSliceInfoOnline()
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)
+ dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
dlg.ShowModal()
dlg.Destroy()
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.layerSelect.setValue(len(self._gcode.layerList) - 1)
self._selectObject(None)
elif self.viewSelection.getValue() == 1:
self.viewMode = 'overhang'
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
self._selectObject(None)
self.sceneUpdated()
+ def OnCenter(self, e):
+ if self._focusObj is None:
+ return
+ self._focusObj.setPosition(numpy.array([0.0, 0.0]))
+ self._scene.pushFree()
+
def _splitCallback(self, progress):
print progress
def OnMergeObjects(self, e):
if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
+ if len(self._scene.objects()) == 2:
+ self._scene.merge(self._scene.objects()[0], self._scene.objects()[1])
+ self.sceneUpdated()
return
self._scene.merge(self._selectedObj, self._focusObj)
self.sceneUpdated()
time.sleep(0.1)
if self._gcode is None:
return True
- if self.layerSelect.getValue() == self.layerSelect.getMaxValue():
- self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
- self.layerSelect.setValue(self.layerSelect.getMaxValue())
- else:
- self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
+ 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:
self._scene.add(obj)
self._scene.centerAll()
self._selectObject(obj)
+ if obj.getScale()[0] < 1.0:
+ self.notification.message("Warning: Object scaled down.")
self.sceneUpdated()
def _deleteObject(self, obj):
self.updateProfileToControls()
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:
def updateProfileToControls(self):
oldSimpleMode = self._isSimpleMode
self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
- if self._isSimpleMode and not oldSimpleMode:
+ if self._isSimpleMode != oldSimpleMode:
self._scene.arrangeAll()
self.sceneUpdated()
- self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
+ 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.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_min_y'), profile.getPreferenceFloat('extruder_head_size_max_y'), profile.getPreferenceFloat('extruder_head_size_height'))
+ 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'))
if self._selectedObj is not None:
scale = self._selectedObj.getScale()
self.scaleZmmctrl.setValue(round(size[2], 2))
def OnKeyChar(self, keyCode):
- if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
+ 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 e.GetButton() == 3:
menu = wx.Menu()
if self._focusObj is not None:
- self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
- self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
- self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
- if self._selectedObj != self._focusObj and self._focusObj is not None and int(profile.getPreference('extruder_amount')) > 1:
- self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
+ self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, _("Delete object")))
+ self.Bind(wx.EVT_MENU, self.OnCenter, menu.Append(-1, _("Center on platform")))
+ self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, _("Multiply object")))
+ self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, _("Split object into parts")))
+ if ((self._selectedObj != self._focusObj and self._focusObj is not None and self._selectedObj is not None) or len(self._scene.objects()) == 2) and int(profile.getMachineSetting('extruder_amount')) > 1:
+ self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, _("Dual extrusion merge")))
if len(self._scene.objects()) > 0:
- self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
+ self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, _("Delete all objects")))
if menu.MenuItemCount > 0:
self.PopupMenu(menu)
menu.Destroy()
self.Refresh()
def OnMouseLeave(self, e):
- self._mouseX = -1
+ #self._mouseX = -1
+ pass
def getMouseRay(self, x, y):
if self._viewport is None:
def OnPaint(self,e):
if machineCom.machineIsConnected():
self.printButton._imageID = 6
- self.printButton._tooltip = 'Print'
+ self.printButton._tooltip = _("Print")
elif len(removableStorage.getPossibleSDcardDrives()) > 0:
self.printButton._imageID = 2
- self.printButton._tooltip = 'Toolpath to SD'
+ self.printButton._tooltip = _("Toolpath to SD")
else:
self.printButton._imageID = 3
- self.printButton._tooltip = 'Save toolpath'
+ self.printButton._tooltip = _("Save toolpath")
if self._animView is not None:
self._viewTarget = self._animView.getPosition()
gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
}
""")
- else:
+ if self._objectShader is None or not self._objectShader.isValid():
self._objectShader = opengl.GLFakeShader()
self._objectOverhangShader = opengl.GLFakeShader()
self._objectLoadShader = None
self._gcodeLoadThread.start()
if self._gcode is not None and self._gcode.layerList is not None:
glPushMatrix()
- glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
+ 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):
break
#['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
if n == drawUpTill - 1:
- if len(self._gcodeVBOs[n]) < 6:
+ if len(self._gcodeVBOs[n]) < 9:
self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
glColor3f(c, 0, 0)
- self._gcodeVBOs[n][5].render(GL_QUADS)
+ 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][6].render(GL_QUADS)
+ self._gcodeVBOs[n][12].render(GL_QUADS)
glColor3f(c/2, c/2, 0.0)
- self._gcodeVBOs[n][7].render(GL_QUADS)
+ self._gcodeVBOs[n][13].render(GL_QUADS)
glColor3f(0, c, c)
- self._gcodeVBOs[n][8].render(GL_QUADS)
- self._gcodeVBOs[n][9].render(GL_QUADS)
+ self._gcodeVBOs[n][14].render(GL_QUADS)
+ self._gcodeVBOs[n][15].render(GL_QUADS)
glColor3f(0, 0, c)
- self._gcodeVBOs[n][10].render(GL_LINES)
+ self._gcodeVBOs[n][16].render(GL_LINES)
else:
glColor3f(c, 0, 0)
self._gcodeVBOs[n][0].render(GL_LINES)
- glColor3f(0, c, 0)
+ glColor3f(c/2, 0, c)
self._gcodeVBOs[n][1].render(GL_LINES)
- glColor3f(c/2, c/2, 0.0)
+ glColor3f(0, c, c/2)
self._gcodeVBOs[n][2].render(GL_LINES)
- glColor3f(0, c, c)
+ 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:
glStencilFunc(GL_ALWAYS, 1, 1)
self._drawMachine()
+ if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID():
+ glEnable(GL_BLEND)
+ 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':
if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
glDisable(GL_DEPTH_TEST)
glLoadIdentity()
glTranslate(0,-4,-10)
glColor4ub(60,60,60,255)
- opengl.glDrawStringCenter('Loading toolpath for visualization...')
+ opengl.glDrawStringCenter(_("Loading toolpath for visualization..."))
glPopMatrix()
else:
#Draw the object box-shadow, so you can see where it will collide with other objects.
glLoadIdentity()
glTranslate(0,-4,-10)
glColor4ub(60,60,60,255)
- opengl.glDrawStringCenter('Overhang view not working due to lack of OpenGL shaders support.')
+ opengl.glDrawStringCenter(_("Overhang view not working due to lack of OpenGL shaders support."))
glPopMatrix()
def _renderObject(self, obj, brightness = False, addSink = True):
glEnable(GL_CULL_FACE)
glEnable(GL_BLEND)
- if profile.getPreference('machine_type') == 'ultimaker':
+ 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 not in self._platformMesh:
+ meshes = meshLoader.loadMeshes(resources.getPathForMesh(machine + '_platform.stl'))
+ if len(meshes) > 0:
+ self._platformMesh[machine] = meshes[0]
+ else:
+ self._platformMesh[machine] = None
+ if machine == 'ultimaker2':
+ self._platformMesh[machine]._drawOffset = numpy.array([0,-37,145], numpy.float32)
+ else:
+ self._platformMesh[machine]._drawOffset = numpy.array([0,0,2.5], numpy.float32)
glColor4f(1,1,1,0.5)
self._objectShader.bind()
- self._renderObject(self._platformMesh, False, False)
+ self._renderObject(self._platformMesh[machine], False, False)
self._objectShader.unbind()
- size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
+ #For the Ultimaker 2 render the texture on the back plate to show the Ultimaker2 text.
+ if machine == 'ultimaker2':
+ if not hasattr(self._platformMesh[machine], 'texture'):
+ self._platformMesh[machine].texture = opengl.loadGLTexture('Ultimaker2backplate.png')
+ glBindTexture(GL_TEXTURE_2D, self._platformMesh[machine].texture)
+ glEnable(GL_TEXTURE_2D)
+ glPushMatrix()
+ glColor4f(1,1,1,1)
+
+ glTranslate(0,150,-5)
+ h = 50
+ d = 8
+ w = 100
+ glEnable(GL_BLEND)
+ glBlendFunc(GL_DST_COLOR, GL_ZERO)
+ glBegin(GL_QUADS)
+ glTexCoord2f(1, 0)
+ glVertex3f( w, 0, h)
+ glTexCoord2f(0, 0)
+ glVertex3f(-w, 0, h)
+ glTexCoord2f(0, 1)
+ glVertex3f(-w, 0, 0)
+ glTexCoord2f(1, 1)
+ glVertex3f( w, 0, 0)
+
+ glTexCoord2f(1, 0)
+ glVertex3f(-w, d, h)
+ glTexCoord2f(0, 0)
+ glVertex3f( w, d, h)
+ glTexCoord2f(0, 1)
+ glVertex3f( w, d, 0)
+ glTexCoord2f(1, 1)
+ glVertex3f(-w, d, 0)
+ glEnd()
+ glDisable(GL_TEXTURE_2D)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+ glPopMatrix()
+ else:
+ glColor4f(0,0,0,1)
+ glLineWidth(3)
+ glBegin(GL_LINES)
+ glVertex3f(-size[0] / 2, -size[1] / 2, 0)
+ glVertex3f(-size[0] / 2, -size[1] / 2, 10)
+ glVertex3f(-size[0] / 2, -size[1] / 2, 0)
+ glVertex3f(-size[0] / 2+10, -size[1] / 2, 0)
+ glVertex3f(-size[0] / 2, -size[1] / 2, 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]]
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]
glVertex3f(x1, y2, -0.02)
glEnd()
- glDisableClientState(GL_VERTEX_ARRAY)
glDisable(GL_BLEND)
glDisable(GL_CULL_FACE)
def _generateGCodeVBOs(self, layer):
ret = []
- for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
+ 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:
+ 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))
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', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
+ 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:
+ 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[:,2] /= lens
ePerDist = path['extrusion'][1:] / lens
- lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
+ if useFilamentArea:
+ lineWidth = ePerDist / path['layerThickness'] / 2.0
+ else:
+ lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
normal[:,0] *= lineWidth
normal[:,1] *= lineWidth
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]), 1)
- #b = numpy.concatenate((b, a[:-1]), 1)
b = b.reshape((len(b) * 4, 3))
if len(a) > 2: