chiark / gitweb /
Updated the GCode preview, now uses thick lines for extrusion. Allows you to spot...
authordaid <daid303@gmail.com>
Tue, 28 Feb 2012 16:39:46 +0000 (17:39 +0100)
committerdaid <daid303@gmail.com>
Tue, 28 Feb 2012 16:39:46 +0000 (17:39 +0100)
This update also adds a layer selection to the GCode preview.

SkeinPyPy_NewUI/newui/configBase.py
SkeinPyPy_NewUI/newui/gcodeInterpreter.py
SkeinPyPy_NewUI/newui/mainWindow.py
SkeinPyPy_NewUI/newui/preview3d.py
SkeinPyPy_NewUI/skeinforge_application/skeinforge_plugins/craft_plugins/export_plugins/static_plugins/gcode_small.py

index 730cb7333099baa4b05fddeb04e4ea9e80128cc5..09280feebbddc72bcaacfc1588a84f2a53cd0804 100644 (file)
@@ -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)
index c446cd15cb36cec3206a0fd895f38c9b8f35d991..1bc88166f4cecefcaac8c698764f2bc442a61219 100644 (file)
@@ -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):
index a33ee02bc0634bf8907b9ab6e428184c5a8d587c..912ee6e6efa0d0303c2e94ffcc55120735b7610b 100644 (file)
@@ -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')
index cc10bba2e6eb08403deabd166be48b3f45df6917..52c592d9f19685ddbfd005538e6c0ec6a01077ee 100644 (file)
@@ -16,6 +16,7 @@ except:
 \r
 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret\r
 from fabmetheus_utilities.vector3 import Vector3\r
+from fabmetheus_utilities import settings\r
 from newui import gcodeInterpreter\r
 \r
 class previewPanel(wx.Panel):\r
@@ -28,16 +29,13 @@ class previewPanel(wx.Panel):
                self.glCanvas = PreviewGLCanvas(self)\r
                self.init = 0\r
                self.triangleMesh = None\r
-               self.pathList = None\r
+               self.gcode = None\r
                self.machineSize = Vector3(210, 210, 200)\r
                self.machineCenter = Vector3(0, 0, 0)\r
                \r
                tb = wx.ToolBar( self, -1 )\r
                self.ToolBar = tb\r
                tb.SetToolBitmapSize( ( 21, 21 ) )\r
-               transparentButton = wx.Button(tb, -1, "T", size=(21,21))\r
-               tb.AddControl(transparentButton)\r
-               self.Bind(wx.EVT_BUTTON, self.OnConfigClick, transparentButton)\r
 \r
                button = wx.Button(tb, -1, "3D", size=(21*2,21))\r
                tb.AddControl(button)\r
@@ -46,9 +44,15 @@ class previewPanel(wx.Panel):
                button = wx.Button(tb, -1, "Top", size=(21*2,21))\r
                tb.AddControl(button)\r
                self.Bind(wx.EVT_BUTTON, self.OnTopClick, button)\r
+\r
+               self.transparentButton = wx.Button(tb, -1, "T", size=(21,21))\r
+               tb.AddControl(self.transparentButton)\r
+               self.Bind(wx.EVT_BUTTON, self.OnConfigClick, self.transparentButton)\r
                \r
                self.layerSpin = wx.SpinCtrl(tb, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)\r
                tb.AddControl(self.layerSpin)\r
+               self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin)\r
+               self.transparentButton.Show(False)\r
                self.layerSpin.Show(False)\r
 \r
                tb.Realize()\r
@@ -67,11 +71,15 @@ class previewPanel(wx.Panel):
 \r
        def OnTopClick(self, e):\r
                self.glCanvas.view3D = False\r
-               self.glCanvas.zoom = 150\r
+               self.glCanvas.zoom = 100\r
                self.glCanvas.offsetX = 0\r
                self.glCanvas.offsetY = 0\r
                self.glCanvas.Refresh()\r
 \r
+       def OnLayerNrChange(self, e):\r
+               self.modelDirty = True\r
+               self.glCanvas.Refresh()\r
+\r
        def updateCenterX(self, x):\r
                self.machineCenter.x = x\r
                self.moveModel()\r
@@ -82,6 +90,12 @@ class previewPanel(wx.Panel):
                self.moveModel()\r
                self.glCanvas.Refresh()\r
        \r
+       def updateWallLineWidth(self, setting):\r
+               self.glCanvas.lineWidth = settings.calculateEdgeWidth(setting)\r
+       \r
+       def updateInfillLineWidth(self, setting):\r
+               self.glCanvas.infillLineWidth = settings.getSetting('nozzle_size')\r
+       \r
        def loadModelFile(self, filename):\r
                self.modelFilename = filename\r
                #Do the STL file loading in a background thread so we don't block the UI.\r
@@ -97,18 +111,26 @@ class previewPanel(wx.Panel):
        def DoModelLoad(self):\r
                self.modelDirty = False\r
                self.triangleMesh = fabmetheus_interpret.getCarving(self.modelFilename)\r
-               self.pathList = None\r
+               self.gcode = None\r
                self.moveModel()\r
+               wx.CallAfter(self.updateToolbar)\r
                wx.CallAfter(self.glCanvas.Refresh)\r
        \r
        def DoGCodeLoad(self):\r
                gcode = gcodeInterpreter.gcode(self.gcodeFilename)\r
                self.modelDirty = False\r
-               self.pathList = gcode.pathList\r
+               self.gcode = gcode\r
                self.triangleMesh = None\r
                self.modelDirty = True\r
+               wx.CallAfter(self.updateToolbar)\r
                wx.CallAfter(self.glCanvas.Refresh)\r
        \r
+       def updateToolbar(self):\r
+               self.transparentButton.Show(self.triangleMesh != None)\r
+               self.layerSpin.Show(self.gcode != None)\r
+               if self.gcode != None:\r
+                       self.layerSpin.SetRange(1, self.gcode.layerCount)\r
+       \r
        def OnConfigClick(self, e):\r
                self.glCanvas.renderTransparent = not self.glCanvas.renderTransparent\r
                self.glCanvas.Refresh()\r
@@ -142,6 +164,8 @@ class PreviewGLCanvas(GLCanvas):
                self.zoom = 150\r
                self.offsetX = 0\r
                self.offsetY = 0\r
+               self.lineWidth = 0.4\r
+               self.fillLineWidth = 0.4\r
                self.view3D = True\r
                self.renderTransparent = False\r
                self.modelDisplayList = None\r
@@ -233,28 +257,66 @@ class PreviewGLCanvas(GLCanvas):
                glVertex3f(0, machineSize.y, machineSize.z)\r
                glEnd()\r
 \r
-               if self.parent.pathList != None:\r
+               if self.parent.gcode != None:\r
                        if self.modelDisplayList == None:\r
                                self.modelDisplayList = glGenLists(1);\r
                        if self.parent.modelDirty:\r
                                self.parent.modelDirty = False\r
                                glNewList(self.modelDisplayList, GL_COMPILE)\r
-                               for path in self.parent.pathList:\r
+                               for path in self.parent.gcode.pathList:\r
+                                       c = 1.0\r
+                                       if path['layerNr'] != self.parent.layerSpin.GetValue():\r
+                                               if path['layerNr'] < self.parent.layerSpin.GetValue():\r
+                                                       c = 0.5 - (self.parent.layerSpin.GetValue() - path['layerNr']) * 0.1\r
+                                                       if c < -0.5:\r
+                                                               continue\r
+                                                       if c < 0.1:\r
+                                                               c = 0.1\r
+                                               else:\r
+                                                       break\r
                                        if path['type'] == 'move':\r
-                                               glColor3f(0,0,1)\r
+                                               glColor3f(0,0,c)\r
                                        if path['type'] == 'extrude':\r
                                                if path['pathType'] == 'FILL':\r
-                                                       glColor3f(0.5,0.5,0)\r
+                                                       glColor3f(c/2,c/2,0)\r
                                                elif path['pathType'] == 'WALL-INNER':\r
-                                                       glColor3f(0,1,0)\r
+                                                       glColor3f(0,c,0)\r
                                                else:\r
-                                                       glColor3f(1,0,0)\r
+                                                       glColor3f(c,0,0)\r
                                        if path['type'] == 'retract':\r
-                                               glColor3f(0,1,1)\r
-                                       glBegin(GL_LINE_STRIP)\r
-                                       for v in path['list']:\r
-                                               glVertex3f(v.x, v.y, v.z)\r
-                                       glEnd()\r
+                                               glColor3f(0,c,c)\r
+                                       if path['type'] == 'extrude':\r
+                                               if path['pathType'] == 'FILL':\r
+                                                       lineWidth = self.fillLineWidth / 2\r
+                                               else:\r
+                                                       lineWidth = self.lineWidth / 2\r
+                                               for i in xrange(0, len(path['list'])-1):\r
+                                                       v0 = path['list'][i]\r
+                                                       v1 = path['list'][i+1]\r
+                                                       normal = (v0 - v1).cross(Vector3(0,0,1))\r
+                                                       normal.normalize()\r
+                                                       v2 = v0 + normal * lineWidth\r
+                                                       v3 = v1 + normal * lineWidth\r
+                                                       v0 = v0 - normal * lineWidth\r
+                                                       v1 = v1 - normal * lineWidth\r
+\r
+                                                       glBegin(GL_QUADS)\r
+                                                       glVertex3f(v0.x, v0.y, v0.z - 0.001)\r
+                                                       glVertex3f(v1.x, v1.y, v1.z - 0.001)\r
+                                                       glVertex3f(v3.x, v3.y, v3.z - 0.001)\r
+                                                       glVertex3f(v2.x, v2.y, v2.z - 0.001)\r
+                                                       glEnd()\r
+                                               for v in path['list']:\r
+                                                       glBegin(GL_TRIANGLE_FAN)\r
+                                                       glVertex3f(v.x, v.y, v.z - 0.001)\r
+                                                       for i in xrange(0, 16+1):\r
+                                                               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)\r
+                                                       glEnd()\r
+                                       else:\r
+                                               glBegin(GL_LINE_STRIP)\r
+                                               for v in path['list']:\r
+                                                       glVertex3f(v.x, v.y, v.z)\r
+                                               glEnd()\r
                                glEndList()\r
                        glCallList(self.modelDisplayList)\r
                \r
index 465d259c8824e64533b103079045edcbec1669e2..a09e0a01ecfbbe2c16fe7e80d5a5f5779d3a038f 100644 (file)
@@ -125,3 +125,4 @@ class GcodeSmallSkein:
                        self.output.write(';TYPE:FILL\n');
                elif line.startswith('(<alteration>'):
                        self.output.write(';TYPE:CUSTOM\n');
+