diff --git a/SkeinPyPy/newui/configWizard.py b/SkeinPyPy/newui/configWizard.py index 2e5ecf1..1b6f2f6 100644 --- a/SkeinPyPy/newui/configWizard.py +++ b/SkeinPyPy/newui/configWizard.py @@ -188,9 +188,19 @@ class UltimakerCheckupPage(InfoPage): self.comm.close() return + if self.DoCommCommandWithTimeout("M104 S0") == False: + wx.CallAfter(self.AddProgressText, "Failed to set temperature") + self.comm.close() + return + wx.MessageBox('Please move the printer head to the center of the machine\nalso move the platform so it is not at the highest or lowest position,\nand make sure the machine is powered on.', 'Machine check', wx.OK | wx.ICON_INFORMATION) idleTemp = self.readTemp() + if idleTemp > 40: + wx.CallAfter(self.AddProgressText, "Waiting for head to cool down before temperature test...") + while idleTemp > 40: + idleTemp = self.readTemp() + time.sleep(1) wx.CallAfter(self.AddProgressText, "Checking heater and temperature sensor...") wx.CallAfter(self.AddProgressText, "(This takes about 30 seconds)") @@ -267,6 +277,7 @@ class UltimakerCheckupPage(InfoPage): return True if ret == False: return False + time.sleep(1) def DoCommCommandWithTimeout(self, cmd = None, replyStart = 'ok'): if cmd != None: diff --git a/SkeinPyPy/newui/gcodeInterpreter.py b/SkeinPyPy/newui/gcodeInterpreter.py index 750a663..0dfd669 100644 --- a/SkeinPyPy/newui/gcodeInterpreter.py +++ b/SkeinPyPy/newui/gcodeInterpreter.py @@ -2,11 +2,13 @@ import sys import math import threading import re +import os from newui import util3d class gcode(): def __init__(self, filename): + print os.stat(filename).st_size f = open(filename, 'r') pos = util3d.Vector3() posOffset = util3d.Vector3() @@ -21,7 +23,9 @@ class gcode(): pathType = 'CUSTOM'; layerNr = 0; #Note layer 0 will be the start code. startCodeDone = False + self.stepsPerE = 865.888 currentPath = {'type': 'move', 'pathType': pathType, 'list': [pos.copy()], 'layerNr': layerNr} + currentPath['list'][-1].e = totalExtrusion for line in f: if line.startswith(';TYPE:'): pathType = line[6:].strip() @@ -79,6 +83,7 @@ class gcode(): pathList.append(currentPath) currentPath = {'type': moveType, 'pathType': pathType, 'list': [currentPath['list'][-1]], 'layerNr': layerNr} currentPath['list'].append(pos.copy()) + currentPath['list'][-1].e = totalExtrusion elif G == 20: #Units are inches scale = 25.4 elif G == 21: #Units are mm @@ -123,6 +128,9 @@ class gcode(): elif M == 84: #Disable step drivers pass elif M == 92: #Set steps per unit + e = self.getCodeFloat(line, 'E') + if e is not None: + self.stepsPerE = e pass elif M == 104: #Set temperature, no wait pass diff --git a/SkeinPyPy/newui/preview3d.py b/SkeinPyPy/newui/preview3d.py index af7d107..7611ab2 100644 --- a/SkeinPyPy/newui/preview3d.py +++ b/SkeinPyPy/newui/preview3d.py @@ -3,6 +3,7 @@ import math import threading import re import time +import os from wx import glcanvas import wx @@ -47,13 +48,11 @@ class previewPanel(wx.Panel): self.toolbar.AddControl(button) self.Bind(wx.EVT_BUTTON, self.OnTopClick, button) - self.transparentButton = wx.Button(self.toolbar, -1, "T", size=(21,21)) - self.toolbar.AddControl(self.transparentButton) - self.Bind(wx.EVT_BUTTON, self.OnTransparentClick, self.transparentButton) - self.XRayButton = wx.Button(self.toolbar, -1, "X-RAY", size=(21*2,21)) - self.toolbar.AddControl(self.XRayButton) - self.Bind(wx.EVT_BUTTON, self.OnXRayClick, self.XRayButton) - + self.viewSelect = wx.ComboBox(self.toolbar, -1, 'Model - Normal', choices=['Model - Normal', 'Model - Transparent', 'Model - X-Ray', 'GCode', 'Mixed'], style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.toolbar.AddControl(self.viewSelect) + self.viewSelect.Bind(wx.EVT_TEXT, self.OnViewChange) + self.glCanvas.viewMode = self.viewSelect.GetValue() + self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS) self.toolbar.AddControl(self.layerSpin) self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin) @@ -80,7 +79,7 @@ class previewPanel(wx.Panel): self.glCanvas.Refresh() def OnLayerNrChange(self, e): - self.modelDirty = True + self.gcodeDirty = True self.glCanvas.Refresh() def updateCenterX(self, x): @@ -103,6 +102,7 @@ class previewPanel(wx.Panel): def loadModelFile(self, filename): self.modelFilename = filename + self.gcodeFilename = filename[: filename.rfind('.')] + "_export.gcode" #Do the STL file loading in a background thread so we don't block the UI. thread = threading.Thread(target=self.DoModelLoad) thread.start() @@ -121,38 +121,29 @@ class previewPanel(wx.Panel): triangleMesh.origonalVertexes[i] = triangleMesh.origonalVertexes[i].copy() triangleMesh.getMinimumZ() self.triangleMesh = triangleMesh - self.gcode = None self.updateModelTransform() wx.CallAfter(self.updateToolbar) wx.CallAfter(self.glCanvas.Refresh) + + if os.path.isfile(self.gcodeFilename): + self.DoGCodeLoad() def DoGCodeLoad(self): gcode = gcodeInterpreter.gcode(self.gcodeFilename) - self.modelDirty = False + self.gcodeDirty = False self.gcode = gcode - self.triangleMesh = None - self.modelDirty = True + self.gcodeDirty = True wx.CallAfter(self.updateToolbar) wx.CallAfter(self.glCanvas.Refresh) def updateToolbar(self): - self.transparentButton.Show(self.triangleMesh != None) - self.XRayButton.Show(self.triangleMesh != None) self.layerSpin.Show(self.gcode != None) if self.gcode != None: self.layerSpin.SetRange(1, self.gcode.layerCount) self.toolbar.Realize() - def OnTransparentClick(self, e): - self.glCanvas.renderTransparent = not self.glCanvas.renderTransparent - if self.glCanvas.renderTransparent: - self.glCanvas.renderXRay = False - self.glCanvas.Refresh() - - def OnXRayClick(self, e): - self.glCanvas.renderXRay = not self.glCanvas.renderXRay - if self.glCanvas.renderXRay: - self.glCanvas.renderTransparent = False + def OnViewChange(self, e): + self.glCanvas.viewMode = self.viewSelect.GetValue() self.glCanvas.Refresh() def updateModelTransform(self, f=0): @@ -228,9 +219,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas): self.lineWidth = 0.4 self.fillLineWidth = 0.4 self.view3D = True - self.renderTransparent = False - self.renderXRay = False self.modelDisplayList = None + self.gcodeDisplayList = None def OnMouseMotion(self,e): if e.Dragging() and e.LeftIsDown(): @@ -260,6 +250,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): self.Refresh() def OnEraseBackground(self,event): + #Workaround for windows background redraw flicker. pass def OnSize(self,event): @@ -319,11 +310,11 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glEnd() if self.parent.gcode != None: - if self.modelDisplayList == None: - self.modelDisplayList = glGenLists(1); - if self.parent.modelDirty: - self.parent.modelDirty = False - glNewList(self.modelDisplayList, GL_COMPILE) + if self.gcodeDisplayList == None: + self.gcodeDisplayList = glGenLists(1); + if self.parent.gcodeDirty: + self.parent.gcodeDirty = False + glNewList(self.gcodeDisplayList, GL_COMPILE) for path in self.parent.gcode.pathList: c = 1.0 if path['layerNr'] != self.parent.layerSpin.GetValue(): @@ -352,6 +343,10 @@ class PreviewGLCanvas(glcanvas.GLCanvas): for i in xrange(0, len(path['list'])-1): v0 = path['list'][i] v1 = path['list'][i+1] + dist = (v0 - v1).vsize() + if dist > 0: + extrusionMMperDist = (v1.e - v0.e) / (v0 - v1).vsize() / self.parent.gcode.stepsPerE + #TODO: Calculate line width from ePerDistance (needs layer thickness, steps_per_E and filament diameter) normal = (v0 - v1).cross(util3d.Vector3(0,0,1)) normal.normalize() v2 = v0 + normal * lineWidth @@ -360,16 +355,25 @@ class PreviewGLCanvas(glcanvas.GLCanvas): v1 = v1 - normal * lineWidth glBegin(GL_QUADS) - glVertex3f(v0.x, v0.y, v0.z - 0.001) - glVertex3f(v1.x, v1.y, v1.z - 0.001) - glVertex3f(v3.x, v3.y, v3.z - 0.001) - glVertex3f(v2.x, v2.y, v2.z - 0.001) + if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap + glVertex3f(v0.x, v0.y, v0.z - 0.02) + glVertex3f(v1.x, v1.y, v1.z - 0.02) + glVertex3f(v3.x, v3.y, v3.z - 0.02) + glVertex3f(v2.x, v2.y, v2.z - 0.02) + else: + glVertex3f(v0.x, v0.y, v0.z - 0.01) + glVertex3f(v1.x, v1.y, v1.z - 0.01) + glVertex3f(v3.x, v3.y, v3.z - 0.01) + glVertex3f(v2.x, v2.y, v2.z - 0.01) glEnd() for v in path['list']: glBegin(GL_TRIANGLE_FAN) glVertex3f(v.x, v.y, v.z - 0.001) for i in xrange(0, 16+1): - glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.001) + if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap + glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.02) + else: + glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.01) glEnd() else: glBegin(GL_LINE_STRIP) @@ -377,7 +381,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glVertex3f(v.x, v.y, v.z) glEnd() glEndList() - glCallList(self.modelDisplayList) + if self.viewMode == "GCode" or self.viewMode == "Mixed": + glCallList(self.gcodeDisplayList) if self.parent.triangleMesh != None: if self.modelDisplayList == None: @@ -411,13 +416,14 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glPopMatrix() glPopMatrix() glEndList() - if self.renderTransparent: + if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed": #If we want transparent, then first render a solid black model to remove the printer size lines. - glDisable(GL_BLEND) - glDisable(GL_LIGHTING) - glColor3f(0,0,0) - glCallList(self.modelDisplayList) - glColor3f(1,1,1) + if self.viewMode != "Mixed": + glDisable(GL_BLEND) + glDisable(GL_LIGHTING) + glColor3f(0,0,0) + glCallList(self.modelDisplayList) + glColor3f(1,1,1) #After the black model is rendered, render the model again but now with lighting and no depth testing. glDisable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) @@ -425,7 +431,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glBlendFunc(GL_ONE, GL_ONE) glEnable(GL_LIGHTING) glCallList(self.modelDisplayList) - elif self.renderXRay: + elif self.viewMode == "Model - X-Ray": glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) glDisable(GL_DEPTH_TEST) glEnable(GL_STENCIL_TEST); @@ -436,7 +442,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) glStencilFunc(GL_EQUAL, 0, 1); - glColor(0, 1, 0) + glColor(1, 1, 1) glCallList(self.modelDisplayList) glStencilFunc(GL_EQUAL, 1, 1); glColor(1, 0, 0) @@ -444,16 +450,16 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glPushMatrix() glLoadIdentity() - for i in xrange(2, 20, 2): + for i in xrange(2, 15, 2): glStencilFunc(GL_EQUAL, i, 0xFF); - glColor(0, float(i)/10, 0) + glColor(float(i)/10, float(i)/10, float(i)/5) glBegin(GL_QUADS) glVertex3f(-1000,-1000,-1) glVertex3f( 1000,-1000,-1) glVertex3f( 1000, 1000,-1) glVertex3f(-1000, 1000,-1) glEnd() - for i in xrange(1, 20, 2): + for i in xrange(1, 15, 2): glStencilFunc(GL_EQUAL, i, 0xFF); glColor(float(i)/10, 0, 0) glBegin(GL_QUADS) @@ -466,7 +472,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glDisable(GL_STENCIL_TEST); glEnable(GL_DEPTH_TEST) - else: + elif self.viewMode == "Model - Normal": glEnable(GL_LIGHTING) glCallList(self.modelDisplayList) glFlush() @@ -478,7 +484,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): size = self.GetSize() glViewport(0,0, size.GetWidth(), size.GetHeight()) - if self.renderTransparent: + if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed": glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0]) glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0]) else: diff --git a/SkeinPyPy/newui/sliceProgessPanel.py b/SkeinPyPy/newui/sliceProgessPanel.py index d880bf9..59b095a 100644 --- a/SkeinPyPy/newui/sliceProgessPanel.py +++ b/SkeinPyPy/newui/sliceProgessPanel.py @@ -66,7 +66,9 @@ class sliceProgessPanel(wx.Panel): self.abort = True def OnShowGCode(self, e): - self.mainWindow.preview3d.loadGCodeFile(self.filename[: self.filename.rfind('.')] + "_export.gcode") + self.mainWindow.preview3d.loadModelFile(self.filename) + self.mainWindow.preview3d.viewSelect.SetValue("GCode") + self.mainWindow.preview3d.OnViewChange(None) def OnShowLog(self, e): LogWindow('\n'.join(self.progressLog))