chiark / gitweb /
Large configuration update, the new UI now starts to work a bit.
authorDaid <daid303@gmail.com>
Mon, 20 Feb 2012 22:27:34 +0000 (23:27 +0100)
committerDaid <daid303@gmail.com>
Mon, 20 Feb 2012 22:27:34 +0000 (23:27 +0100)
Still missing a bunch of configuration settings. And the start/end code is
not editable yet, and never included.

SkeinPyPy_NewUI/fabmetheus_utilities/settings.py
SkeinPyPy_NewUI/newui/mainWindow.py
SkeinPyPy_NewUI/newui/preview3d.py
SkeinPyPy_NewUI/skeinpypy.py

index 0f24b3e971e62e5090b159210c2f885fd03cc33c..43c1cf7e16a4e28e725bc1bda0f94ae94ae35983 100644 (file)
@@ -14,7 +14,7 @@ def getSkeinPyPyConfigInformation():
        return {
                'carve': {
                        'Add_Layer_Template_to_SVG': 'ignore',
-                       'Edge_Width_mm': 'ignore',
+                       'Edge_Width_mm': 'save',
                        'Extra_Decimal_Places_float': 'ignore',
                        'Import_Coarseness_ratio': 'ignore',
                        'Layer_Height_mm': 'save',
@@ -71,7 +71,7 @@ def getSkeinPyPyConfigInformation():
                        'Line': 'ignore',
                        'Infill_Perimeter_Overlap_ratio': 'save',
                        'Infill_Solidity_ratio': 'save',
-                       'Infill_Width': 'save',
+                       'Infill_Width': 'use:carve:Edge_Width_mm',
                        'Solid_Surface_Thickness_layers': 'save',
                        'Start_From_Choice': 'ignore',
                        'Surrounding_Angle_degrees': 'ignore',
@@ -92,12 +92,12 @@ def getSkeinPyPyConfigInformation():
                        'Duty_Cyle_at_Beginning_portion': 'ignore',
                        'Duty_Cyle_at_Ending_portion': 'ignore',
                        'Feed_Rate_mm/s': 'save',
-                       'Flow_Rate_Setting_float': 'use:Feed_Rate_mm/s',
+                       'Flow_Rate_Setting_float': 'use:speed:Feed_Rate_mm/s',
                        'Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio': 'save',
-                       'Object_First_Layer_Feed_Rate_Perimeter_Multiplier_ratio': 'use:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
-                       'Object_First_Layer_Feed_Rate_Travel_Multiplier_ratio': 'use:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
-                       'Object_First_Layer_Flow_Rate_Infill_Multiplier_ratio': 'use:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
-                       'Object_First_Layer_Flow_Rate_Perimeter_Multiplier_ratio': 'use:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
+                       'Object_First_Layer_Feed_Rate_Perimeter_Multiplier_ratio': 'use:speed:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
+                       'Object_First_Layer_Feed_Rate_Travel_Multiplier_ratio': 'use:speed:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
+                       'Object_First_Layer_Flow_Rate_Infill_Multiplier_ratio': 'use:speed:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
+                       'Object_First_Layer_Flow_Rate_Perimeter_Multiplier_ratio': 'use:speed:Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio',
                        'Object_First_Layers_Amount_Of_Layers_For_Speed_Change': 'save',
                        'Orbital_Feed_Rate_over_Operating_Feed_Rate_ratio': 'ignore',
                        'Maximum_Z_Feed_Rate_mm/s': 'save',
@@ -345,7 +345,8 @@ def getReadRepository(repository):
                        continue
                #Load this setting from another value.
                if info[name][0:4] == "use:":
-                       p.setValueToString(globalConfigParser.get(repository.name, info[name][4:]))
+                       i = info[name][4:].split(':')
+                       p.setValueToString(globalConfigParser.get(i[0], i[1]))
                        continue
                
                try:
@@ -357,10 +358,35 @@ def getReadRepository(repository):
                        except:
                                pass
                        globalConfigParser.set(repository.name, name, str(p.value))
-                       saveGlobalConfig(getDefaultConfigPath())
+                       #saveGlobalConfig(getDefaultConfigPath())
                #print "============" + str(p) + "|" + p.name + "|" + str(p.value) + "|" + str(type(p.value))
        return repository
 
+def storeRepository(repository):
+       "Store the configuration for this 'repository'"
+       #Check if we have a configuration file loaded, else load the default.
+       if not globals().has_key('globalConfigParser'):
+               loadGlobalConfig(getDefaultConfigPath())
+       
+       info = getSkeinPyPyConfigInformation()
+       if not info.has_key(repository.name):
+               print "Warning: Plugin: " + repository.name + " missing from SkeinPyPy info"
+               return repository
+       info = info[repository.name]
+       if not type(info) is dict:
+               print "Ignoring plugin configuration: " + repository.name
+               return repository
+       
+       for p in repository.preferences:
+               name = safeConfigName(p.name)
+               if not info.has_key(name):
+                       print "Setting: " + repository.name + ":" + name + " missing from SkeinPyPy info"
+                       continue
+
+               if info[name] == "save":
+                       globalConfigParser.set(repository.name, name, str(p.value))
+       return repository
+
 def printProgress(layerIndex, procedureName):
        print("Progress: ", procedureName, layerIndex)
 def printProgressByNumber(layerIndex, numberOfLayers, procedureName):
@@ -491,7 +517,8 @@ class FloatSpin( FloatSetting ):
                "Initialize."
                self.name = name
                self.value = value
-               repository.preferences.append(self)
+               if repository != None:
+                       repository.preferences.append(self)
                return self
 
 class LabelSeparator:
index fdf9617452612d0d3f4ce824c89eb7e49ab9c84a..3d4c59478078caa3cc6e7893fb505f0d09fe6003 100644 (file)
@@ -1,6 +1,8 @@
 from __future__ import absolute_import
 import __init__
 
+import skeinpypy
+
 import wx, os
 
 from newui import preview3d
@@ -21,62 +23,86 @@ class mainWindow(wx.Frame):
                fileMenu = wx.Menu()
                fitem = fileMenu.Append(-1, 'Open Profile...', 'Open Profile...')
                fitem = fileMenu.Append(-1, 'Save Profile...', 'Save Profile...')
+               self.Bind(wx.EVT_MENU, self.OnSaveProfile, fitem)
                fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')
                self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
                menubar.Append(fileMenu, '&File')
                menubar.Append(wx.Menu(), 'Expert')
                self.SetMenuBar(menubar)
                
-               plugins = {}
+               self.filename = None
+               self.controlList = []
+               self.plugins = {}
                for m in skeinforge_profile.getCraftTypePluginModule().getCraftSequence():
-                       plugins[m] = archive.getModuleWithDirectoryPath(archive.getCraftPluginsDirectoryPath(), m).getNewRepository()
-                       settings.getReadRepository(plugins[m])
+                       self.plugins[m] = archive.getModuleWithDirectoryPath(archive.getCraftPluginsDirectoryPath(), m).getNewRepository()
+                       settings.getReadRepository(self.plugins[m])
                
+               skeinPyPySettingInfo = settings.getSkeinPyPyConfigInformation()
+
+               for pluginName in self.plugins.keys():
+                       self.plugins[pluginName].preferencesDict = {}
+                       for pref in self.plugins[pluginName].preferences:
+                               if skeinPyPySettingInfo[pluginName][settings.safeConfigName(pref.name)] == 'save':
+                                       self.plugins[pluginName].preferencesDict[settings.safeConfigName(pref.name)] = pref
+
                p = wx.Panel(self)
                nb = wx.Notebook(p, size=(500,10))
                
-               printConfig = wx.Panel(nb);
+               configPanel = wx.Panel(nb);
+               nb.AddPage(configPanel, "Print")
+               sizer = wx.GridBagSizer(2, 2)
+               configPanel.SetSizer(sizer)
+               
+               self.AddTitle(configPanel, "Accuracy")
+               self.AddSetting(configPanel, "Layer height (mm)", self.plugins['carve'].preferencesDict['Layer_Height_mm'])
+               self.AddTitle(configPanel, "Skirt")
+               self.AddSetting(configPanel, "Enable skirt", self.plugins['skirt'].preferencesDict['Activate_Skirt'])
+               self.AddSetting(configPanel, "Skirt distance (mm)", self.plugins['skirt'].preferencesDict['Gap_over_Perimeter_Width_ratio'])
+               self.AddTitle(configPanel, "Fill")
+               self.AddSetting(configPanel, "Solid layers", self.plugins['fill'].preferencesDict['Solid_Surface_Thickness_layers'])
+               self.AddSetting(configPanel, "Fill Density", self.plugins['fill'].preferencesDict['Infill_Solidity_ratio'])
+               self.AddTitle(configPanel, "Retraction")
+               self.AddSetting(configPanel, "Speed (mm/s)", self.plugins['dimension'].preferencesDict['Extruder_Retraction_Speed_mm/s'])
+               self.AddSetting(configPanel, "Distance (mm)", self.plugins['dimension'].preferencesDict['Retraction_Distance_millimeters'])
+               self.AddSetting(configPanel, "Extra length on start (mm)", self.plugins['dimension'].preferencesDict['Restart_Extra_Distance_millimeters'])
 
+               configPanel = wx.Panel(nb);
+               nb.AddPage(configPanel, "Machine")
                sizer = wx.GridBagSizer(2, 2)
-               printConfig.SetSizer(sizer)
+               configPanel.SetSizer(sizer)
                
-               skeinPyPySettingInfo = settings.getSkeinPyPyConfigInformation()
+               self.AddTitle(configPanel, "Machine size")
+               self.AddSetting(configPanel, "Width (mm)", settings.IntSpin().getFromValue(10, "machine_width", None, 1000, 205))
+               self.AddSetting(configPanel, "Depth (mm)", settings.IntSpin().getFromValue(10, "machine_depth", None, 1000, 205))
+               self.AddSetting(configPanel, "Height (mm)", settings.IntSpin().getFromValue(10, "machine_height", None, 1000, 200))
 
-               for pluginName in plugins.keys():
-                       box, configPanel = self.CreateGroup(printConfig, pluginName)
-                       
-                       for pref in plugins[pluginName].preferences:
-                               if skeinPyPySettingInfo[pluginName][settings.safeConfigName(pref.name)] == 'save':
-                                       self.AddSetting(configPanel, pref.name, wx.TextCtrl(configPanel, -1, str(pref.value)))
+               self.AddTitle(configPanel, "Machine nozzle")
+               self.AddSetting(configPanel, "Nozzle size (mm)", self.plugins['carve'].preferencesDict['Edge_Width_mm'])
 
-                       if configPanel.GetSizer().GetRows() > 0:
-                               sizer.Add(box, (sizer.GetRows(),0))
-                               sizer.SetRows(sizer.GetRows()+1)
-               
-               #self.AddSetting(generalConfig, "Speed (mm/s)", wx.TextCtrl(generalConfig, -1, "50.0"))
+               self.AddTitle(configPanel, "Speed")
+               self.AddSetting(configPanel, "Print speed (mm/s)", self.plugins['speed'].preferencesDict['Feed_Rate_mm/s'])
+               self.AddSetting(configPanel, "Travel speed (mm/s)", self.plugins['speed'].preferencesDict['Travel_Feed_Rate_mm/s'])
 
-               machineConfig = wx.Panel(nb);
-               sizer = wx.GridBagSizer(2, 2)
-               machineConfig.SetSizer(sizer)
-               box, dimensionsConfig = self.CreateGroup(machineConfig, "Dimensions")
-               self.AddSetting(dimensionsConfig, "Printer size (mm)", wx.TextCtrl(dimensionsConfig, -1, "205,205,200"))
-               sizer.Add(box, (0,0))
+               self.AddTitle(configPanel, "Filament")
+               self.AddSetting(configPanel, "Diameter (mm)", self.plugins['dimension'].preferencesDict['Filament_Diameter_mm'])
+               self.AddSetting(configPanel, "Packing Density", self.plugins['dimension'].preferencesDict['Filament_Packing_Density_ratio'])
                
-               nb.AddPage(printConfig, "Print")
-               nb.AddPage(machineConfig, "Machine")
                nb.AddPage(wx.Panel(nb), "Start/End-GCode")
 
                #Preview window, load and slice buttons.
                self.preview3d = preview3d.myGLCanvas(p)
                
-               loadButton = wx.Button(p, 1, 'Load STL')
+               loadButton = wx.Button(p, -1, 'Load STL')
+               sliceButton = wx.Button(p, -1, 'Slice to GCode')
                self.Bind(wx.EVT_BUTTON, self.OnLoadSTL, loadButton)
+               self.Bind(wx.EVT_BUTTON, self.OnSlice, sliceButton)
                
                sizer = wx.GridBagSizer()
                sizer.Add(nb, (0,0), span=(2,1), flag=wx.EXPAND)
-               sizer.Add(self.preview3d, (0,1), span=(1,1), flag=wx.EXPAND)
+               sizer.Add(self.preview3d, (0,1), span=(1,3), flag=wx.EXPAND)
                sizer.Add(loadButton, (1,1))
-               sizer.AddGrowableCol(1)
+               sizer.Add(sliceButton, (1,2))
+               sizer.AddGrowableCol(2)
                sizer.AddGrowableRow(0)
                p.SetSizer(sizer)
                
@@ -84,32 +110,65 @@ class mainWindow(wx.Frame):
                self.Centre()
                self.Show(True)
        
-       def CreateGroup(self, panel, name):
-               retPanel = wx.Panel(panel)
-               sizer = wx.GridBagSizer(2, 2)
-               retPanel.SetSizer(sizer)
-
-               box = wx.StaticBox(panel, -1, name)
-               sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-               sizer.Add(retPanel)
-               
-               return (sizer, retPanel)
+       def AddTitle(self, panel, name):
+               sizer = panel.GetSizer()
+               title = wx.StaticText(panel, -1, name)
+               title.SetFont(wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD))
+               sizer.Add(title, (sizer.GetRows(),1), (1,2), flag=wx.EXPAND)
+               sizer.Add(wx.StaticLine(panel), (sizer.GetRows()+1,1), (1,2), flag=wx.EXPAND)
+               sizer.SetRows(sizer.GetRows() + 2)
        
-       def AddSetting(self, panel, name, ctrl):
+       def AddSetting(self, panel, name, setting):
                sizer = panel.GetSizer()
-               sizer.Add(wx.StaticText(panel, -1, name), (sizer.GetRows(),0), flag=wx.ALIGN_BOTTOM)
-               sizer.Add(ctrl, (sizer.GetRows(),1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)
+               sizer.Add(wx.StaticText(panel, -1, name), (sizer.GetRows(),1), flag=wx.ALIGN_CENTER_VERTICAL)
+               ctrl = None
+               if setting.__class__ is settings.FloatSpin:
+                       ctrl = wx.TextCtrl(panel, -1, str(setting.value))
+               if setting.__class__ is settings.IntSpin:
+                       ctrl = wx.TextCtrl(panel, -1, str(setting.value))
+               if setting.__class__ is settings.BooleanSetting:
+                       ctrl = wx.CheckBox(panel, -1, '')
+                       ctrl.SetValue(setting.value)
+               if ctrl == None:
+                       print "No WX control for: " + str(setting), str(setting.__class__)
+               else:
+                       ctrl.setting = setting
+                       self.controlList.append(ctrl)
+                       sizer.Add(ctrl, (sizer.GetRows(),2), flag=wx.ALIGN_BOTTOM|wx.EXPAND)
                sizer.SetRows(sizer.GetRows()+1)
        
+       def OnSaveProfile(self, e):
+               dlg=wx.FileDialog(self, "Select profile file to save", style=wx.FD_SAVE)
+               dlg.SetWildcard("ini files (*.ini)|*.ini")
+               if dlg.ShowModal() == wx.ID_OK:
+                       profileFile = dlg.GetPath()
+                       self.updateConfig()
+                       settings.saveGlobalConfig(profileFile)
+       
        def OnLoadSTL(self, e):
                dlg=wx.FileDialog(self, "Open file to print", style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
-               dlg.SetWildcard("OBJ, STL files (;*.stl;*.STL;*.obj;*.OBJ;)")
+               dlg.SetWildcard("OBJ, STL files (*.stl;*.STL;*.obj;*.OBJ;)")
                if dlg.ShowModal() == wx.ID_OK:
                        self.filename=dlg.GetPath()
                        if not(os.path.exists(self.filename)):
                                return
                        self.preview3d.loadFile(self.filename)
        
+       def OnSlice(self, e):
+               if self.filename == None:
+                       return
+               for pluginName in self.plugins.keys():
+                       settings.storeRepository(self.plugins[pluginName])
+               settings.saveGlobalConfig(settings.getDefaultConfigPath())
+               skeinpypy.runSkein([self.filename])
+       
+       def updateConfig(self):
+               for ctrl in self.controlList:
+                       ctrl.setting.setValueToString(ctrl.GetValue())
+               for pluginName in self.plugins.keys():
+                       settings.storeRepository(self.plugins[pluginName])
+               settings.saveGlobalConfig(settings.getDefaultConfigPath())
+       
        def OnQuit(self, e):
                self.Close()
 
index 0b86e113d8ba781c2b2ff0c66ca31a9d9f60e4c6..7a83a47a0640c2fedc96974da1d56365aeacc277 100644 (file)
@@ -1,6 +1,6 @@
 #from wxPython.glcanvas import wxGLCanvas\r
 import wx\r
-import sys,math\r
+import sys,math,threading\r
 \r
 from wx.glcanvas import GLCanvas\r
 try:\r
@@ -24,6 +24,7 @@ class myGLCanvas(GLCanvas):
                wx.EVT_MOTION(self, self.OnMouseMotion)\r
                self.init = 0\r
                self.triangleMesh = None\r
+               self.modelDisplayList = None\r
                self.yaw = 30\r
                self.pitch = 60\r
                self.zoom = 150\r
@@ -31,8 +32,17 @@ class myGLCanvas(GLCanvas):
                self.machineCenter = Vector3(100, 100, 0)\r
        \r
        def loadFile(self, filename):\r
-               self.triangleMesh = fabmetheus_interpret.getCarving(filename)\r
+               self.filename = filename\r
+               #Do the STL file loading in a background thread so we don't block the UI.\r
+               thread = threading.Thread(target=self.DoLoad)\r
+               thread.setDaemon(True)\r
+               thread.start()\r
+       \r
+       def DoLoad(self):\r
+               self.modelDirty = False\r
+               self.triangleMesh = fabmetheus_interpret.getCarving(self.filename)\r
                self.moveModel()\r
+               self.Refresh()\r
                \r
        def moveModel(self):\r
                if self.triangleMesh == None:\r
@@ -46,6 +56,8 @@ class myGLCanvas(GLCanvas):
                        v.y -= min.y + (max.y - min.y) / 2\r
                        v.x += self.machineCenter.x\r
                        v.y += self.machineCenter.y\r
+               self.triangleMesh.getMinimumZ()\r
+               self.modelDirty = True\r
        \r
        def OnMouseMotion(self,e):\r
                if e.Dragging() and e.LeftIsDown():\r
@@ -55,11 +67,12 @@ class myGLCanvas(GLCanvas):
                                self.pitch = 170\r
                        if self.pitch < 10:\r
                                self.pitch = 10\r
+                       self.Refresh()\r
                if e.Dragging() and e.RightIsDown():\r
                        self.zoom += e.GetY() - self.oldY\r
+                       self.Refresh()\r
                self.oldX = e.GetX()\r
                self.oldY = e.GetY()\r
-               self.Refresh()\r
        \r
        def OnEraseBackground(self,event):\r
                pass\r
@@ -85,18 +98,25 @@ class myGLCanvas(GLCanvas):
                glTranslate(-self.machineCenter.x, -self.machineCenter.y, 0)\r
                \r
                if self.triangleMesh != None:\r
-                       glBegin(GL_TRIANGLES)\r
-                       for face in self.triangleMesh.faces:\r
-                               v1 = self.triangleMesh.vertexes[face.vertexIndexes[0]]\r
-                               v2 = self.triangleMesh.vertexes[face.vertexIndexes[1]]\r
-                               v3 = self.triangleMesh.vertexes[face.vertexIndexes[2]]\r
-                               normal = (v2 - v1).cross(v3 - v1)\r
-                               normal.normalize()\r
-                               glNormal3f(normal.x, normal.y, normal.z)\r
-                               glVertex3f(v1.x, v1.y, v1.z)\r
-                               glVertex3f(v2.x, v2.y, v2.z)\r
-                               glVertex3f(v3.x, v3.y, v3.z)\r
-                       glEnd()\r
+                       if self.modelDisplayList == None:\r
+                               self.modelDisplayList = glGenLists(1);\r
+                       if self.modelDirty:\r
+                               self.modelDirty = False\r
+                               glNewList(self.modelDisplayList, GL_COMPILE)\r
+                               glBegin(GL_TRIANGLES)\r
+                               for face in self.triangleMesh.faces:\r
+                                       v1 = self.triangleMesh.vertexes[face.vertexIndexes[0]]\r
+                                       v2 = self.triangleMesh.vertexes[face.vertexIndexes[1]]\r
+                                       v3 = self.triangleMesh.vertexes[face.vertexIndexes[2]]\r
+                                       normal = (v2 - v1).cross(v3 - v1)\r
+                                       normal.normalize()\r
+                                       glNormal3f(normal.x, normal.y, normal.z)\r
+                                       glVertex3f(v1.x, v1.y, v1.z)\r
+                                       glVertex3f(v2.x, v2.y, v2.z)\r
+                                       glVertex3f(v3.x, v3.y, v3.z)\r
+                               glEnd()\r
+                               glEndList()\r
+                       glCallList(self.modelDisplayList)\r
                \r
                glLineWidth(4)\r
                glDisable(GL_LIGHTING)\r
@@ -160,6 +180,6 @@ class myGLCanvas(GLCanvas):
                glTranslate(0,0,-self.zoom)\r
                glRotate(-self.pitch, 1,0,0)\r
                glRotate(self.yaw, 0,0,1)\r
-               #glRotate(90, 1,0,0)\r
-               \r
+               if self.triangleMesh != None:\r
+                       glTranslate(0,0,-self.triangleMesh.getCarveCornerMaximum().z / 2)\r
                return\r
index a4f3afa75d45198e84282522668725383dc6c703..dabf9ca36e3256cacbaa1e76bb109f922adf4b3a 100644 (file)
@@ -13,7 +13,11 @@ from __future__ import absolute_import
 
 from optparse import OptionParser
 from skeinforge_application.skeinforge_utilities import skeinforge_craft
-from newui import mainWindow
+#For some reason the newui import fails when we are importing this from newui.mainWindow (circle references not allowed?) in that case we don't need the UI so skip it.
+try:
+       from newui import mainWindow
+except:
+       pass
 import os
 import sys
 import platform