From cfadc75e9cdb851d15c2cd755fe78a727f25afcb Mon Sep 17 00:00:00 2001 From: daid Date: Mon, 23 Apr 2012 18:02:30 +0200 Subject: [PATCH 1/6] Add alteration files to profile ini. (Note, this broke Slic3r support) --- Cura/alterations/end.gcode | 6 -- Cura/alterations/nextobject.gcode | 9 -- Cura/alterations/start.gcode | 21 ---- Cura/gui/alterationPanel.py | 8 +- Cura/util/profile.py | 156 +++++++++++++++++++++++------- 5 files changed, 123 insertions(+), 77 deletions(-) delete mode 100644 Cura/alterations/end.gcode delete mode 100644 Cura/alterations/nextobject.gcode delete mode 100644 Cura/alterations/start.gcode diff --git a/Cura/alterations/end.gcode b/Cura/alterations/end.gcode deleted file mode 100644 index a84b13158e..0000000000 --- a/Cura/alterations/end.gcode +++ /dev/null @@ -1,6 +0,0 @@ -M104 S0 ;extruder heat off -G91 ;relative positioning -G1 Z+10 E-5 F{max_z_speed} ;move Z up a bit and retract filament by 5mm -G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way -M84 ;steppers off -G90 ;absolute positioning diff --git a/Cura/alterations/nextobject.gcode b/Cura/alterations/nextobject.gcode deleted file mode 100644 index be4ffc1a38..0000000000 --- a/Cura/alterations/nextobject.gcode +++ /dev/null @@ -1,9 +0,0 @@ -;Move to next object on the platform. clear_z is the minimal z height we need to make sure we do not hit any objects. -G92 E0 -G1 Z{clear_z} E-5 F{max_z_speed} -G92 E0 -G1 X{machine_center_x} Y{machine_center_y} F{travel_speed} -G1 F200 E5.5 -G92 E0 -G1 Z0 F{max_z_speed} - diff --git a/Cura/alterations/start.gcode b/Cura/alterations/start.gcode deleted file mode 100644 index 94869d21b2..0000000000 --- a/Cura/alterations/start.gcode +++ /dev/null @@ -1,21 +0,0 @@ -G21 ;metric values -G90 ;absolute positioning - -G28 X0 Y0 ;move X/Y to min endstops -G28 Z0 ;move Z to min endstops - -; if your prints start too high, try changing the Z0.0 below -; to Z1.0 - the number after the Z is the actual, physical -; height of the nozzle in mm. This can take some messing around -; with to get just right... -G92 X0 Y0 Z0 E0 ;reset software position to front/left/z=0.0 -G1 Z15.0 F{max_z_speed} ;move the platform down 15mm -G92 E0 ;zero the extruded length - -G1 F200 E5 ;extrude 5mm of feed stock -G1 F200 E3.5 ;reverse feed stock by 1.5mm -G92 E0 ;zero the extruded length again - -;go to the middle of the platform, and move to Z=0 before starting the print. -G1 X{machine_center_x} Y{machine_center_y} F{travel_speed} -G1 Z0.0 F{max_z_speed} diff --git a/Cura/gui/alterationPanel.py b/Cura/gui/alterationPanel.py index 2692b7fad3..43408f04b2 100644 --- a/Cura/gui/alterationPanel.py +++ b/Cura/gui/alterationPanel.py @@ -32,11 +32,9 @@ class alterationPanel(wx.Panel): self.currentFile = self.list.GetSelection() def loadFile(self, filename): - self.textArea.SetValue(unicode(profile.getAlterationFileContents(filename, False), "utf-8")) + self.textArea.SetValue(profile.getAlterationFile(filename)) def OnFocusLost(self, e): if self.currentFile == self.list.GetSelection(): - filename = profile.getAlterationFilePath(self.alterationFileList[self.list.GetSelection()]) - f = open(filename, "wb") - f.write(self.textArea.GetValue().encode("utf-8")) - f.close() + profile.setAlterationFile(self.alterationFileList[self.list.GetSelection()], self.textArea.GetValue()) + diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 421a14b3e7..3a17a45d30 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -3,10 +3,10 @@ from __future__ import division #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module. import __init__ -import ConfigParser, os, traceback, math, re +import ConfigParser, os, traceback, math, re, zlib, base64 ######################################################### -## Profile and preferences functions +## Default settings when none are found. ######################################################### #Single place to store the defaults, so we have a consistent set of default settings. @@ -53,6 +53,7 @@ profileDefaultSettings = { 'fill_overlap': '15', 'support_rate': '50', 'support_distance': '0.5', + 'support_margin': '3.0', 'joris': 'False', 'enable_skin': 'False', 'enable_raft': 'False', @@ -66,6 +67,58 @@ profileDefaultSettings = { 'add_start_end_gcode': 'True', 'gcode_extension': 'gcode', } +alterationDefault = { +####################################################################################### + 'start.gcode': """;Start GCode +G21 ;metric values +G90 ;absolute positioning + +G28 X0 Y0 ;move X/Y to min endstops +G28 Z0 ;move Z to min endstops + +; if your prints start too high, try changing the Z0.0 below +; to Z1.0 - the number after the Z is the actual, physical +; height of the nozzle in mm. This can take some messing around +; with to get just right... +G92 X0 Y0 Z0 E0 ;reset software position to front/left/z=0.0 +G1 Z15.0 F{max_z_speed} ;move the platform down 15mm +G92 E0 ;zero the extruded length + +G1 F200 E5 ;extrude 5mm of feed stock +G1 F200 E3.5 ;reverse feed stock by 1.5mm +G92 E0 ;zero the extruded length again + +;go to the middle of the platform, and move to Z=0 before starting the print. +G1 X{machine_center_x} Y{machine_center_y} F{travel_speed} +G1 Z0.0 F{max_z_speed} +""", +####################################################################################### + 'end.gcode': """;End GCode +M104 S0 ;extruder heat off +G91 ;relative positioning +G1 Z+10 E-5 F{max_z_speed} ;move Z up a bit and retract filament by 5mm +G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way +M84 ;steppers off +G90 ;absolute positioning +""", +####################################################################################### + 'support_start.gcode': '', + 'support_end.gcode': '', + 'cool_start.gcode': '', + 'cool_end.gcode': '', + 'replace.csv': '', +####################################################################################### + 'nextobject.gcode': """;Move to next object on the platform. clear_z is the minimal z height we need to make sure we do not hit any objects. +G92 E0 +G1 Z{clear_z} E-5 F{max_z_speed} +G92 E0 +G1 X{machine_center_x} Y{machine_center_y} F{travel_speed} +G1 F200 E5.5 +G92 E0 +G1 Z0 F{max_z_speed} +""", +####################################################################################### +} preferencesDefaultSettings = { 'wizardDone': 'False', 'startMode': 'Simple', @@ -83,6 +136,10 @@ preferencesDefaultSettings = { 'filament_cost_meter': '0', } +######################################################### +## Profile and preferences functions +######################################################### + def getDefaultProfilePath(): return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini")) @@ -100,19 +157,31 @@ def loadGlobalProfileFromString(options): global globalProfileParser globalProfileParser = ConfigParser.ConfigParser() globalProfileParser.add_section('profile') - for option in options.split('#'): + globalProfileParser.add_section('alterations') + options = base64.b64decode(options) + options = zlib.decompress(options) + (profileOpts, alt) = options.split('\f', 1) + for option in profileOpts.split('\b'): (key, value) = option.split('=', 1) globalProfileParser.set('profile', key, value) + for option in alt.split('\b'): + (key, value) = option.split('=', 1) + globalProfileParser.set('alterations', key, value) def getGlobalProfileString(): global globalProfileParser if not globals().has_key('globalProfileParser'): loadGlobalProfile(getDefaultProfilePath()) - ret = [] + p = [] + alt = [] for key in globalProfileParser.options('profile'): - ret.append(key + "=" + globalProfileParser.get('profile', key)) - return '#'.join(ret) + p.append(key + "=" + globalProfileParser.get('profile', key)) + for key in globalProfileParser.options('alterations'): + alt.append(key + "=" + globalProfileParser.get('alterations', key)) + ret = '\b'.join(p) + '\f' + '\b'.join(alt) + ret = base64.b64encode(zlib.compress(ret, 9)) + return ret def getProfileSetting(name): #Check if we have a configuration file loaded, else load the default. @@ -221,40 +290,55 @@ def calculateSolidLayerCount(): ######################################################### ## Alteration file functions ######################################################### -def getCuraBasePath(): - return os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) - -def getAlterationFilePath(filename): - return os.path.join(getCuraBasePath(), "alterations", filename) - def replaceTagMatch(m): tag = m.group(0)[1:-1] if tag in ['print_speed', 'retraction_speed', 'travel_speed', 'max_z_speed', 'bottom_layer_speed', 'cool_min_feedrate']: return str(getProfileSettingFloat(tag) * 60) return str(getProfileSettingFloat(tag)) -def getAlterationFileContents(filename, modifyForOutput = True): - "Get the file from the fileName or the lowercase fileName in the alterations directories." - prefix = '' - if modifyForOutput: - if filename == 'start.gcode': - #For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion. - #We also set our steps per E here, if configured. - eSteps = float(getPreference('steps_per_e')) - if eSteps > 0: - prefix += 'M92 E'+str(eSteps)+'\n' - temp = getProfileSettingFloat('print_temperature') - if temp > 0: - prefix += 'M109 S'+str(temp)+'\n' - elif filename == 'replace.csv': - prefix = 'M101\nM103\n' - fullFilename = getAlterationFilePath(filename) - if os.path.isfile(fullFilename): - file = open(fullFilename, "r") - fileText = file.read() - file.close() - if modifyForOutput: - fileText = re.sub("\{[^\}]*\}", replaceTagMatch, fileText) - return prefix + fileText - return prefix +### Get aleration raw contents. (Used internally in Cura) +def getAlterationFile(filename): + #Check if we have a configuration file loaded, else load the default. + if not globals().has_key('globalProfileParser'): + loadGlobalProfile(getDefaultProfilePath()) + + if not globalProfileParser.has_option('alterations', filename): + if filename in alterationDefault: + default = alterationDefault[filename] + else: + print "Missing default alteration for: '" + filename + "'" + alterationDefault[filename] = '' + default = '' + if not globalProfileParser.has_section('alterations'): + globalProfileParser.add_section('alterations') + #print "Using default for: %s" % (filename) + globalProfileParser.set('alterations', filename, default) + return unicode(globalProfileParser.get('alterations', filename), "utf-8") + +def setAlterationFile(filename, value): + #Check if we have a configuration file loaded, else load the default. + if not globals().has_key('globalProfileParser'): + loadGlobalProfile(getDefaultProfilePath()) + if not globalProfileParser.has_section('alterations'): + globalProfileParser.add_section('alterations') + globalProfileParser.set('alterations', filename, value.encode("utf-8")) + saveGlobalProfile(profile.getDefaultProfilePath()) + +### Get the alteration file for output. (Used by Skeinforge) +def getAlterationFileContents(filename): + prefix = '' + if filename == 'start.gcode': + #For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion. + #We also set our steps per E here, if configured. + eSteps = float(getPreference('steps_per_e')) + if eSteps > 0: + prefix += 'M92 E%f\n' % (eSteps) + temp = getProfileSettingFloat('print_temperature') + if temp > 0: + prefix += 'M109 S%f\n' % (temp) + elif filename == 'replace.csv': + #Always remove the extruder on/off M codes. These are no longer needed in 5D printing. + prefix = 'M101\nM103\n' + + return prefix + re.sub("\{[^\}]*\}", replaceTagMatch, getAlterationFile(filename)) From 3645523074ecead961c36811c58ec1acd1f2d657 Mon Sep 17 00:00:00 2001 From: daid Date: Mon, 23 Apr 2012 18:23:29 +0200 Subject: [PATCH 2/6] Remove menu from project planner, and replace it with toolbar buttons. --- Cura/gui/projectPlanner.py | 17 +++++------------ Cura/images/exit.png | Bin 0 -> 713 bytes Cura/images/open.png | Bin 0 -> 423 bytes Cura/images/save.png | Bin 0 -> 563 bytes 4 files changed, 5 insertions(+), 12 deletions(-) create mode 100644 Cura/images/exit.png create mode 100644 Cura/images/open.png create mode 100644 Cura/images/save.png diff --git a/Cura/gui/projectPlanner.py b/Cura/gui/projectPlanner.py index f5340ee08f..18027f67f1 100644 --- a/Cura/gui/projectPlanner.py +++ b/Cura/gui/projectPlanner.py @@ -36,18 +36,6 @@ class projectPlanner(wx.Frame): wx.EVT_CLOSE(self, self.OnClose) #self.SetIcon(icon.getMainIcon()) - menubar = wx.MenuBar() - fileMenu = wx.Menu() - i = fileMenu.Append(-1, 'Open Project...') - self.Bind(wx.EVT_MENU, self.OnLoadProject, i) - i = fileMenu.Append(-1, 'Save Project...') - self.Bind(wx.EVT_MENU, self.OnSaveProject, i) - fileMenu.AppendSeparator() - i = fileMenu.Append(wx.ID_EXIT, 'Quit') - self.Bind(wx.EVT_MENU, self.OnQuit, i) - menubar.Append(fileMenu, '&File') - self.SetMenuBar(menubar) - self.list = [] self.selection = None @@ -57,9 +45,14 @@ class projectPlanner(wx.Frame): self.toolbar = toolbarUtil.Toolbar(self) + toolbarUtil.NormalButton(self.toolbar, self.OnLoadProject, 'open.png', 'Open project') + toolbarUtil.NormalButton(self.toolbar, self.OnSaveProject, 'save.png', 'Save project') + self.toolbar.AddSeparator() group = [] toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick) toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick).SetValue(True) + self.toolbar.AddSeparator() + toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner') self.toolbar.Realize() diff --git a/Cura/images/exit.png b/Cura/images/exit.png new file mode 100644 index 0000000000000000000000000000000000000000..846776e3b6fa3a2454d2d515187b92af7bdbd6bc GIT binary patch literal 713 zcmV;)0yh1LP)x zK~y-)rISBTQ(+XwfA77wx2^qyrCgBM##pqXk%Z9?fPX@Qi3xy)zu%H%gf*2AR=|u+uQ%FS{2FVHe_wBAnWS| z$>s8r&E{ogB`1Z#jtmb!oCSh^+dy@9UuS0KBO@bE@caE()~;-9>?IY?<1oNf%9F_DqLoq!e=vv>Z6fOIRy-cZ zah#(80w)JDOIOv4Q4qoKc-R|CB+^J@WAtdiDe!q6C(yoAq$`!8Qqxql=EL-R=H_Mz z1dbih8vw7p-pO=4KL0Hin;(zGUIk23`FwujnGD6pkI+g{*xF*?*1*06t@ZCa@H8}B ziuCj}RkY@uVNl)Jpq5JEv2B7=Q`8KTYeV-*r!rWkb-;oJU=)kx>hv_)bt$_ps$9mb zRA74>yIN&Aa-2BOe!iVjakCy!c3s(8SU_uy4TSd^Ht@NlgY4})xT&wSI1Z6WWY5AM zfSV!@OpydoZh#Y?U@!p2VrM6rp&{CmXR)>B%!P}j(`f+0;gAQ=N<>gfnScopgewKh zntUs=bFZ~^#%OL{3VFS?P$;Zy+uqLS^IoNl)7k9L<;BG>PwR5vRVr~e93F2q%|Re~ vxDP0x1!x8Q>TsNuQZ^6*N+RO^E6%?FI@&7dg_Aem00000NkvXXu0mjfqn$fK literal 0 HcmV?d00001 diff --git a/Cura/images/open.png b/Cura/images/open.png new file mode 100644 index 0000000000000000000000000000000000000000..32ec3edbb8b361d6006b9c93f267a3e671f3bdfd GIT binary patch literal 423 zcmV;Y0a*TtP)MPJ)&0003-NklQjTj}UYT3`qz)w0g-cGii---RU4GwJxso zgJHgz@B7d9pBX8gN$syH2@MyXbbY6Ac5&*KN7Gc%Xy~Hf?@t_>riyeXwdJOlG))!B zLtqX}opXhr8QZ)#0F2E($M{%0&U-2QZ8mM~7a|bnPAthDNa;AR3Jj zi^Uy@A@F#Ob(3dSMh@ENdDiyI*k;3%&=-=q zKgf*VU=D`jSADwLwh;46e;f=mfB>Z7ECdJ}gax(*b{_`cAS}d}F+QMPuVa}5e1T;? zJGY*$5U@T>pyda6Hd<`v3Un%0p2Q1rh3ZMJ3FM_pc118dcfjTPar21(@&i}m%Qd94 RDM|nU002ovPDHLkV1nZ{t|b5f literal 0 HcmV?d00001 diff --git a/Cura/images/save.png b/Cura/images/save.png new file mode 100644 index 0000000000000000000000000000000000000000..8072aea3268164eb2028a0cebfe44da82b4f4aca GIT binary patch literal 563 zcmV-30?hr1P)XvKK@k7Ytwo{YB(9F? z;2_0Ku;{F~yQsL?!9iy?1;;|c4%SjZ%{70TwwHKcBH=J-%EN&+{;d zhN(E7P<- zOhP?!y}wyJm`;b*`kqJvqBiX|nL~L2fd*Ux1d!eYF6Tbg5P<9ZC&&uF5~UDVJ~Kya z$B9GKW9yGCk1)gXRIvtRXipPk@<6(R{ z10;&Qkze=csdPHpgO1qUX}3Wtm&>>~JBMXkI4Be#D>XTZ+DDB(A$cT#*xhj)kQiey zO%sM;K-YE1@`TY9(UZv}-m29|6TcYK$LKUNox!$kO4I`&Fl}aA7Py>1;e44jn~%EA z#v7jv1002ovPDHLkV1jI` B^11*3 literal 0 HcmV?d00001 From f7071d59cfe677f5a3638be55a9b679d05acfa01 Mon Sep 17 00:00:00 2001 From: Lawrence Johnston Date: Mon, 23 Apr 2012 20:02:50 -0700 Subject: [PATCH 3/6] Fixes #73: When start.gcode is changed changes are not saved --- Cura/util/profile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 3a17a45d30..1596f043dd 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -322,7 +322,7 @@ def setAlterationFile(filename, value): if not globalProfileParser.has_section('alterations'): globalProfileParser.add_section('alterations') globalProfileParser.set('alterations', filename, value.encode("utf-8")) - saveGlobalProfile(profile.getDefaultProfilePath()) + saveGlobalProfile(getDefaultProfilePath()) ### Get the alteration file for output. (Used by Skeinforge) def getAlterationFileContents(filename): From 95705f77d5a4d89ce66c2f4b73ea860edd32b877 Mon Sep 17 00:00:00 2001 From: daid Date: Tue, 24 Apr 2012 11:31:34 +0200 Subject: [PATCH 4/6] Fixed #75 - Unicode chars in start/end code caused crash. --- Cura/cura_sf/fabmetheus_utilities/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cura/cura_sf/fabmetheus_utilities/settings.py b/Cura/cura_sf/fabmetheus_utilities/settings.py index bbc9ff397f..0e053c86b2 100644 --- a/Cura/cura_sf/fabmetheus_utilities/settings.py +++ b/Cura/cura_sf/fabmetheus_utilities/settings.py @@ -446,7 +446,7 @@ def getAlterationLines(fileName): return archive.getTextLines(getAlterationFile(fileName)) def getAlterationFile(fileName): - return profile.getAlterationFileContents(fileName) + return unicode(profile.getAlterationFileContents(fileName)).encode("utf-8") #################################### ## Configuration settings classes ## From a6253b7f489968f6d4b55335df9032cb276961cc Mon Sep 17 00:00:00 2001 From: daid Date: Tue, 24 Apr 2012 11:59:17 +0200 Subject: [PATCH 5/6] Only add temperature to start code if the temperature is not configured in the start code already. Fixes #76 --- Cura/util/profile.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 1596f043dd..5fa85b7ff2 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -64,6 +64,7 @@ profileDefaultSettings = { 'raft_base_material_amount': '100', 'raft_interface_material_amount': '100', 'bottom_thickness': '0.3', + 'add_start_end_gcode': 'True', 'gcode_extension': 'gcode', } @@ -327,6 +328,7 @@ def setAlterationFile(filename, value): ### Get the alteration file for output. (Used by Skeinforge) def getAlterationFileContents(filename): prefix = '' + alterationContents = getAlterationFile(filename) if filename == 'start.gcode': #For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion. #We also set our steps per E here, if configured. @@ -334,11 +336,11 @@ def getAlterationFileContents(filename): if eSteps > 0: prefix += 'M92 E%f\n' % (eSteps) temp = getProfileSettingFloat('print_temperature') - if temp > 0: + if temp > 0 and not '{print_temperature}' in alterationContents: prefix += 'M109 S%f\n' % (temp) elif filename == 'replace.csv': #Always remove the extruder on/off M codes. These are no longer needed in 5D printing. prefix = 'M101\nM103\n' - return prefix + re.sub("\{[^\}]*\}", replaceTagMatch, getAlterationFile(filename)) + return prefix + re.sub("\{[^\}]*\}", replaceTagMatch, alterationContents) From b6492df81eda6e3df6fd6b0ab17ea3122659f102 Mon Sep 17 00:00:00 2001 From: daid Date: Tue, 24 Apr 2012 12:03:03 +0200 Subject: [PATCH 6/6] Add the ability to edit the nextobject.gcode --- Cura/gui/alterationPanel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cura/gui/alterationPanel.py b/Cura/gui/alterationPanel.py index 43408f04b2..c102f19b1f 100644 --- a/Cura/gui/alterationPanel.py +++ b/Cura/gui/alterationPanel.py @@ -7,7 +7,7 @@ class alterationPanel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent,-1) - self.alterationFileList = ['start.gcode', 'end.gcode', 'support_start.gcode', 'support_end.gcode', 'replace.csv'] + self.alterationFileList = ['start.gcode', 'end.gcode', 'support_start.gcode', 'support_end.gcode', 'nextobject.gcode', 'replace.csv'] self.currentFile = None self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_PROCESS_TAB)