3 This page is in the table of contents.
4 The alteration plugin adds the start and end files to the gcode.
6 This plugin also removes the alteration prefix tokens from the alteration lines. Alteration lines have a prefix token so they can go through the craft plugins without being modified. However, the tokens are not recognized by the firmware so they have to be removed before export. The alteration token is:
7 (<alterationDeleteThisPrefix/>)
9 The alteration manual page is at:
10 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Alteration
13 The default 'Activate Alteration' checkbox is on. When it is on, the functions described below will work, when it is off, nothing will be done.
16 Alteration looks for alteration files in the alterations folder in the .skeinforge folder in the home directory. Alteration does not care if the text file names are capitalized, but some file systems do not handle file name cases properly, so to be on the safe side you should give them lower case names. If it doesn't find the file it then looks in the alterations folder in the skeinforge_plugins folder.
18 ===Name of End File===
19 Default is 'end.gcode'.
21 If there is a file with the name of the "Name of End File" setting, it will be added to the very end of the gcode.
23 ===Name of Start File===
24 Default is 'start.gcode'.
26 If there is a file with the name of the "Name of Start File" setting, it will be added to the very beginning of the gcode.
28 ===Remove Redundant Mcode===
31 If 'Remove Redundant Mcode' is selected then M104 and M108 lines which are followed by a different value before there is a movement will be removed. For example, if there is something like:
38 with Remove Redundant Mcode selected, that snippet would become:
44 This is a relatively safe procedure, the only reason it is optional is because someone might make an alteration file which, for some unknown reason, requires the redundant mcode.
46 ===Replace Variable with Setting===
49 If 'Replace Variable with Setting' is selected and there is an alteration line with a setting token, the token will be replaced by the value.
51 For example, if there is an alteration line like:
53 M140 S<setting.chamber.BedTemperature>
55 the token would be replaced with the value and assuming the bed chamber was 60.0, the output would be:
60 The following examples add the alteration information to the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and alteration.py.
62 > python alteration.py
63 This brings up the alteration dialog.
65 > python alteration.py Screw Holder Bottom.stl
66 The alteration tool is parsing the file:
67 Screw Holder Bottom.stl
69 The alteration tool has created the file:
70 .. Screw Holder Bottom_alteration.gcode
74 from __future__ import absolute_import
76 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
77 from fabmetheus_utilities import archive
78 from fabmetheus_utilities import gcodec
79 from fabmetheus_utilities import settings
80 from skeinforge_application.skeinforge_utilities import skeinforge_craft
81 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
82 from skeinforge_application.skeinforge_utilities import skeinforge_profile
87 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
88 __date__ = '$Date: 2008/02/05 $'
89 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
92 def getCraftedText(fileName, text='', repository=None):
93 'Alteration a gcode linear move text.'
94 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository, fileName)
96 def getCraftedTextFromText(gcodeText, repository=None, fileName=''):
97 'Alteration a gcode linear move text.'
98 if gcodec.isProcedureDoneOrFileIsEmpty(gcodeText, 'alteration'):
100 if repository == None:
101 repository = settings.getReadRepository(AlterationRepository())
102 if not repository.activateAlteration.value:
104 return AlterationSkein().getCraftedGcode(gcodeText, repository, fileName)
106 def getGcodeTextWithoutRedundantMcode(gcodeText):
107 'Get gcode text without redundant M104 and M108.'
108 lines = archive.getTextLines(gcodeText)
109 lines = getLinesWithoutRedundancy('M104', lines)
110 lines = getLinesWithoutRedundancy('M108', lines)
111 output = cStringIO.StringIO()
112 gcodec.addLinesToCString(output, lines)
113 return output.getvalue()
115 def getLinesWithoutRedundancy(duplicateWord, lines):
116 'Get gcode lines without redundant first words.'
117 oldDuplicationIndex = None
118 for lineIndex, line in enumerate(lines):
119 firstWord = gcodec.getFirstWordFromLine(line)
120 if firstWord == duplicateWord:
121 if oldDuplicationIndex == None:
122 oldDuplicationIndex = lineIndex
124 lines[oldDuplicationIndex] = line
125 lines[lineIndex] = ''
126 elif firstWord.startswith('G') or firstWord == 'M101' or firstWord == 'M103':
127 oldDuplicationIndex = None
130 def getNewRepository():
131 'Get new repository.'
132 return AlterationRepository()
134 def writeOutput(fileName, shouldAnalyze=True):
135 'Alteration a gcode linear move file. Chain alteration the gcode if the alteration procedure has not been done.'
136 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'alteration', shouldAnalyze)
139 class AlterationRepository(object):
140 "A class to handle the alteration settings."
142 "Set the default settings, execute title & settings fileName."
143 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.alteration.html', self )
144 self.baseNameSynonym = 'bookend.csv'
145 self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Alteration', self, '')
146 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Alteration')
147 self.activateAlteration = settings.BooleanSetting().getFromValue('Activate Alteration', self, True)
148 self.nameOfEndFile = settings.StringSetting().getFromValue('Name of End File:', self, 'end.gcode')
149 self.nameOfStartFile = settings.StringSetting().getFromValue('Name of Start File:', self, 'start.gcode')
150 self.removeRedundantMcode = settings.BooleanSetting().getFromValue('Remove Redundant Mcode', self, True)
151 self.replaceVariableWithSetting = settings.BooleanSetting().getFromValue('Replace Variable with Setting', self, True)
152 self.executeTitle = 'Alteration'
155 'Alteration button has been clicked.'
156 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
157 for fileName in fileNames:
158 writeOutput(fileName)
161 class AlterationSkein(object):
162 "A class to alteration a skein of extrusions."
165 self.distanceFeedRate = gcodec.DistanceFeedRate()
167 self.settingDictionary = None
169 def addFromUpperLowerFile(self, fileName):
170 "Add lines of text from the fileName or the lowercase fileName, if there is no file by the original fileName in the directory."
171 alterationFileLines = map(lambda l: l.replace('?filename?', self.fileName.encode('ascii', 'replace')), settings.getAlterationFileLines(fileName))
172 self.distanceFeedRate.addLinesSetAbsoluteDistanceMode(alterationFileLines)
174 def getCraftedGcode(self, gcodeText, repository, fileName):
175 "Parse gcode text and store the bevel gcode."
176 self.fileName = fileName
177 self.lines = archive.getTextLines(gcodeText)
178 if repository.replaceVariableWithSetting.value:
179 self.setSettingDictionary()
180 self.addFromUpperLowerFile(repository.nameOfStartFile.value) # Add a start file if it exists.
181 self.parseInitialization()
182 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
183 line = self.lines[self.lineIndex]
184 self.distanceFeedRate.addLine(line)
185 self.addFromUpperLowerFile(repository.nameOfEndFile.value) # Add an end file if it exists.
186 gcodeText = self.getReplacedAlterationText()
187 if repository.removeRedundantMcode.value:
188 gcodeText = getGcodeTextWithoutRedundantMcode(gcodeText)
191 def getReplacedAlterationLine(self, alterationFileLine, searchIndex=0):
192 'Get the alteration file line with variables replaced with the settings.'
193 settingIndex = alterationFileLine.find('setting.', searchIndex)
194 beginIndex = settingIndex - 1
196 return alterationFileLine
197 endBracketIndex = alterationFileLine.find('>', settingIndex)
198 if alterationFileLine[beginIndex] != '<' or endBracketIndex == -1:
199 return alterationFileLine
200 endIndex = endBracketIndex + 1
201 innerToken = alterationFileLine[settingIndex + len('setting.'): endIndex].replace('>', '').replace(' ', '').replace('_', '').lower()
202 if innerToken in self.settingDictionary:
203 replacedSetting = self.settingDictionary[innerToken]
204 replacedAlterationLine = alterationFileLine[: beginIndex] + replacedSetting + alterationFileLine[endIndex :]
205 return self.getReplacedAlterationLine(replacedAlterationLine, beginIndex + len(replacedSetting))
206 return alterationFileLine
208 def getReplacedAlterationText(self):
209 'Replace the alteration lines if there are settings.'
210 if self.settingDictionary == None:
211 return self.distanceFeedRate.output.getvalue().replace('(<alterationDeleteThisPrefix/>)', '')
212 lines = archive.getTextLines(self.distanceFeedRate.output.getvalue())
213 distanceFeedRate = gcodec.DistanceFeedRate()
215 if line.startswith('(<alterationDeleteThisPrefix/>)'):
216 line = self.getReplacedAlterationLine(line[len('(<alterationDeleteThisPrefix/>)') :])
217 distanceFeedRate.addLine(line)
218 return distanceFeedRate.output.getvalue()
220 def parseInitialization(self):
221 'Parse gcode initialization and store the parameters.'
222 for self.lineIndex in xrange(len(self.lines)):
223 line = self.lines[self.lineIndex]
224 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
225 firstWord = gcodec.getFirstWord(splitLine)
226 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
227 if firstWord == '(</extruderInitialization>)':
228 self.distanceFeedRate.addTagBracketedProcedure('alteration')
230 self.distanceFeedRate.addLine(line)
232 def setSettingDictionary(self):
233 'Set the setting dictionary from the gcode text.'
234 for line in self.lines:
235 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
236 firstWord = gcodec.getFirstWord(splitLine)
237 if firstWord == '(<setting>' and self.settingDictionary != None:
238 if len(splitLine) > 4:
239 procedure = splitLine[1]
240 name = splitLine[2].replace('_', ' ').replace(' ', '')
242 name = name[: name.find('(')]
243 value = ' '.join(splitLine[3 : -1])
244 self.settingDictionary[(procedure + '.' + name).lower()] = value
245 elif firstWord == '(<settings>)':
246 self.settingDictionary = {}
247 elif firstWord == '(</settings>)':
252 "Display the alteration dialog."
253 if len(sys.argv) > 1:
254 writeOutput(' '.join(sys.argv[1 :]))
256 settings.startMainLoopFromConstructor(getNewRepository())
258 if __name__ == "__main__":