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
75 #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.
78 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
79 from fabmetheus_utilities import archive
80 from fabmetheus_utilities import gcodec
81 from fabmetheus_utilities import settings
82 from skeinforge_application.skeinforge_utilities import skeinforge_craft
83 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
84 from skeinforge_application.skeinforge_utilities import skeinforge_profile
89 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
90 __date__ = '$Date: 2008/02/05 $'
91 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
94 def getCraftedText(fileName, text='', repository=None):
95 'Alteration a gcode linear move text.'
96 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
98 def getCraftedTextFromText(gcodeText, repository=None):
99 'Alteration a gcode linear move text.'
100 if gcodec.isProcedureDoneOrFileIsEmpty(gcodeText, 'alteration'):
102 if repository == None:
103 repository = settings.getReadRepository(AlterationRepository())
104 if not repository.activateAlteration.value:
106 return AlterationSkein().getCraftedGcode(gcodeText, repository)
108 def getGcodeTextWithoutRedundantMcode(gcodeText):
109 'Get gcode text without redundant M104 and M108.'
110 lines = archive.getTextLines(gcodeText)
111 lines = getLinesWithoutRedundancy('M104', lines)
112 lines = getLinesWithoutRedundancy('M108', lines)
113 output = cStringIO.StringIO()
114 gcodec.addLinesToCString(output, lines)
115 return output.getvalue()
117 def getLinesWithoutRedundancy(duplicateWord, lines):
118 'Get gcode lines without redundant first words.'
119 oldDuplicationIndex = None
120 for lineIndex, line in enumerate(lines):
121 firstWord = gcodec.getFirstWordFromLine(line)
122 if firstWord == duplicateWord:
123 if oldDuplicationIndex == None:
124 oldDuplicationIndex = lineIndex
126 lines[oldDuplicationIndex] = line
127 lines[lineIndex] = ''
128 elif firstWord.startswith('G') or firstWord == 'M101' or firstWord == 'M103':
129 oldDuplicationIndex = None
132 def getNewRepository():
133 'Get new repository.'
134 return AlterationRepository()
136 def writeOutput(fileName, shouldAnalyze=True):
137 'Alteration a gcode linear move file. Chain alteration the gcode if the alteration procedure has not been done.'
138 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'alteration', shouldAnalyze)
141 class AlterationRepository:
142 "A class to handle the alteration settings."
144 "Set the default settings, execute title & settings fileName."
145 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.alteration.html', self )
146 self.baseNameSynonym = 'bookend.csv'
147 self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Alteration', self, '')
148 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Alteration')
149 self.activateAlteration = settings.BooleanSetting().getFromValue('Activate Alteration', self, True)
150 self.nameOfEndFile = settings.StringSetting().getFromValue('Name of End File:', self, 'end.gcode')
151 self.nameOfStartFile = settings.StringSetting().getFromValue('Name of Start File:', self, 'start.gcode')
152 self.removeRedundantMcode = settings.BooleanSetting().getFromValue('Remove Redundant Mcode', self, True)
153 self.replaceVariableWithSetting = settings.BooleanSetting().getFromValue('Replace Variable with Setting', self, True)
154 self.executeTitle = 'Alteration'
157 'Alteration button has been clicked.'
158 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
159 for fileName in fileNames:
160 writeOutput(fileName)
163 class AlterationSkein:
164 "A class to alteration a skein of extrusions."
167 self.distanceFeedRate = gcodec.DistanceFeedRate()
169 self.settingDictionary = None
171 def addFromUpperLowerFile(self, fileName):
172 "Add lines of text from the fileName or the lowercase fileName, if there is no file by the original fileName in the directory."
173 alterationFileLines = settings.getAlterationFileLines(fileName)
174 self.distanceFeedRate.addLinesSetAbsoluteDistanceMode(alterationFileLines)
176 def getCraftedGcode(self, gcodeText, repository):
177 "Parse gcode text and store the bevel gcode."
178 self.lines = archive.getTextLines(gcodeText)
179 if repository.replaceVariableWithSetting.value:
180 self.setSettingDictionary()
181 self.addFromUpperLowerFile(repository.nameOfStartFile.value) # Add a start file if it exists.
182 self.parseInitialization()
183 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
184 line = self.lines[self.lineIndex]
185 self.distanceFeedRate.addLine(line)
186 self.addFromUpperLowerFile(repository.nameOfEndFile.value) # Add an end file if it exists.
187 gcodeText = self.getReplacedAlterationText()
188 if repository.removeRedundantMcode.value:
189 gcodeText = getGcodeTextWithoutRedundantMcode(gcodeText)
192 def getReplacedAlterationLine(self, alterationFileLine, searchIndex=0):
193 'Get the alteration file line with variables replaced with the settings.'
194 settingIndex = alterationFileLine.find('setting.', searchIndex)
195 beginIndex = settingIndex - 1
197 return alterationFileLine
198 endBracketIndex = alterationFileLine.find('>', settingIndex)
199 if alterationFileLine[beginIndex] != '<' or endBracketIndex == -1:
200 return alterationFileLine
201 endIndex = endBracketIndex + 1
202 innerToken = alterationFileLine[settingIndex + len('setting.'): endIndex].replace('>', '').replace(' ', '').replace('_', '').lower()
203 if innerToken in self.settingDictionary:
204 replacedSetting = self.settingDictionary[innerToken]
205 replacedAlterationLine = alterationFileLine[: beginIndex] + replacedSetting + alterationFileLine[endIndex :]
206 return self.getReplacedAlterationLine(replacedAlterationLine, beginIndex + len(replacedSetting))
207 return alterationFileLine
209 def getReplacedAlterationText(self):
210 'Replace the alteration lines if there are settings.'
211 if self.settingDictionary == None:
212 return self.distanceFeedRate.output.getvalue().replace('(<alterationDeleteThisPrefix/>)', '')
213 lines = archive.getTextLines(self.distanceFeedRate.output.getvalue())
214 distanceFeedRate = gcodec.DistanceFeedRate()
216 if line.startswith('(<alterationDeleteThisPrefix/>)'):
217 line = self.getReplacedAlterationLine(line[len('(<alterationDeleteThisPrefix/>)') :])
218 distanceFeedRate.addLine(line)
219 return distanceFeedRate.output.getvalue()
221 def parseInitialization(self):
222 'Parse gcode initialization and store the parameters.'
223 for self.lineIndex in xrange(len(self.lines)):
224 line = self.lines[self.lineIndex]
225 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
226 firstWord = gcodec.getFirstWord(splitLine)
227 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
228 if firstWord == '(</extruderInitialization>)':
229 self.distanceFeedRate.addTagBracketedProcedure('alteration')
231 self.distanceFeedRate.addLine(line)
233 def setSettingDictionary(self):
234 'Set the setting dictionary from the gcode text.'
235 for line in self.lines:
236 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
237 firstWord = gcodec.getFirstWord(splitLine)
238 if firstWord == '(<setting>' and self.settingDictionary != None:
239 if len(splitLine) > 4:
240 procedure = splitLine[1]
241 name = splitLine[2].replace('_', ' ').replace(' ', '')
243 name = name[: name.find('(')]
244 value = ' '.join(splitLine[3 : -1])
245 self.settingDictionary[(procedure + '.' + name).lower()] = value
246 elif firstWord == '(<settings>)':
247 self.settingDictionary = {}
248 elif firstWord == '(</settings>)':
253 "Display the alteration dialog."
254 if len(sys.argv) > 1:
255 writeOutput(' '.join(sys.argv[1 :]))
257 settings.startMainLoopFromConstructor(getNewRepository())
259 if __name__ == "__main__":