2 This page is in the table of contents.
3 Lift will change the altitude of the cutting tool when it is on so that it will cut through the slab at the correct altitude. It will also lift the gcode when the tool is off so that the cutting tool will clear the top of the slab.
6 The default 'Activate Lift' checkbox is on. When it is on, the functions described below will work, when it is off, the functions will not be called.
9 ===Cutting Lift over Layer Step===
10 Default is minus 0.5, because the end mill is the more common tool.
12 Defines the ratio of the amount the cutting tool will be lifted over the layer step. If whittle is off the layer step will be the layer height, if it is on, it will be the layer step from the whittle gcode. If the cutting tool is like an end mill, where the cutting happens until the end of the tool, then the 'Cutting Lift over Layer Step' should be minus 0.5, so that the end mill cuts to the bottom of the slab. If the cutting tool is like a laser, where the cutting happens around the focal point. the 'Cutting Lift over Layer Step' should be zero, so that the cutting action will be focused in the middle of the slab.
14 ===Clearance above Top===
15 Default is 5 millimeters.
17 Defines the distance above the top of the slab the cutting tool will be lifted when will tool is off so that the cutting tool will clear the top of the slab.
20 The following examples lift the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and lift.py.
23 This brings up the lift dialog.
25 > python lift.py Screw Holder Bottom.stl
26 The lift tool is parsing the file:
27 Screw Holder Bottom.stl
29 The lift tool has created the file:
30 .. Screw Holder Bottom_lift.gcode
34 from __future__ import absolute_import
35 #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.
38 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
39 from fabmetheus_utilities import archive
40 from fabmetheus_utilities import gcodec
41 from fabmetheus_utilities import settings
42 from skeinforge_application.skeinforge_utilities import skeinforge_craft
43 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
44 from skeinforge_application.skeinforge_utilities import skeinforge_profile
48 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
49 __date__ = '$Date: 2008/02/05 $'
50 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
53 def getCraftedText( fileName, text='', liftRepository = None ):
54 "Lift the preface file or text."
55 return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), liftRepository )
57 def getCraftedTextFromText( gcodeText, liftRepository = None ):
58 "Lift the preface gcode text."
59 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lift'):
61 if liftRepository == None:
62 liftRepository = settings.getReadRepository( LiftRepository() )
63 if not liftRepository.activateLift.value:
65 return LiftSkein().getCraftedGcode( liftRepository, gcodeText )
67 def getNewRepository():
69 return LiftRepository()
71 def writeOutput(fileName, shouldAnalyze=True):
72 "Lift the carving of a gcode file."
73 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lift', shouldAnalyze)
77 "A class to handle the lift settings."
79 "Set the default settings, execute title & settings fileName."
80 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lift.html', self )
81 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File to be Lifted', self, '')
82 self.activateLift = settings.BooleanSetting().getFromValue('Activate Lift', self, True )
83 self.cuttingLiftOverLayerStep = settings.FloatSpin().getFromValue( - 1.0, 'Cutting Lift over Layer Step (ratio):', self, 1.0, - 0.5 )
84 self.clearanceAboveTop = settings.FloatSpin().getFromValue( 0.0, 'Clearance above Top (mm):', self, 10.0, 5.0 )
85 self.executeTitle = 'Lift'
88 "Lift button has been clicked."
89 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
90 for fileName in fileNames:
95 "A class to lift a skein of extrusions."
97 self.distanceFeedRate = gcodec.DistanceFeedRate()
98 self.extruderActive = False
100 self.layerHeight = 0.3333333333
102 self.maximumZ = - 912345678.0
103 self.oldLocation = None
104 self.previousActiveMovementLine = None
105 self.previousInactiveMovementLine = None
107 def addPreviousInactiveMovementLineIfNecessary(self):
108 "Add the previous inactive movement line if necessary."
109 if self.previousInactiveMovementLine != None:
110 self.distanceFeedRate.addLine( self.previousInactiveMovementLine )
111 self.previousInactiveMovementLine = None
113 def getCraftedGcode( self, liftRepository, gcodeText ):
114 "Parse gcode text and store the lift gcode."
115 self.liftRepository = liftRepository
116 self.lines = archive.getTextLines(gcodeText)
117 self.parseInitialization()
118 self.oldLocation = None
119 if self.layerStep == None:
120 self.layerStep = self.layerHeight
121 self.cuttingLift = self.layerStep * liftRepository.cuttingLiftOverLayerStep.value
123 self.travelZ = self.maximumZ + 0.5 * self.layerStep + liftRepository.clearanceAboveTop.value
124 for line in self.lines[self.lineIndex :]:
126 return self.distanceFeedRate.output.getvalue()
128 def getLinearMove( self, line, location, splitLine ):
129 "Get the linear move."
130 if self.extruderActive:
131 z = location.z + self.cuttingLift
132 return self.distanceFeedRate.getLineWithZ( line, splitLine, z )
133 if self.previousActiveMovementLine != None:
134 previousActiveMovementLineSplit = self.previousActiveMovementLine.split()
135 self.distanceFeedRate.addLine( self.distanceFeedRate.getLineWithZ( self.previousActiveMovementLine, previousActiveMovementLineSplit, self.travelZ ) )
136 self.previousActiveMovementLine = None
137 self.distanceFeedRate.addLine( self.distanceFeedRate.getLineWithZ( line, splitLine, self.travelZ ) )
138 self.previousInactiveMovementLine = line
141 def parseInitialization(self):
142 'Parse gcode initialization and store the parameters.'
143 for self.lineIndex in xrange(len(self.lines)):
144 line = self.lines[self.lineIndex].lstrip()
145 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
146 firstWord = gcodec.getFirstWord(splitLine)
147 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
148 if firstWord == '(</extruderInitialization>)':
149 self.distanceFeedRate.addTagBracketedProcedure('lift')
151 elif firstWord == '(<layerHeight>':
152 self.layerHeight = float(splitLine[1])
153 elif firstWord == '(<layerStep>':
154 self.layerStep = float(splitLine[1])
155 self.distanceFeedRate.addLine(line)
157 def parseLine(self, line):
158 "Parse a gcode line and add it to the lift skein."
159 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
160 if len(splitLine) < 1:
162 firstWord = splitLine[0]
163 if firstWord == 'G1':
164 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
165 line = self.getLinearMove( line, location, splitLine )
166 self.previousActiveMovementLine = line
167 self.oldLocation = location
168 elif firstWord == 'M101':
169 self.addPreviousInactiveMovementLineIfNecessary()
170 self.extruderActive = True
171 elif firstWord == 'M103':
172 self.extruderActive = False
173 self.distanceFeedRate.addLine(line)
175 def setMaximumZ(self):
177 localOldLocation = None
178 for line in self.lines[self.lineIndex :]:
179 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
180 firstWord = gcodec.getFirstWord(splitLine)
181 if firstWord == 'G1':
182 location = gcodec.getLocationFromSplitLine( localOldLocation, splitLine )
183 self.maximumZ = max( self.maximumZ, location.z )
184 localOldLocation = location
188 "Display the lift dialog."
189 if len(sys.argv) > 1:
190 writeOutput(' '.join(sys.argv[1 :]))
192 settings.startMainLoopFromConstructor(getNewRepository())
194 if __name__ == "__main__":