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 / lash.py
1 """
2 This page is in the table of contents.
3 Lash is a script to partially compensate for the backlash of the tool head.
4
5 The lash manual page is at:
6 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash
7
8 The lash tool is ported from Erik de Bruijn's 3D-to-5D-Gcode php GPL'd script at:
9 http://objects.reprap.org/wiki/3D-to-5D-Gcode.php
10
11 The default values are from the settings in Erik's 3D-to-5D-Gcode, I believe the settings are used on his Darwin reprap.
12
13 ==Operation==
14 The default 'Activate Lash' checkbox is off.  When it is on, the functions described below will work, when it is off, nothing will be done.
15
16 ==Settings==
17 ===X Backlash===
18 Default is 0.2 millimeters.
19
20 Defines the distance the tool head will be lashed in the X direction.
21
22 ===Y Backlash===
23 Default is 0.2 millimeters.
24
25 Defines the distance the tool head will be lashed in the Y direction.
26
27 ==Examples==
28 The following examples lash the file Screw Holder Bottom.stl.  The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and lash.py.
29
30 > python lash.py
31 This brings up the lash dialog.
32
33 > python lash.py Screw Holder Bottom.stl
34 The lash tool is parsing the file:
35 Screw Holder Bottom.stl
36 ..
37 The lash tool has created the file:
38 .. Screw Holder Bottom_lash.gcode
39
40 """
41
42 from __future__ import absolute_import
43
44 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
45 from fabmetheus_utilities import archive
46 from fabmetheus_utilities import gcodec
47 from fabmetheus_utilities import settings
48 from skeinforge_application.skeinforge_utilities import skeinforge_craft
49 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
50 from skeinforge_application.skeinforge_utilities import skeinforge_profile
51 import sys
52
53 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
54 __date__ = '$Date: 2008/21/04 $'
55 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
56
57
58 def getCraftedText( fileName, text, lashRepository = None ):
59         "Get a lashed gcode linear move text."
60         return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), lashRepository )
61
62 def getCraftedTextFromText( gcodeText, lashRepository = None ):
63         "Get a lashed gcode linear move text from text."
64         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lash'):
65                 return gcodeText
66         if lashRepository == None:
67                 lashRepository = settings.getReadRepository( LashRepository() )
68         if not lashRepository.activateLash.value:
69                 return gcodeText
70         return LashSkein().getCraftedGcode( gcodeText, lashRepository )
71
72 def getNewRepository():
73         'Get new repository.'
74         return LashRepository()
75
76 def writeOutput(fileName, shouldAnalyze=True):
77         "Lash a gcode linear move file."
78         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lash', shouldAnalyze)
79
80
81 class LashRepository(object):
82         "A class to handle the lash settings."
83         def __init__(self):
84                 "Set the default settings, execute title & settings fileName."
85                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html', self)
86                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '')
87                 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash')
88                 self.activateLash = settings.BooleanSetting().getFromValue('Activate Lash', self, False )
89                 self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 )
90                 self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 )
91                 self.executeTitle = 'Lash'
92
93         def execute(self):
94                 "Lash button has been clicked."
95                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
96                 for fileName in fileNames:
97                         writeOutput(fileName)
98
99
100 class LashSkein(object):
101         "A class to lash a skein of extrusions."
102         def __init__(self):
103                 self.distanceFeedRate = gcodec.DistanceFeedRate()
104                 self.feedRateMinute = 958.0
105                 self.lineIndex = 0
106                 self.lines = None
107                 self.oldLocation = None
108
109         def getCraftedGcode( self, gcodeText, lashRepository ):
110                 "Parse gcode text and store the lash gcode."
111                 self.lines = archive.getTextLines(gcodeText)
112                 self.lashRepository = lashRepository
113                 self.xBacklash = lashRepository.xBacklash.value
114                 self.yBacklash = lashRepository.yBacklash.value
115                 self.parseInitialization()
116                 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
117                         line = self.lines[self.lineIndex]
118                         self.parseLash(line)
119                 return self.distanceFeedRate.output.getvalue()
120
121         def getLashedLine( self, line, location, splitLine ):
122                 "Get lashed gcode line."
123                 if self.oldLocation == None:
124                         return line
125                 if location.x > self.oldLocation.x:
126                         line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x + self.xBacklash )
127                 else:
128                         line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x - self.xBacklash )
129                 if location.y > self.oldLocation.y:
130                         line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y + self.yBacklash )
131                 else:
132                         line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y - self.yBacklash )
133                 return line
134
135         def parseInitialization(self):
136                 'Parse gcode initialization and store the parameters.'
137                 for self.lineIndex in xrange(len(self.lines)):
138                         line = self.lines[self.lineIndex]
139                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
140                         firstWord = gcodec.getFirstWord(splitLine)
141                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
142                         if firstWord == '(</extruderInitialization>)':
143                                 self.distanceFeedRate.addTagBracketedProcedure('lash')
144                                 return
145                         self.distanceFeedRate.addLine(line)
146
147         def parseLash(self, line):
148                 "Parse a gcode line and add it to the lash skein."
149                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
150                 if len(splitLine) < 1:
151                         return
152                 firstWord = splitLine[0]
153                 if firstWord == 'G1':
154                         location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
155                         line = self.getLashedLine( line, location, splitLine )
156                         self.oldLocation = location
157                 self.distanceFeedRate.addLine(line)
158
159
160 def main():
161         "Display the lash dialog."
162         if len(sys.argv) > 1:
163                 writeOutput(' '.join(sys.argv[1 :]))
164         else:
165                 settings.startMainLoopFromConstructor(getNewRepository())
166
167 if __name__ == "__main__":
168         main()