chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / 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 #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.
44 import __init__
45
46 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
47 from fabmetheus_utilities import archive
48 from fabmetheus_utilities import gcodec
49 from fabmetheus_utilities import settings
50 from skeinforge_application.skeinforge_utilities import skeinforge_craft
51 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
52 from skeinforge_application.skeinforge_utilities import skeinforge_profile
53 import sys
54
55
56 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
57 __date__ = '$Date: 2008/21/04 $'
58 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
59
60
61 def getCraftedText( fileName, text, lashRepository = None ):
62         "Get a lashed gcode linear move text."
63         return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), lashRepository )
64
65 def getCraftedTextFromText( gcodeText, lashRepository = None ):
66         "Get a lashed gcode linear move text from text."
67         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lash'):
68                 return gcodeText
69         if lashRepository == None:
70                 lashRepository = settings.getReadRepository( LashRepository() )
71         if not lashRepository.activateLash.value:
72                 return gcodeText
73         return LashSkein().getCraftedGcode( gcodeText, lashRepository )
74
75 def getNewRepository():
76         'Get new repository.'
77         return LashRepository()
78
79 def writeOutput(fileName, shouldAnalyze=True):
80         "Lash a gcode linear move file."
81         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lash', shouldAnalyze)
82
83
84 class LashRepository:
85         "A class to handle the lash settings."
86         def __init__(self):
87                 "Set the default settings, execute title & settings fileName."
88                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html', self)
89                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '')
90                 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash')
91                 self.activateLash = settings.BooleanSetting().getFromValue('Activate Lash', self, False )
92                 self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 )
93                 self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 )
94                 self.executeTitle = 'Lash'
95
96         def execute(self):
97                 "Lash button has been clicked."
98                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
99                 for fileName in fileNames:
100                         writeOutput(fileName)
101
102
103 class LashSkein:
104         "A class to lash a skein of extrusions."
105         def __init__(self):
106                 self.distanceFeedRate = gcodec.DistanceFeedRate()
107                 self.feedRateMinute = 958.0
108                 self.lineIndex = 0
109                 self.lines = None
110                 self.oldLocation = None
111
112         def getCraftedGcode( self, gcodeText, lashRepository ):
113                 "Parse gcode text and store the lash gcode."
114                 self.lines = archive.getTextLines(gcodeText)
115                 self.lashRepository = lashRepository
116                 self.xBacklash = lashRepository.xBacklash.value
117                 self.yBacklash = lashRepository.yBacklash.value
118                 self.parseInitialization()
119                 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
120                         line = self.lines[self.lineIndex]
121                         self.parseLash(line)
122                 return self.distanceFeedRate.output.getvalue()
123
124         def getLashedLine( self, line, location, splitLine ):
125                 "Get lashed gcode line."
126                 if self.oldLocation == None:
127                         return line
128                 if location.x > self.oldLocation.x:
129                         line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x + self.xBacklash )
130                 else:
131                         line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x - self.xBacklash )
132                 if location.y > self.oldLocation.y:
133                         line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y + self.yBacklash )
134                 else:
135                         line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y - self.yBacklash )
136                 return line
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]
142                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
143                         firstWord = gcodec.getFirstWord(splitLine)
144                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
145                         if firstWord == '(</extruderInitialization>)':
146                                 self.distanceFeedRate.addTagBracketedProcedure('lash')
147                                 return
148                         self.distanceFeedRate.addLine(line)
149
150         def parseLash(self, line):
151                 "Parse a gcode line and add it to the lash skein."
152                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
153                 if len(splitLine) < 1:
154                         return
155                 firstWord = splitLine[0]
156                 if firstWord == 'G1':
157                         location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
158                         line = self.getLashedLine( line, location, splitLine )
159                         self.oldLocation = location
160                 self.distanceFeedRate.addLine(line)
161
162
163 def main():
164         "Display the lash dialog."
165         if len(sys.argv) > 1:
166                 writeOutput(' '.join(sys.argv[1 :]))
167         else:
168                 settings.startMainLoopFromConstructor(getNewRepository())
169
170 if __name__ == "__main__":
171         main()