From: daid Date: Tue, 28 Feb 2012 16:39:46 +0000 (+0100) Subject: Updated the GCode preview, now uses thick lines for extrusion. Allows you to spot... X-Git-Tag: RC1~139 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=5481b6e636c6a24908ac09ee9aec4eb8f7ce21e8;p=cura.git Updated the GCode preview, now uses thick lines for extrusion. Allows you to spot slicing errors better. This update also adds a layer selection to the GCode preview. --- diff --git a/SkeinPyPy_NewUI/newui/configBase.py b/SkeinPyPy_NewUI/newui/configBase.py index 730cb733..09280fee 100644 --- a/SkeinPyPy_NewUI/newui/configBase.py +++ b/SkeinPyPy_NewUI/newui/configBase.py @@ -123,6 +123,7 @@ class SettingRow(): sizer.SetRows(x+1) def OnSettingTextChange(self, e): + settings.putSetting(self.configName, self.GetValue()) result = validators.SUCCESS msgs = [] for validator in self.validators: @@ -140,7 +141,6 @@ class SettingRow(): else: self.ctrl.SetBackgroundColour(wx.NullColour) self.ctrl.Refresh() - settings.putSetting(self.configName, self.GetValue()) self.validationMsg = '\n'.join(msgs) self.panel.main.UpdatePopup(self) diff --git a/SkeinPyPy_NewUI/newui/gcodeInterpreter.py b/SkeinPyPy_NewUI/newui/gcodeInterpreter.py index c446cd15..1bc88166 100644 --- a/SkeinPyPy_NewUI/newui/gcodeInterpreter.py +++ b/SkeinPyPy_NewUI/newui/gcodeInterpreter.py @@ -12,13 +12,18 @@ class gcode(): posOffset = Vector3() currentE = 0 pathList = [] - currentPath = {'type': 'move', 'list': [pos.copy()]} scale = 1.0 posAbs = True + feedRate = 3600 pathType = 'CUSTOM'; + layerNr = 0; #Note layer 0 will be the start code. + startCodeDone = False + currentPath = {'type': 'move', 'pathType': pathType, 'list': [pos.copy()], 'layerNr': layerNr} for line in f: if line.startswith(';TYPE:'): pathType = line[6:].strip() + if pathType != "CUSTOM": + startCodeDone = True G = self.getCodeInt(line, 'G') if G is not None: if G == 0 or G == 1: #Move @@ -26,6 +31,7 @@ class gcode(): y = self.getCodeFloat(line, 'Y') z = self.getCodeFloat(line, 'Z') e = self.getCodeFloat(line, 'E') + f = self.getCodeFloat(line, 'F') if x is not None: if posAbs: pos.x = x * scale @@ -37,10 +43,15 @@ class gcode(): else: pos.y += y * scale if z is not None: + oldZ = pos.z if posAbs: pos.z = z * scale else: pos.z += z * scale + if oldZ != pos.z and startCodeDone: + layerNr += 1 + if f is not None: + feedRate = f newPoint = pos.copy() moveType = 'move' if e is not None: @@ -49,9 +60,9 @@ class gcode(): if e < currentE: moveType = 'retract' currentE = e - if currentPath['type'] != moveType: + if currentPath['type'] != moveType or currentPath['pathType'] != pathType: pathList.append(currentPath) - currentPath = {'type': moveType, 'pathType': pathType, 'list': [currentPath['list'][-1]]} + currentPath = {'type': moveType, 'pathType': pathType, 'list': [currentPath['list'][-1]], 'layerNr': layerNr} currentPath['list'].append(newPoint) elif G == 20: #Units are inches scale = 25.4 @@ -112,6 +123,7 @@ class gcode(): pass else: print "Unknown M code:" + str(M) + self.layerCount = layerNr self.pathList = pathList def getCodeInt(self, str, id): diff --git a/SkeinPyPy_NewUI/newui/mainWindow.py b/SkeinPyPy_NewUI/newui/mainWindow.py index a33ee02b..912ee6e6 100644 --- a/SkeinPyPy_NewUI/newui/mainWindow.py +++ b/SkeinPyPy_NewUI/newui/mainWindow.py @@ -60,6 +60,7 @@ class mainWindow(configBase.configWindowBase): c = configBase.SettingRow(left, "Wall thickness (mm)", 'wall_thickness', '0.8', 'Thickness of the walls.\nThis is used in combination with the nozzle size to define the number\nof perimeter lines and the thickness of those perimeter lines.') validators.validFloat(c, 0.0) validators.wallThicknessValidator(c) + configBase.settingNotify(c, self.preview3d.updateWallLineWidth) configBase.TitleRow(left, "Fill") c = configBase.SettingRow(left, "Bottom/Top thickness (mm)", 'solid_layer_thickness', '0.6', 'This controls the thickness of the bottom and top layers, the amount of solid layers put down is calculated by the layer thickness and this value.\nHaving this value a multiply of the layer thickness makes sense. And keep it near your wall thickness to make an evenly strong part.') @@ -109,6 +110,8 @@ class mainWindow(configBase.configWindowBase): configBase.TitleRow(left, "Machine nozzle") c = configBase.SettingRow(left, "Nozzle size (mm)", 'nozzle_size', '0.4', 'The nozzle size is very important, this is used to calculate the line width of the infill, and used to calculate the amount of outside wall lines and thickness for the wall thickness you entered in the print settings.') validators.validFloat(c, 0.1, 1.0) + configBase.settingNotify(c, self.preview3d.updateWallLineWidth) + configBase.settingNotify(c, self.preview3d.updateInfillLineWidth) configBase.TitleRow(left, "Retraction") c = configBase.SettingRow(left, "Minimal travel (mm)", 'retraction_min_travel', '5.0', 'Minimal amount of travel needed for a retraction to happen at all. To make sure you do not get a lot of retractions in a small area') diff --git a/SkeinPyPy_NewUI/newui/preview3d.py b/SkeinPyPy_NewUI/newui/preview3d.py index cc10bba2..52c592d9 100644 --- a/SkeinPyPy_NewUI/newui/preview3d.py +++ b/SkeinPyPy_NewUI/newui/preview3d.py @@ -16,6 +16,7 @@ except: from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret from fabmetheus_utilities.vector3 import Vector3 +from fabmetheus_utilities import settings from newui import gcodeInterpreter class previewPanel(wx.Panel): @@ -28,16 +29,13 @@ class previewPanel(wx.Panel): self.glCanvas = PreviewGLCanvas(self) self.init = 0 self.triangleMesh = None - self.pathList = None + self.gcode = None self.machineSize = Vector3(210, 210, 200) self.machineCenter = Vector3(0, 0, 0) tb = wx.ToolBar( self, -1 ) self.ToolBar = tb tb.SetToolBitmapSize( ( 21, 21 ) ) - transparentButton = wx.Button(tb, -1, "T", size=(21,21)) - tb.AddControl(transparentButton) - self.Bind(wx.EVT_BUTTON, self.OnConfigClick, transparentButton) button = wx.Button(tb, -1, "3D", size=(21*2,21)) tb.AddControl(button) @@ -46,9 +44,15 @@ class previewPanel(wx.Panel): button = wx.Button(tb, -1, "Top", size=(21*2,21)) tb.AddControl(button) self.Bind(wx.EVT_BUTTON, self.OnTopClick, button) + + self.transparentButton = wx.Button(tb, -1, "T", size=(21,21)) + tb.AddControl(self.transparentButton) + self.Bind(wx.EVT_BUTTON, self.OnConfigClick, self.transparentButton) self.layerSpin = wx.SpinCtrl(tb, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS) tb.AddControl(self.layerSpin) + self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin) + self.transparentButton.Show(False) self.layerSpin.Show(False) tb.Realize() @@ -67,11 +71,15 @@ class previewPanel(wx.Panel): def OnTopClick(self, e): self.glCanvas.view3D = False - self.glCanvas.zoom = 150 + self.glCanvas.zoom = 100 self.glCanvas.offsetX = 0 self.glCanvas.offsetY = 0 self.glCanvas.Refresh() + def OnLayerNrChange(self, e): + self.modelDirty = True + self.glCanvas.Refresh() + def updateCenterX(self, x): self.machineCenter.x = x self.moveModel() @@ -82,6 +90,12 @@ class previewPanel(wx.Panel): self.moveModel() self.glCanvas.Refresh() + def updateWallLineWidth(self, setting): + self.glCanvas.lineWidth = settings.calculateEdgeWidth(setting) + + def updateInfillLineWidth(self, setting): + self.glCanvas.infillLineWidth = settings.getSetting('nozzle_size') + def loadModelFile(self, filename): self.modelFilename = filename #Do the STL file loading in a background thread so we don't block the UI. @@ -97,18 +111,26 @@ class previewPanel(wx.Panel): def DoModelLoad(self): self.modelDirty = False self.triangleMesh = fabmetheus_interpret.getCarving(self.modelFilename) - self.pathList = None + self.gcode = None self.moveModel() + wx.CallAfter(self.updateToolbar) wx.CallAfter(self.glCanvas.Refresh) def DoGCodeLoad(self): gcode = gcodeInterpreter.gcode(self.gcodeFilename) self.modelDirty = False - self.pathList = gcode.pathList + self.gcode = gcode self.triangleMesh = None self.modelDirty = True + wx.CallAfter(self.updateToolbar) wx.CallAfter(self.glCanvas.Refresh) + def updateToolbar(self): + self.transparentButton.Show(self.triangleMesh != None) + self.layerSpin.Show(self.gcode != None) + if self.gcode != None: + self.layerSpin.SetRange(1, self.gcode.layerCount) + def OnConfigClick(self, e): self.glCanvas.renderTransparent = not self.glCanvas.renderTransparent self.glCanvas.Refresh() @@ -142,6 +164,8 @@ class PreviewGLCanvas(GLCanvas): self.zoom = 150 self.offsetX = 0 self.offsetY = 0 + self.lineWidth = 0.4 + self.fillLineWidth = 0.4 self.view3D = True self.renderTransparent = False self.modelDisplayList = None @@ -233,28 +257,66 @@ class PreviewGLCanvas(GLCanvas): glVertex3f(0, machineSize.y, machineSize.z) glEnd() - if self.parent.pathList != None: + 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) - for path in self.parent.pathList: + for path in self.parent.gcode.pathList: + c = 1.0 + if path['layerNr'] != self.parent.layerSpin.GetValue(): + if path['layerNr'] < self.parent.layerSpin.GetValue(): + c = 0.5 - (self.parent.layerSpin.GetValue() - path['layerNr']) * 0.1 + if c < -0.5: + continue + if c < 0.1: + c = 0.1 + else: + break if path['type'] == 'move': - glColor3f(0,0,1) + glColor3f(0,0,c) if path['type'] == 'extrude': if path['pathType'] == 'FILL': - glColor3f(0.5,0.5,0) + glColor3f(c/2,c/2,0) elif path['pathType'] == 'WALL-INNER': - glColor3f(0,1,0) + glColor3f(0,c,0) else: - glColor3f(1,0,0) + glColor3f(c,0,0) if path['type'] == 'retract': - glColor3f(0,1,1) - glBegin(GL_LINE_STRIP) - for v in path['list']: - glVertex3f(v.x, v.y, v.z) - glEnd() + glColor3f(0,c,c) + if path['type'] == 'extrude': + if path['pathType'] == 'FILL': + lineWidth = self.fillLineWidth / 2 + else: + lineWidth = self.lineWidth / 2 + for i in xrange(0, len(path['list'])-1): + v0 = path['list'][i] + v1 = path['list'][i+1] + normal = (v0 - v1).cross(Vector3(0,0,1)) + normal.normalize() + v2 = v0 + normal * lineWidth + v3 = v1 + normal * lineWidth + v0 = v0 - normal * lineWidth + 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) + 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) + glEnd() + else: + glBegin(GL_LINE_STRIP) + for v in path['list']: + glVertex3f(v.x, v.y, v.z) + glEnd() glEndList() glCallList(self.modelDisplayList) diff --git a/SkeinPyPy_NewUI/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py b/SkeinPyPy_NewUI/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py index 465d259c..a09e0a01 100644 --- a/SkeinPyPy_NewUI/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py +++ b/SkeinPyPy_NewUI/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py @@ -125,3 +125,4 @@ class GcodeSmallSkein: self.output.write(';TYPE:FILL\n'); elif line.startswith('('): self.output.write(';TYPE:CUSTOM\n'); +