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',
'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',
'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',
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:
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):
"Initialize."
self.name = name
self.value = value
- repository.preferences.append(self)
+ if repository != None:
+ repository.preferences.append(self)
return self
class LabelSeparator:
from __future__ import absolute_import
import __init__
+import skeinpypy
+
import wx, os
from newui import preview3d
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)
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()
#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
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
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
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
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
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
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