chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / skeinforge_application / skeinforge_plugins / craft_plugins / lift.py
1 """
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.
4
5 ==Operation==
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.
7
8 ==Settings==
9 ===Cutting Lift over Layer Step===
10 Default is minus 0.5, because the end mill is the more common tool.
11
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.
13
14 ===Clearance above Top===
15 Default is 5 millimeters.
16
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.
18
19 ==Examples==
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.
21
22 > python lift.py
23 This brings up the lift dialog.
24
25 > python lift.py Screw Holder Bottom.stl
26 The lift tool is parsing the file:
27 Screw Holder Bottom.stl
28 ..
29 The lift tool has created the file:
30 .. Screw Holder Bottom_lift.gcode
31
32 """
33
34 from __future__ import absolute_import
35
36 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
37 from fabmetheus_utilities import archive
38 from fabmetheus_utilities import gcodec
39 from fabmetheus_utilities import settings
40 from skeinforge_application.skeinforge_utilities import skeinforge_craft
41 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
42 from skeinforge_application.skeinforge_utilities import skeinforge_profile
43 import sys
44
45 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
46 __date__ = '$Date: 2008/02/05 $'
47 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
48
49
50 def getCraftedText( fileName, text='', liftRepository = None ):
51         "Lift the preface file or text."
52         return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), liftRepository )
53
54 def getCraftedTextFromText( gcodeText, liftRepository = None ):
55         "Lift the preface gcode text."
56         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lift'):
57                 return gcodeText
58         if liftRepository == None:
59                 liftRepository = settings.getReadRepository( LiftRepository() )
60         if not liftRepository.activateLift.value:
61                 return gcodeText
62         return LiftSkein().getCraftedGcode( liftRepository, gcodeText )
63
64 def getNewRepository():
65         'Get new repository.'
66         return LiftRepository()
67
68 def writeOutput(fileName, shouldAnalyze=True):
69         "Lift the carving of a gcode file."
70         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lift', shouldAnalyze)
71
72
73 class LiftRepository(object):
74         "A class to handle the lift settings."
75         def __init__(self):
76                 "Set the default settings, execute title & settings fileName."
77                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lift.html', self )
78                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File to be Lifted', self, '')
79                 self.activateLift = settings.BooleanSetting().getFromValue('Activate Lift', self, True )
80                 self.cuttingLiftOverLayerStep = settings.FloatSpin().getFromValue( - 1.0, 'Cutting Lift over Layer Step (ratio):', self, 1.0, - 0.5 )
81                 self.clearanceAboveTop = settings.FloatSpin().getFromValue( 0.0, 'Clearance above Top (mm):', self, 10.0, 5.0 )
82                 self.executeTitle = 'Lift'
83
84         def execute(self):
85                 "Lift button has been clicked."
86                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
87                 for fileName in fileNames:
88                         writeOutput(fileName)
89
90
91 class LiftSkein(object):
92         "A class to lift a skein of extrusions."
93         def __init__(self):
94                 self.distanceFeedRate = gcodec.DistanceFeedRate()
95                 self.extruderActive = False
96                 self.layerStep = None
97                 self.layerHeight = 0.3333333333
98                 self.lineIndex = 0
99                 self.maximumZ = - 912345678.0
100                 self.oldLocation = None
101                 self.previousActiveMovementLine = None
102                 self.previousInactiveMovementLine = None
103
104         def addPreviousInactiveMovementLineIfNecessary(self):
105                 "Add the previous inactive movement line if necessary."
106                 if self.previousInactiveMovementLine != None:
107                         self.distanceFeedRate.addLine( self.previousInactiveMovementLine )
108                         self.previousInactiveMovementLine = None
109
110         def getCraftedGcode( self, liftRepository, gcodeText ):
111                 "Parse gcode text and store the lift gcode."
112                 self.liftRepository = liftRepository
113                 self.lines = archive.getTextLines(gcodeText)
114                 self.parseInitialization()
115                 self.oldLocation = None
116                 if self.layerStep == None:
117                         self.layerStep = self.layerHeight
118                 self.cuttingLift = self.layerStep * liftRepository.cuttingLiftOverLayerStep.value
119                 self.setMaximumZ()
120                 self.travelZ = self.maximumZ + 0.5 * self.layerStep + liftRepository.clearanceAboveTop.value
121                 for line in self.lines[self.lineIndex :]:
122                         self.parseLine(line)
123                 return self.distanceFeedRate.output.getvalue()
124
125         def getLinearMove( self, line, location, splitLine ):
126                 "Get the linear move."
127                 if self.extruderActive:
128                         z = location.z + self.cuttingLift
129                         return self.distanceFeedRate.getLineWithZ( line, splitLine, z )
130                 if self.previousActiveMovementLine != None:
131                         previousActiveMovementLineSplit = self.previousActiveMovementLine.split()
132                         self.distanceFeedRate.addLine( self.distanceFeedRate.getLineWithZ( self.previousActiveMovementLine, previousActiveMovementLineSplit, self.travelZ ) )
133                         self.previousActiveMovementLine = None
134                 self.distanceFeedRate.addLine( self.distanceFeedRate.getLineWithZ( line, splitLine, self.travelZ ) )
135                 self.previousInactiveMovementLine = line
136                 return ''
137
138         def parseInitialization(self):
139                 'Parse gcode initialization and store the parameters.'
140                 for self.lineIndex in xrange(len(self.lines)):
141                         line = self.lines[self.lineIndex].lstrip()
142                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
143                         firstWord = gcodec.getFirstWord(splitLine)
144                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
145                         if firstWord == '(</extruderInitialization>)':
146                                 self.distanceFeedRate.addTagBracketedProcedure('lift')
147                                 return
148                         elif firstWord == '(<layerHeight>':
149                                 self.layerHeight = float(splitLine[1])
150                         elif firstWord == '(<layerStep>':
151                                 self.layerStep = float(splitLine[1])
152                         self.distanceFeedRate.addLine(line)
153
154         def parseLine(self, line):
155                 "Parse a gcode line and add it to the lift skein."
156                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
157                 if len(splitLine) < 1:
158                         return
159                 firstWord = splitLine[0]
160                 if firstWord == 'G1':
161                         location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
162                         line = self.getLinearMove( line, location, splitLine )
163                         self.previousActiveMovementLine = line
164                         self.oldLocation = location
165                 elif firstWord == 'M101':
166                         self.addPreviousInactiveMovementLineIfNecessary()
167                         self.extruderActive = True
168                 elif firstWord == 'M103':
169                         self.extruderActive = False
170                 self.distanceFeedRate.addLine(line)
171
172         def setMaximumZ(self):
173                 "Set maximum  z."
174                 localOldLocation = None
175                 for line in self.lines[self.lineIndex :]:
176                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
177                         firstWord = gcodec.getFirstWord(splitLine)
178                         if firstWord == 'G1':
179                                 location = gcodec.getLocationFromSplitLine( localOldLocation, splitLine )
180                                 self.maximumZ = max( self.maximumZ, location.z )
181                                 localOldLocation = location
182
183
184 def main():
185         "Display the lift dialog."
186         if len(sys.argv) > 1:
187                 writeOutput(' '.join(sys.argv[1 :]))
188         else:
189                 settings.startMainLoopFromConstructor(getNewRepository())
190
191 if __name__ == "__main__":
192         main()