X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=Cura%2Fgui%2FsceneView.py;h=01ce44a03da8d3791f7108503fec3ba7870964bf;hb=805ed88766a2abf1cb9c9f4691c9989423c99a3e;hp=6b235257b9b9a812de7cf27591c25c5ee9550b34;hpb=6c49c57b430d0f3c8773aa916eae4ab601452615;p=cura.git diff --git a/Cura/gui/sceneView.py b/Cura/gui/sceneView.py index 6b235257..01ce44a0 100644 --- a/Cura/gui/sceneView.py +++ b/Cura/gui/sceneView.py @@ -8,7 +8,7 @@ import os import traceback import threading import math -import glob +import platform import OpenGL OpenGL.ERROR_CHECKING = False @@ -24,10 +24,12 @@ from Cura.util import sliceEngine from Cura.util import machineCom from Cura.util import removableStorage from Cura.util import gcodeInterpreter +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.tools import youmagineGui +from Cura.gui.tools import imageToMesh class SceneView(openglGui.glGuiPanel): def __init__(self, parent): @@ -55,6 +57,7 @@ class SceneView(openglGui.glGuiPanel): self._platformMesh = {} self._isSimpleMode = True self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh()) + self._printerConnectionManager = printerConnectionManager.PrinterConnectionManager() self._viewport = None self._modelMatrix = None @@ -151,7 +154,7 @@ class SceneView(openglGui.glGuiPanel): 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) @@ -170,11 +173,11 @@ class SceneView(openglGui.glGuiPanel): # 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: @@ -196,7 +199,7 @@ class SceneView(openglGui.glGuiPanel): 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 @@ -221,9 +224,11 @@ class SceneView(openglGui.glGuiPanel): def OnPrintButton(self, button): if button == 1: + + connectionEntry = self._printerConnectionManager.getAvailableConnection() if machineCom.machineIsConnected(): self.showPrintWindow() - elif len(removableStorage.getPossibleSDcardDrives()) > 0: + elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 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)) @@ -236,6 +241,9 @@ class SceneView(openglGui.glGuiPanel): drive = drives[0] filename = self._scene._objectList[0].getName() + '.gcode' threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start() + elif connectionEntry is not None: + connectionEntry.connection.loadFile(self._gcodeFilename) + connectionEntry.connection.startPrint() else: self.showSaveGCode() if button == 3: @@ -249,13 +257,19 @@ class SceneView(openglGui.glGuiPanel): def showPrintWindow(self): if self._gcodeFilename is None: return + 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() 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) - dlg.SetFilename(self._scene._objectList[0].getName()+'.gcode') + filename = self._scene._objectList[0].getName() + '.gcode' + dlg.SetFilename(filename) dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g') if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() @@ -371,7 +385,20 @@ class SceneView(openglGui.glGuiPanel): 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)) + machine = profile.getMachineSetting('machine_type') + self._selectedObj.setPosition(numpy.array([0.0, 0.0])) + self._scene.pushFree() + #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() + else: + self._selectedObj.setPosition(numpy.array([0.0, 0.0])) + self._scene.pushFree() + 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._selectObject(self._selectedObj) self.updateProfileToControls() @@ -418,7 +445,7 @@ class SceneView(openglGui.glGuiPanel): 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 @@ -456,6 +483,9 @@ class SceneView(openglGui.glGuiPanel): return self._focusObj.setPosition(numpy.array([0.0, 0.0])) self._scene.pushFree() + 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 @@ -472,7 +502,7 @@ class SceneView(openglGui.glGuiPanel): def sceneUpdated(self): self._sceneUpdateTimer.Start(500, True) self._slicer.abortSlicer() - self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32)) + self._scene.updateSizeOffsets() self.QueueRefresh() def _onRunSlicer(self, e): @@ -499,11 +529,16 @@ class SceneView(openglGui.glGuiPanel): self._gcodeVBOs = [] if ready: 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())) + text = '%s' % (self._slicer.getPrintTime()) + for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))): + amount = self._slicer.getFilamentAmount(e) + if amount is None: + continue + text += '\n%s' % (amount) + cost = self._slicer.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: @@ -515,7 +550,7 @@ class SceneView(openglGui.glGuiPanel): self._gcode.load(self._gcodeFilename) def _gcodeLoadCallback(self, progress): - if self._gcode is None: + if not self or self._gcode is None: return True if len(self._gcode.layerList) % 15 == 0: time.sleep(0.1) @@ -529,7 +564,12 @@ class SceneView(openglGui.glGuiPanel): 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: @@ -564,7 +604,7 @@ class SceneView(openglGui.glGuiPanel): 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: @@ -583,7 +623,6 @@ class SceneView(openglGui.glGuiPanel): 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')) if self._selectedObj is not None: @@ -597,7 +636,7 @@ class SceneView(openglGui.glGuiPanel): 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() @@ -797,12 +836,16 @@ class SceneView(openglGui.glGuiPanel): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) def OnPaint(self,e): + connectionEntry = self._printerConnectionManager.getAvailableConnection() if machineCom.machineIsConnected(): self.printButton._imageID = 6 self.printButton._tooltip = _("Print") - elif len(removableStorage.getPossibleSDcardDrives()) > 0: + elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0): self.printButton._imageID = 2 self.printButton._tooltip = _("Toolpath to SD") + elif connectionEntry is not None: + self.printButton._imageID = connectionEntry.icon + self.printButton._tooltip = _("Print with %s") % (connectionEntry.name) else: self.printButton._imageID = 3 self.printButton._tooltip = _("Save toolpath") @@ -896,7 +939,7 @@ void main(void) 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 @@ -1116,19 +1159,31 @@ void main(void) glPopMatrix() else: #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) + 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() + 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._headAreaHull[::-1]: + glVertex3f(p[0], p[1], 0) + glEnd() + glDepthMask(True) glDisable(GL_CULL_FACE) glPopMatrix() @@ -1265,6 +1320,7 @@ void main(void) glVertex3f(-size[0] / 2, -size[1] / 2+10, 0) glEnd() + #Cornerpoints for big blue square 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]] @@ -1278,6 +1334,7 @@ void main(void) glEnableClientState(GL_VERTEX_ARRAY) glVertexPointer(3, GL_FLOAT, 3*4, vList) + glDepthMask(False) glColor4ub(5, 171, 231, 64) glDrawArrays(GL_QUADS, 0, 4) glColor4ub(5, 171, 231, 96) @@ -1286,6 +1343,7 @@ void main(void) glDrawArrays(GL_QUADS, 12, 8) glDisableClientState(GL_VERTEX_ARRAY) + #Draw checkerboard sx = self._machineSize[0] sy = self._machineSize[1] for x in xrange(-int(sx/20)-1, int(sx / 20) + 1): @@ -1298,17 +1356,68 @@ void main(void) y1 = max(min(y1, sy/2), -sy/2) x2 = max(min(x2, sx/2), -sx/2) y2 = max(min(y2, sy/2), -sy/2) + #Black or "white" checker if (x & 1) == (y & 1): glColor4ub(5, 171, 231, 127) 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) + glVertex3f(x1, y1, 0) + glVertex3f(x2, y1, 0) + glVertex3f(x2, y2, 0) + glVertex3f(x1, y2, 0) glEnd() + if machine == 'ultimaker2': + + glColor4ub(127, 127, 127, 200) + #if UM2, draw bat-area zone for head. THe head can't stop there, because its bat-area. + #UpperRight + clipWidth = 25 + clipHeight = 10 + posX = sx / 2 - clipWidth + posY = sy / 2 - clipHeight + glBegin(GL_QUADS) + glVertex3f(posX, posY, 0) + glVertex3f(posX+clipWidth, posY, 0) + glVertex3f(posX+clipWidth, posY+clipHeight, 0) + glVertex3f(posX, posY+clipHeight, 0) + glEnd() + #UpperLeft + clipWidth = 25 + clipHeight = 10 + posX = -sx / 2 + posY = sy / 2 - clipHeight + glBegin(GL_QUADS) + glVertex3f(posX, posY, 0) + glVertex3f(posX+clipWidth, posY, 0) + glVertex3f(posX+clipWidth, posY+clipHeight, 0) + glVertex3f(posX, posY+clipHeight, 0) + glEnd() + #LowerRight + clipWidth = 25 + clipHeight = 10 + posX = sx / 2 - clipWidth + posY = -sy / 2 + glBegin(GL_QUADS) + glVertex3f(posX, posY, 0) + glVertex3f(posX+clipWidth, posY, 0) + glVertex3f(posX+clipWidth, posY+clipHeight, 0) + glVertex3f(posX, posY+clipHeight, 0) + glEnd() + #LowerLeft + clipWidth = 25 + clipHeight = 10 + posX = -sx / 2 + posY = -sy / 2 + glBegin(GL_QUADS) + glVertex3f(posX, posY, 0) + glVertex3f(posX+clipWidth, posY, 0) + glVertex3f(posX+clipWidth, posY+clipHeight, 0) + glVertex3f(posX, posY+clipHeight, 0) + glEnd() + + glDepthMask(True) glDisable(GL_BLEND) glDisable(GL_CULL_FACE)